From 74ce99971c59d960babf163c191d6014a2a32c81 Mon Sep 17 00:00:00 2001 From: Frank Schmirler Date: Mon, 7 Mar 2011 21:37:08 +0100 Subject: [PATCH] Live TV must be switched in VDR main thread (fixes #568). --- HISTORY | 1 + server/connection.c | 85 ++++++++++++++++++++++++++------------- server/connection.h | 6 +++ server/server.c | 13 ++++++ server/server.h | 1 + server/streamdev-server.c | 5 +++ server/streamdev-server.h | 1 + 7 files changed, 84 insertions(+), 28 deletions(-) diff --git a/HISTORY b/HISTORY index bdcad70..15234b9 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,7 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- live TV must be switched in VDR main thread - return value of streamdev-clients cDevice::NumProvidedSystems() now configurable in plugin setup diff --git a/server/connection.c b/server/connection.c index 78a023a..3bf0ad5 100644 --- a/server/connection.c +++ b/server/connection.c @@ -8,11 +8,60 @@ #include "common.h" #include +#include #include #include #include #include +class cSwitchLive { +private: + cMutex mutex; + cCondWait switched; + cDevice *device; + const cChannel *channel; +public: + cDevice* Switch(cDevice *Device, const cChannel *Channel); + void Switch(void); + cSwitchLive(void); +}; + +cSwitchLive::cSwitchLive(): device(NULL), channel(NULL) +{ +} + +cDevice* cSwitchLive::Switch(cDevice *Device, const cChannel *Channel) +{ + mutex.Lock(); + device = Device; + channel = Channel; + mutex.Unlock(); + switched.Wait(); + return device; +} + +void cSwitchLive::Switch(void) +{ + mutex.Lock(); + if (channel && device) { + cDevice::SetAvoidDevice(device); + if (!Channels.SwitchTo(cDevice::CurrentChannel())) { + if (StreamdevServerSetup.SuspendMode == smAlways) { + Channels.SwitchTo(channel->Number()); + Skins.Message(mtInfo, tr("Streaming active")); + } + else { + esyslog("streamdev: Can't receive channel %d (%s) from device %d. Moving live TV to other device failed (PrimaryDevice=%d, ActualDevice=%d)", channel->Number(), channel->Name(), device->CardIndex(), cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex()); + device = NULL; + } + } + // make sure we don't come in here next time + channel = NULL; + switched.Signal(); + } + mutex.Unlock(); +} + cServerConnection::cServerConnection(const char *Protocol, int Type): cTBSocket(Type), m_Protocol(Protocol), @@ -22,10 +71,12 @@ cServerConnection::cServerConnection(const char *Protocol, int Type): m_WriteBytes(0), m_WriteIndex(0) { + m_SwitchLive = new cSwitchLive(); } cServerConnection::~cServerConnection() { + delete m_SwitchLive; } const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) { @@ -302,34 +353,7 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority) && UsedByLiveTV(device)) { // now we would have to switch away live tv...let's see if live tv // can be handled by another device -#if VDRVERSNUM >= 10516 - cDevice::SetAvoidDevice(device); - if (!Channels.SwitchTo(cDevice::CurrentChannel())) { - if (StreamdevServerSetup.SuspendMode == smAlways) { - Channels.SwitchTo(Channel->Number()); - Skins.QueueMessage(mtInfo, tr("Streaming active")); - } - else { - dsyslog("streamdev: GetDevice: Live TV not suspended"); - device = NULL; - } - } -#else - const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel()); - cDevice *newdev = current ? CheckDevice(current, 0, true, device) : NULL; - if (newdev) { - dsyslog("streamdev: GetDevice: Trying to move live TV to device %d", newdev->CardIndex()); - newdev->SwitchChannel(current, true); - } - else if (StreamdevServerSetup.SuspendMode == smAlways) { - Channels.SwitchTo(Channel->Number()); - Skins.QueueMessage(mtInfo, tr("Streaming active")); - } - else { - dsyslog("streamdev: GetDevice: Live TV not suspended"); - device = NULL; - } -#endif + device = m_SwitchLive->Switch(device, Channel); } if (!device) { @@ -371,3 +395,8 @@ bool cServerConnection::ProvidesChannel(const cChannel *Channel, int Priority) } return device; } + +void cServerConnection::MainThreadHook() +{ + m_SwitchLive->Switch(); +} diff --git a/server/connection.h b/server/connection.h index 01a070c..6cc6764 100644 --- a/server/connection.h +++ b/server/connection.h @@ -15,6 +15,7 @@ typedef std::pair tStrStr; class cChannel; class cDevice; +class cSwitchLive; /* Basic capabilities of a straight text-based protocol, most functions virtual to support more complicated protocols */ @@ -33,6 +34,8 @@ private: uint m_WriteBytes; uint m_WriteIndex; + cSwitchLive *m_SwitchLive; + tStrStrMap m_Headers; /* Check if a device would be available for transfering the given @@ -108,6 +111,9 @@ public: /* Test if a call to GetDevice would return a usable device. */ bool ProvidesChannel(const cChannel *Channel, int Priority); + /* Do things which must be done in VDR's main loop */ + void MainThreadHook(); + virtual void Flushed(void) {} virtual void Detach(void) = 0; diff --git a/server/server.c b/server/server.c index 1bdb20a..c7fa96f 100644 --- a/server/server.c +++ b/server/server.c @@ -121,7 +121,9 @@ void cStreamdevServer::Action(void) cServerConnection *client = c->Accept(); if (!client) continue; + Lock(); m_Clients.Add(client); + Unlock(); if (m_Clients.Count() > StreamdevServerSetup.MaxClients) { esyslog("streamdev: too many clients, rejecting %s:%d", @@ -153,17 +155,21 @@ void cStreamdevServer::Action(void) isyslog("streamdev: closing streamdev connection to %s:%d", s->RemoteIp().c_str(), s->RemotePort()); s->Close(); + Lock(); m_Clients.Del(s); + Unlock(); } s = next; } } + Lock(); while (m_Clients.Count() > 0) { cServerConnection *s = m_Clients.First(); s->Close(); m_Clients.Del(s); } + Unlock(); while (m_Servers.Count() > 0) { cServerComponent *c = m_Servers.First(); @@ -171,3 +177,10 @@ void cStreamdevServer::Action(void) m_Servers.Del(c); } } + +void cStreamdevServer::MainThreadHook(void) +{ + cThreadLock lock(m_Instance); + for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s)) + s->MainThreadHook(); +} diff --git a/server/server.h b/server/server.h index a44df1c..dfe9cc1 100644 --- a/server/server.h +++ b/server/server.h @@ -36,6 +36,7 @@ public: static void Initialize(void); static void Destruct(void); static bool Active(void); + static void MainThreadHook(void); }; inline bool cStreamdevServer::Active(void) diff --git a/server/streamdev-server.c b/server/streamdev-server.c index b444df7..f31576c 100644 --- a/server/streamdev-server.c +++ b/server/streamdev-server.c @@ -130,6 +130,11 @@ cOsdObject *cPluginStreamdevServer::MainMenuAction(void) return NULL; } +void cPluginStreamdevServer::MainThreadHook(void) +{ + cStreamdevServer::MainThreadHook(); +} + cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void) { return new cStreamdevServerMenuSetupPage; diff --git a/server/streamdev-server.h b/server/streamdev-server.h index 4083689..f1be8aa 100644 --- a/server/streamdev-server.h +++ b/server/streamdev-server.h @@ -26,6 +26,7 @@ public: virtual cString Active(void); virtual const char *MainMenuEntry(void); virtual cOsdObject *MainMenuAction(void); + virtual void MainThreadHook(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); };