summaryrefslogtreecommitdiff
path: root/server/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/connection.c')
-rw-r--r--server/connection.c218
1 files changed, 20 insertions, 198 deletions
diff --git a/server/connection.c b/server/connection.c
index b6df6fd..9c7ae31 100644
--- a/server/connection.c
+++ b/server/connection.c
@@ -14,71 +14,6 @@
#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) {
-#if APIVERSNUM >= 10726
- cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
- cDevice *newdev = cServerConnection::CheckDevice(current, 0, true, device);
- if (!newdev) {
- 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;
- }
- }
- else {
- newdev->SwitchChannel(current, true);
- }
-#else
- 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;
- }
- }
-#endif
- // 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),
@@ -87,14 +22,13 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
m_Pending(false),
m_ReadBytes(0),
m_WriteBytes(0),
- m_WriteIndex(0)
+ m_WriteIndex(0),
+ m_SwitchTo(NULL)
{
- m_SwitchLive = new cSwitchLive();
}
cServerConnection::~cServerConnection()
{
- delete m_SwitchLive;
}
const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid, int *Dpid) {
@@ -264,99 +198,6 @@ bool cServerConnection::Close()
return cTBSocket::Close();
}
-static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
-{
- int MaxNumProvidedSystems = (1 << AvailableBits) - 1;
- int NumProvidedSystems = Device->NumProvidedSystems();
- if (NumProvidedSystems > MaxNumProvidedSystems) {
- esyslog("ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed", Device->CardIndex() + 1, NumProvidedSystems, MaxNumProvidedSystems);
- NumProvidedSystems = MaxNumProvidedSystems;
- }
- else if (NumProvidedSystems <= 0) {
- esyslog("ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1", Device->CardIndex() + 1, NumProvidedSystems);
- NumProvidedSystems = 1;
- }
- return NumProvidedSystems;
-}
-
-/*
- * copy of cDevice::GetDevice(...) but without side effects (not detaching receivers)
- */
-cDevice* cServerConnection::CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice)
-{
- //cDevice *AvoidDevice = avoidDevice;
- //avoidDevice = NULL;
- // Collect the current priorities of all CAM slots that can decrypt the channel:
- int NumCamSlots = CamSlots.Count();
- int SlotPriority[NumCamSlots];
- int NumUsableSlots = 0;
- if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
- for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
- SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
- if (CamSlot->ModuleStatus() == msReady) {
- if (CamSlot->ProvidesCa(Channel->Caids())) {
- if (!ChannelCamRelations.CamChecked(Channel->GetChannelID(), CamSlot->SlotNumber())) {
- SlotPriority[CamSlot->Index()] = CamSlot->Priority();
- NumUsableSlots++;
- }
- }
- }
- }
- if (!NumUsableSlots)
- return NULL; // no CAM is able to decrypt this channel
- }
-
- cDevice *d = NULL;
- //cCamSlot *s = NULL;
-
- uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
- for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
- if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
- continue; // there is no CAM available in this slot
- for (int i = 0; i < cDevice::NumDevices(); i++) {
- cDevice *device = cDevice::GetDevice(i);
- if (device == AvoidDevice)
- continue; // we've been asked to skip this device
- if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device->CardIndex() + 1)
- continue; // a specific card was requested, but not this one
- if (NumUsableSlots && !CamSlots.Get(j)->Assign(device, true))
- continue; // CAM slot can't be used with this device
- bool ndr;
- if (device->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basicly able to do the job
- if (NumUsableSlots && device->CamSlot() && device->CamSlot() != CamSlots.Get(j))
- ndr = true; // using a different CAM slot requires detaching receivers
- // Put together an integer number that reflects the "impact" using
- // this device would have on the overall system. Each condition is represented
- // by one bit in the number (or several bits, if the condition is actually
- // a numeric value). The sequence in which the conditions are listed corresponds
- // to their individual severity, where the one listed first will make the most
- // difference, because it results in the most significant bit of the result.
- uint32_t imp = 0;
- imp <<= 1; imp |= LiveView ? !device->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
- imp <<= 1; imp |= !device->Receiving() && (device != cTransferControl::ReceiverDevice() || device->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
- imp <<= 1; imp |= device->Receiving(); // avoid devices that are receiving
- imp <<= 4; imp |= GetClippedNumProvidedSystems(4, device) - 1; // avoid cards which support multiple delivery systems
- imp <<= 1; imp |= device == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
- imp <<= 8; imp |= min(max(device->Priority() + MAXPRIORITY, 0), 0xFF); // use the device with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
- imp <<= 8; imp |= min(max((NumUsableSlots ? SlotPriority[j] : 0) + MAXPRIORITY, 0), 0xFF); // use the CAM slot with the lowest priority (+MAXPRIORITY to assure that values -99..99 can be used)
- imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
- imp <<= 1; imp |= NumUsableSlots ? 0 : device->HasCi(); // avoid cards with Common Interface for FTA channels
- imp <<= 1; imp |= device->AvoidRecording(); // avoid SD full featured cards
- imp <<= 1; imp |= NumUsableSlots ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), j + 1) : 0; // prefer CAMs that are known to decrypt this channel
- imp <<= 1; imp |= device->IsPrimaryDevice(); // avoid the primary device
- if (imp < Impact) {
- // This device has less impact than any previous one, so we take it.
- Impact = imp;
- d = device;
- }
- }
- }
- if (!NumUsableSlots)
- break; // no CAM necessary, so just one loop over the devices
- }
- return d;
-}
-
bool cServerConnection::UsedByLiveTV(cDevice *device)
{
return device == cTransferControl::ReceiverDevice() ||
@@ -367,59 +208,40 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
{
// turn off the streams of this connection
Detach();
- // This call may detach receivers of the device it returns
- cDevice *device = cDevice::GetDevice(Channel, Priority, false);
-
- if (device && !device->IsTunedToTransponder(Channel)
- && UsedByLiveTV(device)) {
- // now we would have to switch away live tv...let's see if live tv
- // can be handled by another device
- device = m_SwitchLive->Switch(device, Channel);
- }
+ cDevice *device = cDevice::GetDevice(Channel, Priority, false);
if (!device) {
// can't switch - continue the current stream
Attach();
dsyslog("streamdev: GetDevice failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
}
+ else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
+ // switched away live TV
+ m_SwitchTo = Channel;
+ }
return device;
}
bool cServerConnection::ProvidesChannel(const cChannel *Channel, int Priority)
{
- cDevice *device = CheckDevice(Channel, Priority, false);
- if (!device || (StreamdevServerSetup.SuspendMode != smAlways
- && !device->IsTunedToTransponder(Channel)
- && UsedByLiveTV(device))) {
- // no device available or the device is in use for live TV and suspend mode doesn't allow us to switch it:
- // maybe a device would be free if THIS connection did turn off its streams?
- Detach();
- device = CheckDevice(Channel, Priority, false);
- Attach();
- if (device && StreamdevServerSetup.SuspendMode != smAlways
- && !device->IsTunedToTransponder(Channel)
- && UsedByLiveTV(device)) {
- // now we would have to switch away live tv...let's see if live tv
- // can be handled by another device
- const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
- cDevice *newdev = current ? CheckDevice(current, 0, true, device) : NULL;
- if (newdev) {
- dsyslog("streamdev: Providing channel %d (%s) at priority %d requires moving live TV to device %d (PrimaryDevice=%d, ActualDevice=%d)", Channel->Number(), Channel->Name(), Priority, newdev->CardIndex(), cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex());
- }
- else {
- device = NULL;
- dsyslog("streamdev: Not providing channel %d (%s) at priority %d - live TV not suspended", Channel->Number(), Channel->Name(), Priority);
- }
- }
- else if (!device)
- dsyslog("streamdev: No device provides channel %d (%s) at priority %d", Channel->Number(), Channel->Name(), Priority);
- }
+ cDevice *device = cDevice::GetDevice(Channel, Priority, false, true);
+ if (!device)
+ dsyslog("streamdev: No device provides channel %d (%s) at priority %d", Channel->Number(), Channel->Name(), Priority);
return device;
}
void cServerConnection::MainThreadHook()
{
- m_SwitchLive->Switch();
+ if (m_SwitchTo)
+ {
+ // switched away live TV. Try previous channel on other device first
+ if (!Channels.SwitchTo(cDevice::CurrentChannel())) {
+ // switch to streamdev channel otherwise
+ Channels.SwitchTo(m_SwitchTo->Number());
+ Skins.Message(mtInfo, tr("Streaming active"));
+ }
+ m_SwitchTo = NULL;
+ }
}
cString cServerConnection::ToText() const