diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/component.c | 5 | ||||
-rw-r--r-- | server/component.h | 6 | ||||
-rw-r--r-- | server/componentIGMP.c | 447 | ||||
-rw-r--r-- | server/componentIGMP.h | 62 | ||||
-rw-r--r-- | server/connection.c | 13 | ||||
-rw-r--r-- | server/connection.h | 7 | ||||
-rw-r--r-- | server/connectionHTTP.c | 34 | ||||
-rw-r--r-- | server/connectionHTTP.h | 5 | ||||
-rw-r--r-- | server/connectionIGMP.c | 64 | ||||
-rw-r--r-- | server/connectionIGMP.h | 45 | ||||
-rw-r--r-- | server/connectionVTP.c | 25 | ||||
-rw-r--r-- | server/connectionVTP.h | 4 | ||||
-rw-r--r-- | server/livefilter.c | 10 | ||||
-rw-r--r-- | server/livefilter.h | 5 | ||||
-rw-r--r-- | server/livestreamer.c | 85 | ||||
-rw-r--r-- | server/livestreamer.h | 8 | ||||
-rw-r--r-- | server/menuHTTP.c | 45 | ||||
-rw-r--r-- | server/menuHTTP.h | 2 | ||||
-rw-r--r-- | server/server.c | 34 | ||||
-rw-r--r-- | server/server.h | 10 | ||||
-rw-r--r-- | server/setup.c | 30 | ||||
-rw-r--r-- | server/setup.h | 6 | ||||
-rw-r--r-- | server/streamer.c | 45 | ||||
-rw-r--r-- | server/streamer.h | 16 | ||||
-rw-r--r-- | server/suspend.c | 24 | ||||
-rw-r--r-- | server/suspend.h | 9 |
26 files changed, 853 insertions, 193 deletions
diff --git a/server/component.c b/server/component.c index 1a584b5..70d861a 100644 --- a/server/component.c +++ b/server/component.c @@ -1,13 +1,14 @@ /* - * $Id: component.c,v 1.3 2005/05/09 20:22:29 lordjaxom Exp $ + * $Id: component.c,v 1.4 2009/02/13 10:39:22 schmirl Exp $ */ #include "server/component.h" #include "server/connection.h" cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp, - uint ListenPort): + uint ListenPort, int Type, int IpProto): m_Protocol(Protocol), + m_Listen(Type, IpProto), m_ListenIp(ListenIp), m_ListenPort(ListenPort) { diff --git a/server/component.h b/server/component.h index 8703348..7efd4ba 100644 --- a/server/component.h +++ b/server/component.h @@ -1,5 +1,5 @@ /* - * $Id: component.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $ + * $Id: component.h,v 1.3 2009/02/13 10:39:22 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H @@ -17,8 +17,8 @@ class cServerConnection; class cServerComponent: public cListObject { private: - cTBSocket m_Listen; const char *m_Protocol; + cTBSocket m_Listen; const char *m_ListenIp; uint m_ListenPort; @@ -27,7 +27,7 @@ protected: virtual cServerConnection *NewClient(void) = 0; public: - cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort); + cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort, int Type = SOCK_STREAM, int IpProto = 0); virtual ~cServerComponent(); /* Starts listening on the specified Port, override if you want to do things diff --git a/server/componentIGMP.c b/server/componentIGMP.c new file mode 100644 index 0000000..946c513 --- /dev/null +++ b/server/componentIGMP.c @@ -0,0 +1,447 @@ +/* + * $Id: componentIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ +#include <netinet/ip.h> +#include <netinet/igmp.h> + +#include "server/componentIGMP.h" +#include "server/connectionIGMP.h" +#include "server/setup.h" + +#ifndef IGMP_ALL_HOSTS +#define IGMP_ALL_HOSTS htonl(0xE0000001L) +#endif +#ifndef IGMP_ALL_ROUTER +#define IGMP_ALL_ROUTER htonl(0xE0000002L) +#endif + +// IGMP parameters according to RFC2236. All time values in seconds. +#define IGMP_ROBUSTNESS 2 +#define IGMP_QUERY_INTERVAL 125 +#define IGMP_QUERY_RESPONSE_INTERVAL 10 +#define IGMP_GROUP_MEMBERSHIP_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL) +#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL / 2) +#define IGMP_STARTUP_QUERY_INTERVAL (IGMP_QUERY_INTERVAL / 4) +#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS +// This value is 1/10 sec. RFC default is 10. Reduced to minimum to free unused channels ASAP +#define IGMP_LAST_MEMBER_QUERY_INTERVAL_TS 1 +#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS + +// operations on struct timeval +#define TV_CMP(a, cmp, b) (a.tv_sec == b.tv_sec ? a.tv_usec cmp b.tv_usec : a.tv_sec cmp b.tv_sec) +#define TV_SET(tv) (tv.tv_sec || tv.tv_usec) +#define TV_CLR(tv) memset(&tv, 0, sizeof(tv)) +#define TV_CPY(dst, src) memcpy(&dst, &src, sizeof(dst)) +#define TV_ADD(dst, ts) dst.tv_sec += ts / 10; dst.tv_usec += (ts % 10) * 100000; if (dst.tv_usec >= 1000000) { dst.tv_usec -= 1000000; dst.tv_sec++; } + +class cMulticastGroup: public cListObject +{ +public: + cConnectionIGMP *connection; + in_addr_t group; + in_addr_t reporter; + struct timeval timeout; + struct timeval v1timer; + struct timeval retransmit; + + cMulticastGroup(in_addr_t Group); +}; + +cMulticastGroup::cMulticastGroup(in_addr_t Group) : + connection(NULL), + group(Group), + reporter(0) +{ + TV_CLR(timeout); + TV_CLR(v1timer); + TV_CLR(retransmit); +} + +void logIGMP(uint8_t type, struct in_addr Src, struct in_addr Dst, struct in_addr Grp) +{ + const char* msg; + switch (type) { + case IGMP_MEMBERSHIP_QUERY: msg = "membership query"; break; + case IGMP_V1_MEMBERSHIP_REPORT: msg = "V1 membership report"; break; + case IGMP_V2_MEMBERSHIP_REPORT: msg = "V2 membership report"; break; + case IGMP_V2_LEAVE_GROUP: msg = "leave group"; break; + default: msg = "unknown"; break; + } + char* s = strdup(inet_ntoa(Src)); + char* d = strdup(inet_ntoa(Dst)); + dsyslog("streamdev-server IGMP: Received %s from %s (dst %s) for %s", msg, s, d, inet_ntoa(Grp)); + free(s); + free(d); +} + +/* Taken from http://tools.ietf.org/html/rfc1071 */ +uint16_t inetChecksum(uint16_t *addr, int count) +{ + uint32_t sum = 0; + while (count > 1) { + sum += *addr++; + count -= 2; + } + + if( count > 0 ) + sum += * (uint8_t *) addr; + + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +cComponentIGMP::cComponentIGMP(void): + cServerComponent("IGMP", "0.0.0.0", 0, SOCK_RAW, IPPROTO_IGMP), + cThread("IGMP timeout handler"), + m_BindIp(inet_addr(StreamdevServerSetup.IGMPBindIP)), + m_MaxChannelNumber(0), + m_StartupQueryCount(IGMP_STARTUP_QUERY_COUNT), + m_Querier(true) +{ +} + +cComponentIGMP::~cComponentIGMP(void) +{ +} + +cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) const +{ + cMulticastGroup *group = m_Groups.First(); + while (group && group->group != Group) + group = m_Groups.Next(group); + return group; +} + +bool cComponentIGMP::Initialize(void) +{ + if (cServerComponent::Initialize() && IGMPMembership(IGMP_ALL_ROUTER)) + { + for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) + { + if (channel->GroupSep()) + continue; + int num = channel->Number(); + if (!IGMPMembership(htonl(MULTICAST_PRIV_MIN + num))) + break; + m_MaxChannelNumber = num; + } + if (m_MaxChannelNumber == 0) + { + IGMPMembership(IGMP_ALL_ROUTER, false); + esyslog("streamdev-server IGMP: no multicast group joined"); + } + else + { + Start(); + } + } + return m_MaxChannelNumber > 0; +} + +void cComponentIGMP::Destruct(void) +{ + if (m_MaxChannelNumber > 0) + { + Cancel(3); + for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) + { + if (channel->GroupSep()) + continue; + int num = channel->Number(); + if (num > m_MaxChannelNumber) + break; + IGMPMembership(htonl(MULTICAST_PRIV_MIN + num), false); + } + IGMPMembership(IGMP_ALL_ROUTER, false); + } + m_MaxChannelNumber = 0; + cServerComponent::Destruct(); +} + +cServerConnection *cComponentIGMP::NewClient(void) +{ + return new cConnectionIGMP("IGMP", StreamdevServerSetup.IGMPClientPort, (eStreamType) StreamdevServerSetup.IGMPStreamType); +} + +cServerConnection* cComponentIGMP::Accept(void) +{ + ssize_t recv_len; + int ip_hdrlen, ip_datalen; + struct ip *ip; + struct igmp *igmp; + + while ((recv_len = ::recvfrom(Socket(), m_ReadBuffer, sizeof(m_ReadBuffer), 0, NULL, NULL)) < 0 && errno == EINTR) + errno = 0; + + if (recv_len < 0) { + esyslog("streamdev-server IGMP: read failed: %m"); + return NULL; + } + else if (recv_len < (ssize_t) sizeof(struct ip)) { + esyslog("streamdev-server IGMP: IP packet too short"); + return NULL; + } + + ip = (struct ip*) m_ReadBuffer; + + // filter out my own packets + if (ip->ip_src.s_addr == m_BindIp) + return NULL; + + ip_hdrlen = ip->ip_hl << 2; +#ifdef __FreeBSD__ + ip_datalen = ip->ip_len; +#else + ip_datalen = ntohs(ip->ip_len) - ip_hdrlen; +#endif + if (ip->ip_p != IPPROTO_IGMP) { + esyslog("streamdev-server IGMP: Unexpected protocol %hhu", ip->ip_p); + return NULL; + } + if (recv_len < ip_hdrlen + IGMP_MINLEN) { + esyslog("streamdev-server IGMP: packet too short"); + return NULL; + } + igmp = (struct igmp*) (m_ReadBuffer + ip_hdrlen); + uint16_t chksum = igmp->igmp_cksum; + igmp->igmp_cksum = 0; + if (chksum != inetChecksum((uint16_t *)igmp, ip_datalen)) + { + esyslog("INVALID CHECKSUM %d %d %d %d 0x%x 0x%x", ntohs(ip->ip_len), ip_hdrlen, ip_datalen, recv_len, chksum, inetChecksum((uint16_t *)igmp, ip_datalen)); + return NULL; + } + logIGMP(igmp->igmp_type, ip->ip_src, ip->ip_dst, igmp->igmp_group); + return ProcessMessage(igmp, igmp->igmp_group.s_addr, ip->ip_src.s_addr); +} + +cServerConnection* cComponentIGMP::ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender) +{ + cServerConnection* conn = NULL; + cMulticastGroup* group; + LOCK_THREAD; + switch (Igmp->igmp_type) { + case IGMP_MEMBERSHIP_QUERY: + if (ntohl(Sender) < ntohl(m_BindIp)) + IGMPStartOtherQuerierPresentTimer(); + break; + case IGMP_V1_MEMBERSHIP_REPORT: + case IGMP_V2_MEMBERSHIP_REPORT: + group = FindGroup(Group); + if (!group) { + group = new cMulticastGroup(Group); + m_Groups.Add(group); + } + if (!group->connection) { + IGMPStartMulticast(group); + conn = group->connection; + } + IGMPStartTimer(group, Sender); + if (Igmp->igmp_type == IGMP_V1_MEMBERSHIP_REPORT) + IGMPStartV1HostTimer(group); + break; + case IGMP_V2_LEAVE_GROUP: + group = FindGroup(Group); + if (group && !TV_SET(group->v1timer)) { + if (group->reporter == Sender) { + IGMPStartTimerAfterLeave(group, m_Querier ? IGMP_LAST_MEMBER_QUERY_INTERVAL_TS : Igmp->igmp_code); + if (m_Querier) + IGMPSendGroupQuery(group); + IGMPStartRetransmitTimer(group); + } + m_CondWait.Signal(); + } + break; + default: + break; + } + return conn; +} + +void cComponentIGMP::Action() +{ + while (Running()) { + struct timeval now; + struct timeval next; + + gettimeofday(&now, NULL); + TV_CPY(next, now); + next.tv_sec += IGMP_QUERY_INTERVAL; + + cMulticastGroup *del = NULL; + { + LOCK_THREAD; + if (TV_CMP(m_GeneralQueryTimer, <, now)) { + dsyslog("General Query"); + IGMPSendGeneralQuery(); + IGMPStartGeneralQueryTimer(); + } + if (TV_CMP(next, >, m_GeneralQueryTimer)) + TV_CPY(next, m_GeneralQueryTimer); + + for (cMulticastGroup *group = m_Groups.First(); group; group = m_Groups.Next(group)) { + if (TV_CMP(group->timeout, <, now)) { + IGMPStopMulticast(group); + IGMPClearRetransmitTimer(group); + if (del) + m_Groups.Del(del); + del = group; + } + else if (m_Querier && TV_SET(group->retransmit) && TV_CMP(group->retransmit, <, now)) { + IGMPSendGroupQuery(group); + IGMPStartRetransmitTimer(group); + if (TV_CMP(next, >, group->retransmit)) + TV_CPY(next, group->retransmit); + } + else if (TV_SET(group->v1timer) && TV_CMP(group->v1timer, <, now)) { + TV_CLR(group->v1timer); + } + else { + if (TV_CMP(next, >, group->timeout)) + TV_CPY(next, group->timeout); + if (TV_SET(group->retransmit) && TV_CMP(next, >, group->retransmit)) + TV_CPY(next, group->retransmit); + if (TV_SET(group->v1timer) && TV_CMP(next, >, group->v1timer)) + TV_CPY(next, group->v1timer); + } + } + if (del) + m_Groups.Del(del); + } + + int sleep = (next.tv_sec - now.tv_sec) * 1000; + sleep += (next.tv_usec - now.tv_usec) / 1000; + if (next.tv_usec < now.tv_usec) + sleep += 1000; + dsyslog("Sleeping %d ms", sleep); + m_CondWait.Wait(sleep); + } +} + +bool cComponentIGMP::IGMPMembership(in_addr_t Group, bool Add) +{ + struct ip_mreqn mreq; + mreq.imr_multiaddr.s_addr = Group; + mreq.imr_address.s_addr = INADDR_ANY; + mreq.imr_ifindex = 0; + if (setsockopt(Socket(), IPPROTO_IP, Add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + esyslog("streamdev-server IGMP: unable to %s %s: %m", Add ? "join" : "leave", inet_ntoa(mreq.imr_multiaddr)); + if (errno == ENOBUFS) + esyslog("consider increasing sys.net.ipv4.igmp_max_memberships"); + return false; + } + return true; +} + +void cComponentIGMP::IGMPSendQuery(in_addr_t Group, int Timeout) +{ + struct sockaddr_in dst; + struct igmp query; + + dst.sin_family = AF_INET; + dst.sin_port = IPPROTO_IGMP; + dst.sin_addr.s_addr = Group; + query.igmp_type = IGMP_MEMBERSHIP_QUERY; + query.igmp_code = Timeout * 10; + query.igmp_cksum = 0; + query.igmp_group.s_addr = (Group == IGMP_ALL_HOSTS) ? 0 : Group; + query.igmp_cksum = inetChecksum((uint16_t *) &query, sizeof(query)); + + for (int i = 0; i < 5 && ::sendto(Socket(), &query, sizeof(query), 0, (sockaddr*)&dst, sizeof(dst)) == -1; i++) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + esyslog("streamdev-server IGMP: unable to query group %s: %m", inet_ntoa(dst.sin_addr)); + break; + } + cCondWait::SleepMs(10); + } +} + +// Querier state actions +void cComponentIGMP::IGMPStartGeneralQueryTimer() +{ + m_Querier = true; + if (m_StartupQueryCount) { + gettimeofday(&m_GeneralQueryTimer, NULL); + m_GeneralQueryTimer.tv_sec += IGMP_STARTUP_QUERY_INTERVAL; + m_StartupQueryCount--; + } + else { + gettimeofday(&m_GeneralQueryTimer, NULL); + m_GeneralQueryTimer.tv_sec += IGMP_QUERY_INTERVAL; + } +} + +void cComponentIGMP::IGMPStartOtherQuerierPresentTimer() +{ + m_Querier = false; + m_StartupQueryCount = 0; + gettimeofday(&m_GeneralQueryTimer, NULL); + m_GeneralQueryTimer.tv_sec += IGMP_OTHER_QUERIER_PRESENT_INTERVAL; +} + +void cComponentIGMP::IGMPSendGeneralQuery() +{ + IGMPSendQuery(IGMP_ALL_HOSTS, IGMP_QUERY_RESPONSE_INTERVAL); +} + +// Group state actions +void cComponentIGMP::IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member) +{ + gettimeofday(&Group->timeout, NULL); + Group->timeout.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL; + TV_CLR(Group->retransmit); + Group->reporter = Member; + +} + +void cComponentIGMP::IGMPStartV1HostTimer(cMulticastGroup* Group) +{ + gettimeofday(&Group->v1timer, NULL); + Group->v1timer.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL; +} + +void cComponentIGMP::IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTimeTs) +{ + //Group->Update(time(NULL) + MaxResponseTime * IGMP_LAST_MEMBER_QUERY_COUNT / 10); + MaxResponseTimeTs *= IGMP_LAST_MEMBER_QUERY_COUNT; + gettimeofday(&Group->timeout, NULL); + TV_ADD(Group->timeout, MaxResponseTimeTs); + TV_CLR(Group->retransmit); + Group->reporter = 0; +} + +void cComponentIGMP::IGMPStartRetransmitTimer(cMulticastGroup* Group) +{ + gettimeofday(&Group->retransmit, NULL); + TV_ADD(Group->retransmit, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS); +} + +void cComponentIGMP::IGMPClearRetransmitTimer(cMulticastGroup* Group) +{ + TV_CLR(Group->retransmit); +} + +void cComponentIGMP::IGMPSendGroupQuery(cMulticastGroup* Group) +{ + IGMPSendQuery(Group->group, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS); +} + +void cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group) +{ + in_addr_t g = ntohl(Group->group); + if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) { + cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN); + Group->connection = (cConnectionIGMP*) NewClient(); + if (!Group->connection->Start(channel, Group->group)) { + DELETENULL(Group->connection); + } + } +} + +void cComponentIGMP::IGMPStopMulticast(cMulticastGroup* Group) +{ + if (Group->connection) + Group->connection->Stop(); +} diff --git a/server/componentIGMP.h b/server/componentIGMP.h new file mode 100644 index 0000000..09d8fde --- /dev/null +++ b/server/componentIGMP.h @@ -0,0 +1,62 @@ +/* + * $Id: componentIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ + +#ifndef VDR_STREAMDEV_IGMPSERVER_H +#define VDR_STREAMDEV_IGMPSERVER_H + +#include <sys/time.h> +#include <time.h> +#include <vdr/thread.h> +#include "server/component.h" + +class cConnectionIGMP; +class cMulticastGroup; + +class cComponentIGMP: public cServerComponent, public cThread { +private: + char m_ReadBuffer[2048]; + cList<cMulticastGroup> m_Groups; + in_addr_t m_BindIp; + int m_MaxChannelNumber; + struct timeval m_GeneralQueryTimer; + int m_StartupQueryCount; + bool m_Querier; + cCondWait m_CondWait; + + cMulticastGroup* FindGroup(in_addr_t Group) const; + + /* Add or remove local host to multicast group */ + bool IGMPMembership(in_addr_t Group, bool Add = true); + void IGMPSendQuery(in_addr_t Group, int Timeout); + + cServerConnection* ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender); + + void IGMPStartGeneralQueryTimer(); + void IGMPStartOtherQuerierPresentTimer(); + void IGMPSendGeneralQuery(); + + void IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member); + void IGMPStartV1HostTimer(cMulticastGroup* Group); + void IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTime); + void IGMPStartRetransmitTimer(cMulticastGroup* Group); + void IGMPClearRetransmitTimer(cMulticastGroup* Group); + void IGMPSendGroupQuery(cMulticastGroup* Group); + void IGMPStartMulticast(cMulticastGroup* Group); + void IGMPStopMulticast(cMulticastGroup* Group); + + virtual void Action(); + +protected: + virtual cServerConnection *NewClient(void); + +public: + virtual bool Initialize(void); + virtual void Destruct(void); + virtual cServerConnection* Accept(void); + + cComponentIGMP(void); + ~cComponentIGMP(void); +}; + +#endif // VDR_STREAMDEV_IGMPSERVER_H diff --git a/server/connection.c b/server/connection.c index 629ed1d..74b2783 100644 --- a/server/connection.c +++ b/server/connection.c @@ -1,5 +1,5 @@ /* - * $Id: connection.c,v 1.10 2007/05/07 12:25:11 schmirl Exp $ + * $Id: connection.c,v 1.12 2009/02/13 10:39:22 schmirl Exp $ */ #include "server/connection.h" @@ -12,7 +12,8 @@ #include <stdarg.h> #include <errno.h> -cServerConnection::cServerConnection(const char *Protocol): +cServerConnection::cServerConnection(const char *Protocol, int Type): + cTBSocket(Type), m_Protocol(Protocol), m_DeferClose(false), m_Pending(false), @@ -139,11 +140,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority) Dprintf(" * GetDevice(const cChannel*, int)\n"); Dprintf(" * -------------------------------\n"); -#if VDRVERSNUM < 10500 - device = cDevice::GetDevice(Channel, Priority); -#else device = cDevice::GetDevice(Channel, Priority, false); -#endif Dprintf(" * Found following device: %p (%d)\n", device, device ? device->CardIndex() + 1 : 0); @@ -161,11 +158,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority) const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel()); isyslog("streamdev-server: Detaching current receiver"); Detach(); -#if VDRVERSNUM < 10500 - device = cDevice::GetDevice(Channel, Priority); -#else device = cDevice::GetDevice(Channel, Priority, false); -#endif Attach(); Dprintf(" * Found following device: %p (%d)\n", device, device ? device->CardIndex() + 1 : 0); diff --git a/server/connection.h b/server/connection.h index fe828d9..2c28a09 100644 --- a/server/connection.h +++ b/server/connection.h @@ -1,5 +1,5 @@ /* - * $Id: connection.h,v 1.5 2007/04/16 11:01:02 schmirl Exp $ + * $Id: connection.h,v 1.7 2009/02/13 10:39:22 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_CONNECTION_H @@ -44,9 +44,12 @@ protected: public: /* If you derive, specify a short string such as HTTP for Protocol, which will be displayed in error messages */ - cServerConnection(const char *Protocol); + cServerConnection(const char *Protocol, int Type = SOCK_STREAM); virtual ~cServerConnection(); + /* If true, any client IP will be accepted */ + virtual bool CanAuthenticate(void) { return false; } + /* Gets called if the client has been accepted by the core */ virtual void Welcome(void) { } diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index 38a82a3..fc10bfc 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -1,11 +1,12 @@ /* - * $Id: connectionHTTP.c,v 1.13 2008/03/28 15:11:40 schmirl Exp $ + * $Id: connectionHTTP.c,v 1.16 2009/02/13 07:02:19 schmirl Exp $ */ #include <ctype.h> #include "server/connectionHTTP.h" #include "server/menuHTTP.h" +#include "server/server.h" #include "server/setup.h" cConnectionHTTP::cConnectionHTTP(void): @@ -26,6 +27,11 @@ cConnectionHTTP::~cConnectionHTTP() delete m_LiveStreamer; } +bool cConnectionHTTP::CanAuthenticate(void) +{ + return opt_auth != NULL; +} + bool cConnectionHTTP::Command(char *Cmd) { Dprintf("command %s\n", Cmd); @@ -44,10 +50,22 @@ bool cConnectionHTTP::Command(char *Cmd) if (strncasecmp(Cmd, "Host:", 5) == 0) { Dprintf("Host-Header\n"); m_Host = (std::string) skipspace(Cmd + 5); + return true; + } + 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; + } } Dprintf("header\n"); return true; default: + // skip additional blank lines + if (*Cmd == '\0') + return true; break; } return false; // ??? shouldn't happen @@ -56,6 +74,16 @@ bool cConnectionHTTP::Command(char *Cmd) bool cConnectionHTTP::ProcessRequest(void) { Dprintf("process\n"); + if (!StreamdevHosts.Acceptable(RemoteIpAddr())) + { + if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) { + isyslog("streamdev-server: HTTP authorization required"); + DeferClose(); + return Respond("HTTP/1.0 401 Authorization Required") + && Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")") + && Respond(""); + } + } if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) { switch (m_Job) { case hjListing: @@ -183,8 +211,10 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) const char* pType = type.c_str(); if (strcasecmp(pType, "PS") == 0) { m_StreamType = stPS; +#if APIVERSNUM < 10703 } else if (strcasecmp(pType, "PES") == 0) { m_StreamType = stPES; +#endif } else if (strcasecmp(pType, "TS") == 0) { m_StreamType = stTS; } else if (strcasecmp(pType, "ES") == 0) { @@ -236,7 +266,9 @@ bool cConnectionHTTP::CmdGET(const std::string &Opts) { case stTS: base += "TS/"; break; case stPS: base += "PS/"; break; +#if APIVERSNUM < 10703 case stPES: base += "PES/"; break; +#endif case stES: base += "ES/"; break; case stExtern: base += "Extern/"; break; default: break; diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h index a3558ad..0548959 100644 --- a/server/connectionHTTP.h +++ b/server/connectionHTTP.h @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.h,v 1.5 2008/03/28 15:11:40 schmirl Exp $ + * $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H @@ -30,6 +30,7 @@ private: 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; @@ -52,6 +53,8 @@ public: virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); } virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); } + virtual bool CanAuthenticate(void); + virtual bool Command(char *Cmd); bool CmdGET(const std::string &Opts); diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c new file mode 100644 index 0000000..dc08798 --- /dev/null +++ b/server/connectionIGMP.c @@ -0,0 +1,64 @@ +/* + * $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ + +#include <ctype.h> + +#include "server/connectionIGMP.h" +#include "server/server.h" +#include "server/setup.h" +#include <vdr/channels.h> + +cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType) : + cServerConnection(Name, SOCK_DGRAM), + m_LiveStreamer(NULL), + m_ClientPort(ClientPort), + m_StreamType(StreamType) +{ +} + +cConnectionIGMP::~cConnectionIGMP() +{ + delete m_LiveStreamer; +} + +bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst) +{ + if (Channel != NULL) { + cDevice *device = GetDevice(Channel, 0); + if (device != NULL) { + device->SwitchChannel(Channel, false); + struct in_addr ip; + ip.s_addr = Dst; + if (Connect(inet_ntoa(ip), m_ClientPort)) { + m_LiveStreamer = new cStreamdevLiveStreamer(0); + if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) { + m_LiveStreamer->SetDevice(device); + if (!SetDSCP()) + LOG_ERROR_STR("unable to set DSCP sockopt"); + Dprintf("streamer start\n"); + m_LiveStreamer->Start(this); + return true; + } + else + esyslog("streamdev-server IGMP: SetDevice failed"); + DELETENULL(m_LiveStreamer); + } + else + esyslog("streamdev-server IGMP: Connect failed: %m"); + } + else + esyslog("streamdev-server IGMP: GetDevice failed"); + } + else + esyslog("streamdev-server IGMP: Channel not found"); + return false; +} + +void cConnectionIGMP::Stop() +{ + if (m_LiveStreamer) { + m_LiveStreamer->Stop(); + DELETENULL(m_LiveStreamer); + } +} diff --git a/server/connectionIGMP.h b/server/connectionIGMP.h new file mode 100644 index 0000000..90abd58 --- /dev/null +++ b/server/connectionIGMP.h @@ -0,0 +1,45 @@ +/* + * $Id: connectionIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $ + */ + +#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H +#define VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H + +#include "connection.h" +#include "server/livestreamer.h" + +#include <tools/select.h> + +#define MULTICAST_PRIV_MIN ((uint32_t) 0xefff0000) +#define MULTICAST_PRIV_MAX ((uint32_t) 0xeffffeff) + +class cStreamdevLiveStreamer; + +class cConnectionIGMP: public cServerConnection { +private: + cStreamdevLiveStreamer *m_LiveStreamer; + int m_ClientPort; + eStreamType m_StreamType; + +public: + cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType); + virtual ~cConnectionIGMP(); + + bool Start(cChannel *Channel, in_addr_t Dst); + void Stop(); + + /* Not used here */ + virtual bool Command(char *Cmd) { return false; } + + virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); } + virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); } + + virtual bool Abort(void) const; +}; + +inline bool cConnectionIGMP::Abort(void) const +{ + return !m_LiveStreamer || m_LiveStreamer->Abort(); +} + +#endif // VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H diff --git a/server/connectionVTP.c b/server/connectionVTP.c index 2829c13..e0edb6e 100644 --- a/server/connectionVTP.c +++ b/server/connectionVTP.c @@ -1,5 +1,5 @@ /* - * $Id: connectionVTP.c,v 1.17 2008/03/13 16:01:18 schmirl Exp $ + * $Id: connectionVTP.c,v 1.19 2009/01/16 11:35:44 schmirl Exp $ */ #include "server/connectionVTP.h" @@ -595,17 +595,18 @@ bool cConnectionVTP::CmdCAPS(char *Opts) return Respond(220, "Capability \"%s\" accepted", Opts); } +#if APIVERSNUM < 10703 if (strcasecmp(Opts, "PES") == 0) { m_StreamType = stPES; return Respond(220, "Capability \"%s\" accepted", Opts); } +#endif if (strcasecmp(Opts, "EXTERN") == 0) { m_StreamType = stExtern; return Respond(220, "Capability \"%s\" accepted", Opts); } -#if VDRVERSNUM >= 10300 // // Deliver section filters data in separate, channel-independent data stream // @@ -613,7 +614,6 @@ bool cConnectionVTP::CmdCAPS(char *Opts) m_FiltersSupport = true; return Respond(220, "Capability \"%s\" accepted", Opts); } -#endif return Respond(561, "Capability \"%s\" not known", Opts); } @@ -648,13 +648,8 @@ bool cConnectionVTP::CmdPORT(char *Opts) if (ep == Opts || !isspace(*ep)) return Respond(500, "Use: PORT Id Destination"); -#if VDRVERSNUM >= 10300 if (id != siLive && id != siLiveFilter) return Respond(501, "Wrong connection id %d", id); -#else - if (id != siLive) - return Respond(501, "Wrong connection id %d", id); -#endif Opts = skipspace(ep); n = 0; @@ -681,7 +676,6 @@ bool cConnectionVTP::CmdPORT(char *Opts) isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport); -#if VDRVERSNUM >= 10300 if (id == siLiveFilter) { m_FiltersSupport = true; if(m_FilterStreamer) @@ -703,7 +697,6 @@ bool cConnectionVTP::CmdPORT(char *Opts) return Respond(220, "Port command ok, data connection opened"); } -#endif if(m_LiveSocket && m_LiveStreamer) m_LiveStreamer->Stop(); @@ -746,14 +739,12 @@ bool cConnectionVTP::CmdTUNE(char *Opts) if(m_LiveSocket) m_LiveStreamer->Start(m_LiveSocket); -#if VDRVERSNUM >= 10300 if(m_FiltersSupport) { if(!m_FilterStreamer) m_FilterStreamer = new cStreamdevFilterStreamer; m_FilterStreamer->SetDevice(dev); //m_FilterStreamer->SetChannel(chan); } -#endif return Respond(220, "Channel tuned"); } @@ -788,7 +779,6 @@ bool cConnectionVTP::CmdDELP(char *Opts) bool cConnectionVTP::CmdADDF(char *Opts) { -#if VDRVERSNUM >= 10300 int pid, tid, mask; char *ep; @@ -810,14 +800,10 @@ bool cConnectionVTP::CmdADDF(char *Opts) return m_FilterStreamer->SetFilter(pid, tid, mask, true) ? Respond(220, "Filter %d transferring", pid) : Respond(560, "Filter %d not available", pid); -#else - return Respond(500, "ADDF known but unimplemented with VDR < 1.3.0"); -#endif } bool cConnectionVTP::CmdDELF(char *Opts) { -#if VDRVERSNUM >= 10307 int pid, tid, mask; char *ep; @@ -838,9 +824,6 @@ bool cConnectionVTP::CmdDELF(char *Opts) m_FilterStreamer->SetFilter(pid, tid, mask, false); return Respond(220, "Filter %d stopped", pid); -#else - return Respond(500, "DELF known but unimplemented with VDR < 1.3.0"); -#endif } bool cConnectionVTP::CmdABRT(char *Opts) @@ -857,12 +840,10 @@ bool cConnectionVTP::CmdABRT(char *Opts) DELETENULL(m_LiveStreamer); DELETENULL(m_LiveSocket); break; -#if VDRVERSNUM >= 10300 case siLiveFilter: DELETENULL(m_FilterStreamer); DELETENULL(m_FilterSocket); break; -#endif default: return Respond(501, "Wrong connection id %d", id); break; diff --git a/server/connectionVTP.h b/server/connectionVTP.h index 3acb1a2..452f3ae 100644 --- a/server/connectionVTP.h +++ b/server/connectionVTP.h @@ -12,9 +12,9 @@ class cLSTTHandler; class cConnectionVTP: public cServerConnection { friend class cLSTEHandler; - // if your compiler doesn't understand the following statement - // (e.g. gcc 2.x), simply remove it and try again ;-) +#if !defined __GNUC__ || __GNUC__ >= 3 using cServerConnection::Respond; +#endif private: cTBSocket *m_LiveSocket; diff --git a/server/livefilter.c b/server/livefilter.c index e7d896c..67b0e37 100644 --- a/server/livefilter.c +++ b/server/livefilter.c @@ -1,20 +1,15 @@ /* - * $Id: livefilter.c,v 1.4 2007/04/24 11:06:12 schmirl Exp $ + * $Id: livefilter.c,v 1.7 2009/02/13 13:02:40 schmirl Exp $ */ #include "server/livefilter.h" #include "server/streamer.h" #include "common.h" -#ifndef TS_SIZE -# define TS_SIZE 188 -#endif #ifndef TS_SYNC_BYTE # define TS_SYNC_BYTE 0x47 #endif -#if VDRVERSNUM >= 10300 - cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) { m_Streamer = Streamer; } @@ -31,6 +26,7 @@ void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data, buffer[1] = ((Pid >> 8) & 0x3f) | (pos==0 ? 0x40 : 0); /* bit 6: payload unit start indicator (PUSI) */ buffer[2] = Pid & 0xff; buffer[3] = Tid; + // this makes it a proprietary stream buffer[4] = (uchar)chunk; memcpy(buffer + 5, Data + pos, chunk); length -= chunk; @@ -41,5 +37,3 @@ void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data, m_Streamer->ReportOverflow(TS_SIZE - p); } } - -#endif // VDRVERSNUM >= 10300 diff --git a/server/livefilter.h b/server/livefilter.h index 99c69d4..13e8956 100644 --- a/server/livefilter.h +++ b/server/livefilter.h @@ -1,5 +1,5 @@ /* - * $Id: livefilter.h,v 1.4 2007/04/24 11:29:29 schmirl Exp $ + * $Id: livefilter.h,v 1.5 2008/04/07 14:27:31 schmirl Exp $ */ #ifndef VDR_STREAMEV_LIVEFILTER_H @@ -7,8 +7,6 @@ #include <vdr/config.h> -# if VDRVERSNUM >= 10300 - #include <vdr/filter.h> class cStreamdevStreamer; @@ -31,5 +29,4 @@ public: } }; -# endif // VDRVERSNUM >= 10300 #endif // VDR_STREAMEV_LIVEFILTER_H diff --git a/server/livestreamer.c b/server/livestreamer.c index 5e19d2b..97dffd7 100644 --- a/server/livestreamer.c +++ b/server/livestreamer.c @@ -3,13 +3,14 @@ #include <libsi/section.h> #include <libsi/descriptor.h> +#include "remux/ts2ps.h" +#include "remux/ts2es.h" +#include "remux/extern.h" + #include <vdr/ringbuffer.h> #include "server/livestreamer.h" #include "server/livefilter.h" -#include "remux/ts2ps.h" -#include "remux/ts2es.h" -#include "remux/extern.h" #include "common.h" #define TSPATREPACKER @@ -27,23 +28,13 @@ protected: virtual void Receive(uchar *Data, int Length); public: -#if VDRVERSNUM < 10500 - cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, int Priority, const int *Pids); -#else cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids); -#endif virtual ~cStreamdevLiveReceiver(); }; -#if VDRVERSNUM < 10500 -cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, - int Priority, const int *Pids): - cReceiver(Ca, Priority, 0, Pids), -#else cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids): cReceiver(ChannelID, Priority, 0, Pids), -#endif m_Streamer(Streamer) { } @@ -86,7 +77,7 @@ public: cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel) { - Dprintf("cStreamdevPatFilter(\"%s\")", Channel->Name()); + Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name()); assert(Streamer); m_Channel = Channel; m_Streamer = Streamer; @@ -145,7 +136,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4) case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264) - Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)", + Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n", stream.getPid(), psStreamTypes[stream.getStreamType()]); return stream.getPid(); case 0x05: // ISO/IEC 13818-1 private sections @@ -153,19 +144,19 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { switch (d->getDescriptorTag()) { case SI::AC3DescriptorTag: - Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", + Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3"); return stream.getPid(); case SI::TeletextDescriptorTag: - Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", + Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext"); return stream.getPid(); case SI::SubtitlingDescriptorTag: - Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", + Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB"); return stream.getPid(); default: - Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s", + Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN"); break; } @@ -210,7 +201,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) return stream.getPid(); } } - Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s", + Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n", stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN"); break; } @@ -220,7 +211,7 @@ int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream) void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { if (Pid == 0x00) { - if (Tid == 0x00 && !pmtPid) { + if (Tid == 0x00) { SI::PAT pat(Data, false); if (!pat.CheckCRCAndParse()) return; @@ -229,8 +220,9 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i if (!assoc.isNITPid()) { const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId()); if (Channel && (Channel == m_Channel)) { + int prevPmtPid = pmtPid; if (0 != (pmtPid = assoc.getPid())) { - Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d", Channel->Name(), pmtPid); + Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d\n", Channel->Name(), pmtPid); pmtSid = assoc.getServiceId(); if (Length < TS_SIZE-5) { // repack PAT to TS frame and send to client @@ -242,25 +234,27 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i int ts_id; unsigned int crc, i, len; uint8_t *tmp, tspat_buf[TS_SIZE]; + static uint8_t ccounter = 0; + ccounter = (ccounter + 1) % 16; memset(tspat_buf, 0xff, TS_SIZE); - memset(tspat_buf, 0x0, 4 + 12 + 5); // TS_HDR_LEN + PAT_TABLE_LEN + 5 ts_id = Channel->Tid(); // Get transport stream id of the channel tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h) tspat_buf[1] = 0x40; // Set payload unit start indicator bit tspat_buf[2] = 0x0; // PID - tspat_buf[3] = 0x10; // Set payload flag to indicate precence of payload data - tspat_buf[4] = 0x0; // PSI + tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter + tspat_buf[4] = 0x0; // SI pointer field tspat_buf[5] = 0x0; // PAT table id tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1 - tspat_buf[8] = (ts_id >> 8) & 0xff; // Transport stream ID (bits 8-15) + tspat_buf[8] = (ts_id >> 8); // Transport stream ID (bits 8-15) tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7) - tspat_buf[10] = 0x01; // Version number 0, Current next indicator bit set + tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) | + pat.getCurrentNextIndicator();// Version number, Current next indicator tspat_buf[11] = 0x0; // Section number tspat_buf[12] = 0x0; // Last section number - tspat_buf[13] = (pmtSid >> 8) & 0xff; // Program number (bits 8-15) + tspat_buf[13] = (pmtSid >> 8); // Program number (bits 8-15) tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7) - tspat_buf[15] = (pmtPid >> 8) & 0xff; // Network ID (bits 8-12) + tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12) tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7) crc = 0xffffffff; len = 12; // PAT_TABLE_LEN @@ -278,9 +272,11 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i #endif } else isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length); - m_Streamer->SetPids(pmtPid); - Add(pmtPid, 0x02); - pmtVersion = -1; + if (pmtPid != prevPmtPid) { + m_Streamer->SetPids(pmtPid); + Add(pmtPid, 0x02); + pmtVersion = -1; + } return; } } @@ -295,7 +291,7 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i return; // skip broken PMT records if (pmtVersion != -1) { if (pmtVersion != pmt.getVersionNumber()) { - Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids"); + Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n"); Del(pmtPid, 0x02); pmtPid = 0; // this triggers PAT scan } @@ -333,7 +329,9 @@ cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Paramet m_Device(NULL), m_Receiver(NULL), m_PatFilter(NULL), +#if APIVERSNUM < 10703 m_PESRemux(NULL), +#endif m_ESRemux(NULL), m_PSRemux(NULL), m_ExtRemux(NULL) @@ -349,7 +347,9 @@ cStreamdevLiveStreamer::~cStreamdevLiveStreamer() DELETENULL(m_PatFilter); } DELETENULL(m_Receiver); +#if APIVERSNUM < 10703 delete m_PESRemux; +#endif delete m_ESRemux; delete m_PSRemux; delete m_ExtRemux; @@ -434,11 +434,7 @@ void cStreamdevLiveStreamer::StartReceiver(void) DELETENULL(m_Receiver); if (m_NumPids > 0) { Dprintf("Creating Receiver to respect changed pids\n"); -#if VDRVERSNUM < 10500 - m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->Ca(), m_Priority, m_Pids); -#else m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids); -#endif if (IsRunning() && m_Device != NULL) { Dprintf("Attaching new receiver\n"); Attach(); @@ -467,10 +463,12 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str return SetPids(pid); } +#if APIVERSNUM < 10703 case stPES: m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), m_Channel->Spids(), false); return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); +#endif case stPS: m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), @@ -483,6 +481,10 @@ bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType Str Detach(); DELETENULL(m_PatFilter); } + // Set pids from cChannel + SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids()); + if (m_Channel->Vpid() != m_Channel->Ppid()) + SetPid(m_Channel->Ppid(), true); // Set pids from PMT m_PatFilter = new cStreamdevPatFilter(this, m_Channel); return true; @@ -506,8 +508,10 @@ int cStreamdevLiveStreamer::Put(const uchar *Data, int Count) case stTSPIDS: return cStreamdevStreamer::Put(Data, Count); +#if APIVERSNUM < 10703 case stPES: return m_PESRemux->Put(Data, Count); +#endif case stES: return m_ESRemux->Put(Data, Count); @@ -530,8 +534,10 @@ uchar *cStreamdevLiveStreamer::Get(int &Count) case stTSPIDS: return cStreamdevStreamer::Get(Count); +#if APIVERSNUM < 10703 case stPES: return m_PESRemux->Get(Count); +#endif case stES: return m_ESRemux->Get(Count); @@ -555,9 +561,11 @@ void cStreamdevLiveStreamer::Del(int Count) cStreamdevStreamer::Del(Count); break; +#if APIVERSNUM < 10703 case stPES: m_PESRemux->Del(Count); break; +#endif case stES: m_ESRemux->Del(Count); @@ -618,7 +626,6 @@ std::string cStreamdevLiveStreamer::Report(void) // --- cStreamdevFilterStreamer ------------------------------------------------- -#if VDRVERSNUM >= 10300 cStreamdevFilterStreamer::cStreamdevFilterStreamer(): cStreamdevStreamer("streamdev-filterstreaming"), m_Device(NULL), @@ -720,5 +727,3 @@ void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelN } } #endif - -#endif // if VDRVERSNUM >= 10300 diff --git a/server/livestreamer.h b/server/livestreamer.h index 57c3a90..5c4ae8f 100644 --- a/server/livestreamer.h +++ b/server/livestreamer.h @@ -10,7 +10,9 @@ class cTS2PSRemux; class cTS2ESRemux; class cExternRemux; +#if APIVERSNUM < 10703 class cRemux; +#endif class cStreamdevPatFilter; class cStreamdevLiveReceiver; @@ -27,7 +29,9 @@ private: cDevice *m_Device; cStreamdevLiveReceiver *m_Receiver; cStreamdevPatFilter *m_PatFilter; +#if APIVERSNUM < 10703 cRemux *m_PESRemux; +#endif cTS2ESRemux *m_ESRemux; cTS2PSRemux *m_PSRemux; cExternRemux *m_ExtRemux; @@ -58,8 +62,6 @@ public: // --- cStreamdevFilterStreamer ------------------------------------------------- -# if VDRVERSNUM >= 10300 - //#include <vdr/status.h> class cStreamdevLiveFilter; @@ -85,6 +87,4 @@ public: //virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber); }; -# endif // if VDRVERSNUM >= 10300 - #endif // VDR_STREAMDEV_LIVESTREAMER_H diff --git a/server/menuHTTP.c b/server/menuHTTP.c index b5bb299..41b1f10 100644 --- a/server/menuHTTP.c +++ b/server/menuHTTP.c @@ -112,10 +112,10 @@ const cChannel* cChannelList::GetGroup(int Index) // ******************** cHtmlChannelList ****************** const char* cHtmlChannelList::menu = - "[<a href=\"/\">Home</a> (<a href=\"all.html\">no script</a>)] " - "[<a href=\"tree.html\">Tree View</a>] " - "[<a href=\"groups.html\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] " - "[<a href=\"channels.html\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] "; + "[<a href=\"/\">Home</a> (<a href=\"all.html\" tvid=\"RED\">no script</a>)] " + "[<a href=\"tree.html\" tvid=\"GREEN\">Tree View</a>] " + "[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] " + "[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] "; const char* cHtmlChannelList::css = "<style type=\"text/css\">\n" @@ -201,8 +201,10 @@ std::string cHtmlChannelList::StreamTypeMenu() (std::string) "[<a href=\"/TS/" + self + "\">TS</a>] "); typeMenu += (streamType == stPS ? (std::string) "[PS] " : (std::string) "[<a href=\"/PS/" + self + "\">PS</a>] "); +#if APIVERSNUM < 10703 typeMenu += (streamType == stPES ? (std::string) "[PES] " : (std::string) "[<a href=\"/PES/" + self + "\">PES</a>] "); +#endif typeMenu += (streamType == stES ? (std::string) "[ES] " : (std::string) "[<a href=\"/ES/" + self + "\">ES</a>] "); typeMenu += (streamType == stExtern ? (std::string) "[Extern] " : @@ -336,9 +338,26 @@ std::string cHtmlChannelList::GroupTitle() std::string cHtmlChannelList::ItemText() { std::string line; + std::string suffix; + + switch (streamType) { + case stTS: suffix = (std::string) ".ts"; break; + case stPS: suffix = (std::string) ".vob"; break; +#if APIVERSNUM < 10703 + // for Network Media Tank + case stPES: suffix = (std::string) ".vdr"; break; +#endif + default: suffix = ""; + } line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">"; - line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + "\">" + - current->Name() + "</a>"; + line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + suffix + "\""; + + // for Network Media Tank + line += (std::string) " vod "; + if (current->Number() < 1000) + line += (std::string) " tvid=\"" + (const char*) itoa(current->Number()) + "\""; + + line += (std::string) ">" + current->Name() + "</a>"; int count = 0; for (int i = 0; current->Apid(i) != 0; ++i, ++count) @@ -351,11 +370,11 @@ std::string cHtmlChannelList::ItemText() int index = 1; for (int i = 0; current->Apid(i) != 0; ++i, ++index) { line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() + - "+" + (const char*)itoa(index) + "\" class=\"apid\">" + current->Alang(i) + "</a>"; + "+" + (const char*)itoa(index) + suffix + "\" class=\"apid\" vod>" + current->Alang(i) + "</a>"; } for (int i = 0; current->Dpid(i) != 0; ++i, ++index) { line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() + - "+" + (const char*)itoa(index) + "\" class=\"dpid\">" + current->Dlang(i) + "</a>"; + "+" + (const char*)itoa(index) + suffix + "\" class=\"dpid\" vod>" + current->Dlang(i) + "</a>"; } } line += "</li>"; @@ -364,10 +383,8 @@ std::string cHtmlChannelList::ItemText() // ******************** cM3uChannelList ****************** cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base) -: cChannelList(Iterator) -#if defined(APIVERSNUM) && APIVERSNUM >= 10503 - , m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8") -#endif +: cChannelList(Iterator), + m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8") { base = strdup(Base); m3uState = msFirst; @@ -398,11 +415,7 @@ std::string cM3uChannelList::Next() return ""; } -#if defined(APIVERSNUM) && APIVERSNUM >= 10503 std::string name = (std::string) m_IConv.Convert(channel->Name()); -#else - std::string name = channel->Name(); -#endif if (channel->GroupSep()) { diff --git a/server/menuHTTP.h b/server/menuHTTP.h index 8be613b..fa699b9 100644 --- a/server/menuHTTP.h +++ b/server/menuHTTP.h @@ -126,9 +126,7 @@ class cM3uChannelList: public cChannelList char *base; enum eM3uState { msFirst, msContinue, msLast }; eM3uState m3uState; -#if defined(APIVERSNUM) && APIVERSNUM >= 10503 cCharSetConv m_IConv; -#endif public: virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl\r\n"; }; virtual bool HasNext(); diff --git a/server/server.c b/server/server.c index 5db895e..1bdb20a 100644 --- a/server/server.c +++ b/server/server.c @@ -1,10 +1,11 @@ /* - * $Id: server.c,v 1.5 2007/04/02 10:32:34 schmirl Exp $ + * $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $ */ #include "server/server.h" #include "server/componentVTP.h" #include "server/componentHTTP.h" +#include "server/componentIGMP.h" #include "server/setup.h" #include <vdr/tools.h> @@ -13,14 +14,15 @@ #include <errno.h> cSVDRPhosts StreamdevHosts; +char *opt_auth = NULL; +char *opt_remux = NULL; cStreamdevServer *cStreamdevServer::m_Instance = NULL; cList<cServerComponent> cStreamdevServer::m_Servers; cList<cServerConnection> cStreamdevServer::m_Clients; cStreamdevServer::cStreamdevServer(void): - cThread("streamdev server"), - m_Active(false) + cThread("streamdev server") { Start(); } @@ -35,6 +37,12 @@ void cStreamdevServer::Initialize(void) if (m_Instance == NULL) { if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP); if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP); + if (StreamdevServerSetup.StartIGMPServer) { + if (strcmp(StreamdevServerSetup.IGMPBindIP, "0.0.0.0") == 0) + esyslog("streamdev-server: Not starting IGMP. IGMP must be bound to a local IP"); + else + Register(new cComponentIGMP); + } m_Instance = new cStreamdevServer; } @@ -47,10 +55,8 @@ void cStreamdevServer::Destruct(void) void cStreamdevServer::Stop(void) { - if (m_Active) { - m_Active = false; + if (Running()) Cancel(3); - } } void cStreamdevServer::Register(cServerComponent *Server) @@ -60,8 +66,6 @@ void cStreamdevServer::Register(cServerComponent *Server) void cStreamdevServer::Action(void) { - m_Active = true; - /* Initialize Server components, deleting those that failed */ for (cServerComponent *c = m_Servers.First(); c;) { cServerComponent *next = m_Servers.Next(c); @@ -72,11 +76,11 @@ void cStreamdevServer::Action(void) if (m_Servers.Count() == 0) { esyslog("ERROR: no streamdev server activated, exiting"); - m_Active = false; + Cancel(-1); } cTBSelect select; - while (m_Active) { + while (Running()) { select.Clear(); /* Ask all Server components to register to the selector */ @@ -102,9 +106,9 @@ void cStreamdevServer::Action(void) sel = 0; } } - } while (sel < 0 && errno == ETIMEDOUT && m_Active); + } while (sel < 0 && errno == ETIMEDOUT && Running()); - if (!m_Active) + if (!Running()) break; if (sel < 0) { esyslog("fatal error, server exiting: %m"); @@ -115,13 +119,15 @@ void cStreamdevServer::Action(void) for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){ if (sel && select.CanRead(c->Socket())) { cServerConnection *client = c->Accept(); + if (!client) + continue; m_Clients.Add(client); if (m_Clients.Count() > StreamdevServerSetup.MaxClients) { esyslog("streamdev: too many clients, rejecting %s:%d", client->RemoteIp().c_str(), client->RemotePort()); client->Reject(); - } else if (!StreamdevHosts.Acceptable(client->RemoteIpAddr())) { + } else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) { esyslog("streamdev: client %s:%d not allowed to connect", client->RemoteIp().c_str(), client->RemotePort()); client->Reject(); @@ -164,6 +170,4 @@ void cStreamdevServer::Action(void) c->Destruct(); m_Servers.Del(c); } - - m_Active = false; } diff --git a/server/server.h b/server/server.h index af574f5..a44df1c 100644 --- a/server/server.h +++ b/server/server.h @@ -1,5 +1,5 @@ /* - * $Id: server.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $ + * $Id: server.h,v 1.6 2008/10/22 11:59:32 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_H @@ -10,12 +10,14 @@ #include "server/component.h" #include "server/connection.h" -#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(), "streamdevhosts.conf")) +#define DEFAULT_EXTERNREMUX (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "externremux.sh")) +#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "streamdevhosts.conf")) + +extern char *opt_auth; +extern char *opt_remux; class cStreamdevServer: public cThread { private: - bool m_Active; - static cStreamdevServer *m_Instance; static cList<cServerComponent> m_Servers; static cList<cServerConnection> m_Clients; diff --git a/server/setup.c b/server/setup.c index 2589fec..710b1fa 100644 --- a/server/setup.c +++ b/server/setup.c @@ -1,12 +1,11 @@ /* - * $Id: setup.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $ + * $Id: setup.c,v 1.6 2009/02/13 10:39:22 schmirl Exp $ */ #include <vdr/menuitems.h> #include "server/setup.h" #include "server/server.h" -#include "i18n.h" cStreamdevServerSetup StreamdevServerSetup; @@ -16,11 +15,15 @@ cStreamdevServerSetup::cStreamdevServerSetup(void) { VTPServerPort = 2004; StartHTTPServer = true; HTTPServerPort = 3000; - HTTPStreamType = stPES; - SuspendMode = smOffer; + HTTPStreamType = stTS; + StartIGMPServer = false; + IGMPClientPort = 1234; + IGMPStreamType = stTS; + SuspendMode = smAlways; AllowSuspend = false; strcpy(VTPBindIP, "0.0.0.0"); strcpy(HTTPBindIP, "0.0.0.0"); + strcpy(IGMPBindIP, "0.0.0.0"); } bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) { @@ -32,6 +35,10 @@ bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) { else if (strcmp(Name, "HTTPServerPort") == 0) HTTPServerPort = atoi(Value); else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value); else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value); + else if (strcmp(Name, "StartIGMPServer") == 0) StartIGMPServer = atoi(Value); + else if (strcmp(Name, "IGMPClientPort") == 0) IGMPClientPort = atoi(Value); + else if (strcmp(Name, "IGMPStreamType") == 0) IGMPStreamType = atoi(Value); + else if (strcmp(Name, "IGMPBindIP") == 0) strcpy(IGMPBindIP, Value); else if (strcmp(Name, "SuspendMode") == 0) SuspendMode = atoi(Value); else if (strcmp(Name, "AllowSuspend") == 0) AllowSuspend = atoi(Value); else return false; @@ -56,7 +63,11 @@ cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) { AddShortEdit(tr("HTTP Server Port"), m_NewSetup.HTTPServerPort); AddTypeEdit (tr("HTTP Streamtype"), m_NewSetup.HTTPStreamType); AddIpEdit (tr("Bind to IP"), m_NewSetup.HTTPBindIP); - + AddCategory (tr("Multicast Streaming Server")); + AddBoolEdit (tr("Start IGMP Server"), m_NewSetup.StartIGMPServer); + AddShortEdit(tr("Multicast Client Port"), m_NewSetup.IGMPClientPort); + AddTypeEdit (tr("Multicast Streamtype"), m_NewSetup.IGMPStreamType); + AddIpEdit (tr("Bind to IP"), m_NewSetup.IGMPBindIP); SetCurrent(Get(1)); } @@ -70,7 +81,10 @@ void cStreamdevServerMenuSetupPage::Store(void) { || strcmp(m_NewSetup.VTPBindIP, StreamdevServerSetup.VTPBindIP) != 0 || m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer || m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort - || strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0) { + || strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0 + || m_NewSetup.StartIGMPServer != StreamdevServerSetup.StartIGMPServer + || m_NewSetup.IGMPClientPort != StreamdevServerSetup.IGMPClientPort + || strcmp(m_NewSetup.IGMPBindIP, StreamdevServerSetup.IGMPBindIP) != 0) { restart = true; cStreamdevServer::Destruct(); } @@ -83,6 +97,10 @@ void cStreamdevServerMenuSetupPage::Store(void) { SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort); SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType); SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP); + SetupStore("StartIGMPServer", m_NewSetup.StartIGMPServer); + SetupStore("IGMPClientPort", m_NewSetup.IGMPClientPort); + SetupStore("IGMPStreamType", m_NewSetup.IGMPStreamType); + SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP); SetupStore("SuspendMode", m_NewSetup.SuspendMode); SetupStore("AllowSuspend", m_NewSetup.AllowSuspend); diff --git a/server/setup.h b/server/setup.h index 840567f..d2b1592 100644 --- a/server/setup.h +++ b/server/setup.h @@ -1,5 +1,5 @@ /* - * $Id: setup.h,v 1.1.1.1 2004/12/30 22:44:21 lordjaxom Exp $ + * $Id: setup.h,v 1.2 2009/02/13 10:39:22 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SETUPSERVER_H @@ -20,6 +20,10 @@ struct cStreamdevServerSetup { int HTTPServerPort; int HTTPStreamType; char HTTPBindIP[20]; + int StartIGMPServer; + int IGMPClientPort; + int IGMPStreamType; + char IGMPBindIP[20]; int SuspendMode; int AllowSuspend; }; diff --git a/server/streamer.c b/server/streamer.c index 979032a..9795cc6 100644 --- a/server/streamer.c +++ b/server/streamer.c @@ -1,5 +1,5 @@ /* - * $Id: streamer.c,v 1.16 2007/09/21 11:45:53 schmirl Exp $ + * $Id: streamer.c,v 1.18 2009/02/13 10:39:22 schmirl Exp $ */ #include <vdr/ringbuffer.h> @@ -20,16 +20,15 @@ cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer): cThread("streamdev-writer"), m_Streamer(Streamer), - m_Socket(Socket), - m_Active(false) + m_Socket(Socket) { } cStreamdevWriter::~cStreamdevWriter() { Dprintf("destructing writer\n"); - m_Active = false; - Cancel(3); + if (Running()) + Cancel(3); } void cStreamdevWriter::Action(void) @@ -39,11 +38,10 @@ void cStreamdevWriter::Action(void) int max = 0; uchar *block = NULL; int count, offset = 0; - m_Active = true; sel.Clear(); sel.Add(*m_Socket, true); - while (m_Active) { + while (Running()) { if (block == NULL) { block = m_Streamer->Get(count); offset = 0; @@ -57,23 +55,39 @@ void cStreamdevWriter::Action(void) if (sel.CanWrite(*m_Socket)) { int written; - if ((written = m_Socket->Write(block + offset, count)) == -1) { - esyslog("ERROR: streamdev-server: couldn't send data: %m"); + int pkgsize = count; + // SOCK_DGRAM indicates multicast + if (m_Socket->Type() == SOCK_DGRAM) { + // don't fragment multicast packets + // max. payload on standard local ethernet is 1416 to 1456 bytes + // and some STBs expect complete TS packets + // so let's always limit to 7 * TS_SIZE = 1316 + if (pkgsize > 7 * TS_SIZE) + pkgsize = 7 * TS_SIZE; + else + pkgsize -= pkgsize % TS_SIZE; + } + if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) { + esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize); break; } + + // statistics if (count > max) max = count; offset += written; count -= written; - if (count == 0) { + + // less than one TS packet left: + // delete what we've written so far and get next chunk + if (count < TS_SIZE) { m_Streamer->Del(offset); block = NULL; } } } } - m_Active = false; Dprintf("Max. Transmit Blocksize was: %d\n", max); } @@ -81,7 +95,6 @@ void cStreamdevWriter::Action(void) cStreamdevStreamer::cStreamdevStreamer(const char *Name): cThread(Name), - m_Active(false), m_Running(false), m_Writer(NULL), m_RingBuffer(new cRingBufferLinear(STREAMERBUFSIZE, TS_SIZE * 2, @@ -109,7 +122,7 @@ void cStreamdevStreamer::Start(cTBSocket *Socket) void cStreamdevStreamer::Activate(bool On) { - if (On && !m_Active) { + if (On && !Active()) { Dprintf("activate streamer\n"); m_Writer->Start(); cThread::Start(); @@ -118,9 +131,8 @@ void cStreamdevStreamer::Activate(bool On) void cStreamdevStreamer::Stop(void) { - if (m_Active) { + if (Running()) { Dprintf("stopping streamer\n"); - m_Active = false; Cancel(3); } if (m_Running) { @@ -132,8 +144,7 @@ void cStreamdevStreamer::Stop(void) void cStreamdevStreamer::Action(void) { - m_Active = true; - while (m_Active) { + while (Running()) { int got; uchar *block = m_RingBuffer->Get(got); diff --git a/server/streamer.h b/server/streamer.h index e557d55..20323b7 100644 --- a/server/streamer.h +++ b/server/streamer.h @@ -1,5 +1,5 @@ /* - * $Id: streamer.h,v 1.8 2007/04/02 10:32:34 schmirl Exp $ + * $Id: streamer.h,v 1.10 2009/02/13 10:39:22 schmirl Exp $ */ #ifndef VDR_STREAMDEV_STREAMER_H @@ -12,6 +12,10 @@ class cTBSocket; class cStreamdevStreamer; +#ifndef TS_SIZE +#define TS_SIZE 188 +#endif + #define STREAMERBUFSIZE MEGABYTE(4) #define WRITERBUFSIZE KILOBYTE(256) @@ -21,7 +25,6 @@ class cStreamdevWriter: public cThread { private: cStreamdevStreamer *m_Streamer; cTBSocket *m_Socket; - bool m_Active; protected: virtual void Action(void); @@ -29,15 +32,12 @@ protected: public: cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer); virtual ~cStreamdevWriter(); - - bool IsActive(void) const { return m_Active; } }; // --- cStreamdevStreamer ----------------------------------------------------- class cStreamdevStreamer: public cThread { private: - bool m_Active; bool m_Running; cStreamdevWriter *m_Writer; cRingBufferLinear *m_RingBuffer; @@ -54,7 +54,7 @@ public: virtual void Start(cTBSocket *Socket); virtual void Stop(void); - bool Abort(void) const; + bool Abort(void); void Activate(bool On); int Receive(uchar *Data, int Length) { return m_RingBuffer->Put(Data, Length); } @@ -68,9 +68,9 @@ public: virtual void Attach(void) {} }; -inline bool cStreamdevStreamer::Abort(void) const +inline bool cStreamdevStreamer::Abort(void) { - return m_Active && !m_Writer->IsActive(); + return Active() && !m_Writer->Active(); } #endif // VDR_STREAMDEV_STREAMER_H diff --git a/server/suspend.c b/server/suspend.c index 9ac9ac5..b6e1382 100644 --- a/server/suspend.c +++ b/server/suspend.c @@ -1,5 +1,5 @@ /* - * $Id: suspend.c,v 1.1.1.1 2004/12/30 22:44:21 lordjaxom Exp $ + * $Id: suspend.c,v 1.3 2008/10/22 11:59:32 schmirl Exp $ */ #include "server/suspend.h" @@ -7,13 +7,12 @@ #include "common.h" cSuspendLive::cSuspendLive(void) -#if VDRVERSNUM >= 10300 : cThread("Streamdev: server suspend") -#endif { } cSuspendLive::~cSuspendLive() { + Stop(); Detach(); } @@ -26,26 +25,15 @@ void cSuspendLive::Activate(bool On) { } void cSuspendLive::Stop(void) { - if (m_Active) { - m_Active = false; + if (Running()) Cancel(3); - } } void cSuspendLive::Action(void) { -#if VDRVERSNUM < 10300 - isyslog("Streamdev: Suspend Live thread started (pid = %d)", getpid()); -#endif - - m_Active = true; - while (m_Active) { + while (Running()) { DeviceStillPicture(suspend_mpg, sizeof(suspend_mpg)); - usleep(100000); + cCondWait::SleepMs(100); } - -#if VDRVERSNUM < 10300 - isyslog("Streamdev: Suspend Live thread stopped"); -#endif } bool cSuspendCtl::m_Active = false; @@ -61,7 +49,7 @@ cSuspendCtl::~cSuspendCtl() { } eOSState cSuspendCtl::ProcessKey(eKeys Key) { - if (!m_Suspend->IsActive() || Key == kBack) { + if (!m_Suspend->Active() || Key == kBack) { DELETENULL(m_Suspend); return osEnd; } diff --git a/server/suspend.h b/server/suspend.h index f60e6ec..bea25ee 100644 --- a/server/suspend.h +++ b/server/suspend.h @@ -1,5 +1,5 @@ /* - * $Id: suspend.h,v 1.1.1.1 2004/12/30 22:44:26 lordjaxom Exp $ + * $Id: suspend.h,v 1.2 2008/10/22 11:59:32 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SUSPEND_H @@ -7,10 +7,7 @@ #include <vdr/player.h> -class cSuspendLive: public cPlayer, cThread { -private: - bool m_Active; - +class cSuspendLive: public cPlayer, public cThread { protected: virtual void Activate(bool On); virtual void Action(void); @@ -20,8 +17,6 @@ protected: public: cSuspendLive(void); virtual ~cSuspendLive(); - - bool IsActive(void) const { return m_Active; } }; class cSuspendCtl: public cControl { |