Live TV must be switched in VDR main thread (fixes #568).

This commit is contained in:
Frank Schmirler 2011-03-07 21:37:08 +01:00
parent ee7929bd39
commit c06970123c
7 changed files with 84 additions and 28 deletions

View File

@ -1,6 +1,7 @@
VDR Plugin 'streamdev' Revision History VDR Plugin 'streamdev' Revision History
--------------------------------------- ---------------------------------------
- live TV must be switched in VDR main thread
- return value of streamdev-clients cDevice::NumProvidedSystems() now - return value of streamdev-clients cDevice::NumProvidedSystems() now
configurable in plugin setup configurable in plugin setup

View File

@ -8,11 +8,60 @@
#include "common.h" #include "common.h"
#include <vdr/tools.h> #include <vdr/tools.h>
#include <vdr/thread.h>
#include <vdr/transfer.h> #include <vdr/transfer.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <errno.h> #include <errno.h>
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): cServerConnection::cServerConnection(const char *Protocol, int Type):
cTBSocket(Type), cTBSocket(Type),
m_Protocol(Protocol), m_Protocol(Protocol),
@ -22,10 +71,12 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
m_WriteBytes(0), m_WriteBytes(0),
m_WriteIndex(0) m_WriteIndex(0)
{ {
m_SwitchLive = new cSwitchLive();
} }
cServerConnection::~cServerConnection() cServerConnection::~cServerConnection()
{ {
delete m_SwitchLive;
} }
const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) { 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)) { && UsedByLiveTV(device)) {
// now we would have to switch away live tv...let's see if live tv // now we would have to switch away live tv...let's see if live tv
// can be handled by another device // can be handled by another device
#if VDRVERSNUM >= 10516 device = m_SwitchLive->Switch(device, Channel);
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
} }
if (!device) { if (!device) {
@ -371,3 +395,8 @@ bool cServerConnection::ProvidesChannel(const cChannel *Channel, int Priority)
} }
return device; return device;
} }
void cServerConnection::MainThreadHook()
{
m_SwitchLive->Switch();
}

View File

@ -15,6 +15,7 @@ typedef std::pair<std::string,std::string> tStrStr;
class cChannel; class cChannel;
class cDevice; class cDevice;
class cSwitchLive;
/* Basic capabilities of a straight text-based protocol, most functions /* Basic capabilities of a straight text-based protocol, most functions
virtual to support more complicated protocols */ virtual to support more complicated protocols */
@ -33,6 +34,8 @@ private:
uint m_WriteBytes; uint m_WriteBytes;
uint m_WriteIndex; uint m_WriteIndex;
cSwitchLive *m_SwitchLive;
tStrStrMap m_Headers; tStrStrMap m_Headers;
/* Check if a device would be available for transfering the given /* 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. */ /* Test if a call to GetDevice would return a usable device. */
bool ProvidesChannel(const cChannel *Channel, int Priority); 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 Flushed(void) {}
virtual void Detach(void) = 0; virtual void Detach(void) = 0;

View File

@ -121,7 +121,9 @@ void cStreamdevServer::Action(void)
cServerConnection *client = c->Accept(); cServerConnection *client = c->Accept();
if (!client) if (!client)
continue; continue;
Lock();
m_Clients.Add(client); m_Clients.Add(client);
Unlock();
if (m_Clients.Count() > StreamdevServerSetup.MaxClients) { if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
esyslog("streamdev: too many clients, rejecting %s:%d", esyslog("streamdev: too many clients, rejecting %s:%d",
@ -153,17 +155,21 @@ void cStreamdevServer::Action(void)
isyslog("streamdev: closing streamdev connection to %s:%d", isyslog("streamdev: closing streamdev connection to %s:%d",
s->RemoteIp().c_str(), s->RemotePort()); s->RemoteIp().c_str(), s->RemotePort());
s->Close(); s->Close();
Lock();
m_Clients.Del(s); m_Clients.Del(s);
Unlock();
} }
s = next; s = next;
} }
} }
Lock();
while (m_Clients.Count() > 0) { while (m_Clients.Count() > 0) {
cServerConnection *s = m_Clients.First(); cServerConnection *s = m_Clients.First();
s->Close(); s->Close();
m_Clients.Del(s); m_Clients.Del(s);
} }
Unlock();
while (m_Servers.Count() > 0) { while (m_Servers.Count() > 0) {
cServerComponent *c = m_Servers.First(); cServerComponent *c = m_Servers.First();
@ -171,3 +177,10 @@ void cStreamdevServer::Action(void)
m_Servers.Del(c); 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();
}

View File

@ -36,6 +36,7 @@ public:
static void Initialize(void); static void Initialize(void);
static void Destruct(void); static void Destruct(void);
static bool Active(void); static bool Active(void);
static void MainThreadHook(void);
}; };
inline bool cStreamdevServer::Active(void) inline bool cStreamdevServer::Active(void)

View File

@ -130,6 +130,11 @@ cOsdObject *cPluginStreamdevServer::MainMenuAction(void)
return NULL; return NULL;
} }
void cPluginStreamdevServer::MainThreadHook(void)
{
cStreamdevServer::MainThreadHook();
}
cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void) cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void)
{ {
return new cStreamdevServerMenuSetupPage; return new cStreamdevServerMenuSetupPage;

View File

@ -26,6 +26,7 @@ public:
virtual cString Active(void); virtual cString Active(void);
virtual const char *MainMenuEntry(void); virtual const char *MainMenuEntry(void);
virtual cOsdObject *MainMenuAction(void); virtual cOsdObject *MainMenuAction(void);
virtual void MainThreadHook(void);
virtual cMenuSetupPage *SetupMenu(void); virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value); virtual bool SetupParse(const char *Name, const char *Value);
}; };