diff options
Diffstat (limited to 'server/connection.c')
-rw-r--r-- | server/connection.c | 218 |
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 |