Bug #568 ยป streamdev-mainthread_switch.diff
| server/connection.c | ||
|---|---|---|
|
#include "common.h"
|
||
|
#include <vdr/tools.h>
|
||
|
#include <vdr/thread.h>
|
||
|
#include <vdr/transfer.h>
|
||
|
#include <string.h>
|
||
|
#include <stdarg.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):
|
||
|
cTBSocket(Type),
|
||
|
m_Protocol(Protocol),
|
||
| ... | ... | |
|
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) {
|
||
| ... | ... | |
|
&& 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) {
|
||
| ... | ... | |
|
}
|
||
|
return device;
|
||
|
}
|
||
|
void cServerConnection::MainThreadHook()
|
||
|
{
|
||
|
m_SwitchLive->Switch();
|
||
|
}
|
||
| server/connection.h | ||
|---|---|---|
|
class cChannel;
|
||
|
class cDevice;
|
||
|
class cSwitchLive;
|
||
|
/* Basic capabilities of a straight text-based protocol, most functions
|
||
|
virtual to support more complicated protocols */
|
||
| ... | ... | |
|
uint m_WriteBytes;
|
||
|
uint m_WriteIndex;
|
||
|
cSwitchLive *m_SwitchLive;
|
||
|
tStrStrMap m_Headers;
|
||
|
/* Check if a device would be available for transfering the given
|
||
| ... | ... | |
|
/* 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;
|
||
| server/server.c | ||
|---|---|---|
|
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",
|
||
| ... | ... | |
|
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();
|
||
| ... | ... | |
|
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();
|
||
|
}
|
||
| server/server.h | ||
|---|---|---|
|
static void Initialize(void);
|
||
|
static void Destruct(void);
|
||
|
static bool Active(void);
|
||
|
static void MainThreadHook(void);
|
||
|
};
|
||
|
inline bool cStreamdevServer::Active(void)
|
||
| server/streamdev-server.c | ||
|---|---|---|
|
return NULL;
|
||
|
}
|
||
|
void cPluginStreamdevServer::MainThreadHook(void)
|
||
|
{
|
||
|
cStreamdevServer::MainThreadHook();
|
||
|
}
|
||
|
cMenuSetupPage *cPluginStreamdevServer::SetupMenu(void)
|
||
|
{
|
||
|
return new cStreamdevServerMenuSetupPage;
|
||
| server/streamdev-server.h | ||
|---|---|---|
|
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);
|
||
|
};
|
||