mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
A device is now always kept occupied if a timer is in VPS margin or needs the transponder
This commit is contained in:
parent
51dca45a0c
commit
179d5b87fc
@ -2569,6 +2569,8 @@ Markus Ehrnsperger <markus.ehrnsperger@googlemail.com>
|
|||||||
a decoder
|
a decoder
|
||||||
for improving handling present/following data for VPS timers
|
for improving handling present/following data for VPS timers
|
||||||
for making logging event status changes also show the previous status
|
for making logging event status changes also show the previous status
|
||||||
|
for making a device always being kept occupied if a timer is in VPS margin or needs the
|
||||||
|
transponder
|
||||||
|
|
||||||
Werner Färber <w.faerber@gmx.de>
|
Werner Färber <w.faerber@gmx.de>
|
||||||
for reporting a bug in handling the cPluginManager::Active() result when pressing
|
for reporting a bug in handling the cPluginManager::Active() result when pressing
|
||||||
|
4
HISTORY
4
HISTORY
@ -9887,7 +9887,7 @@ Video Disk Recorder Revision History
|
|||||||
- Fixed possible duplicate component entries in the info of an ongoing recording
|
- Fixed possible duplicate component entries in the info of an ongoing recording
|
||||||
(reported by Christoph Haubrich).
|
(reported by Christoph Haubrich).
|
||||||
|
|
||||||
2024-03-28:
|
2024-03-29:
|
||||||
|
|
||||||
- Fixed the move assignment operator to check for self-assignment (suggested by
|
- Fixed the move assignment operator to check for self-assignment (suggested by
|
||||||
Stefan Herdler).
|
Stefan Herdler).
|
||||||
@ -9916,3 +9916,5 @@ Video Disk Recorder Revision History
|
|||||||
transponder.
|
transponder.
|
||||||
- If the current channel is no longer available because of a VPS timer entering the
|
- If the current channel is no longer available because of a VPS timer entering the
|
||||||
VPS margin, live view now switches to the channel of that timer.
|
VPS margin, live view now switches to the channel of that timer.
|
||||||
|
- A device is now always kept occupied if a timer is in VPS margin or needs the
|
||||||
|
transponder (thanks to Markus Ehrnsperger).
|
||||||
|
41
device.c
41
device.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.c 5.12 2024/03/28 13:02:42 kls Exp $
|
* $Id: device.c 5.13 2024/03/29 21:46:50 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -95,7 +95,9 @@ cDevice::cDevice(void)
|
|||||||
|
|
||||||
camSlot = NULL;
|
camSlot = NULL;
|
||||||
|
|
||||||
|
occupiedFrom = 0;
|
||||||
occupiedTimeout = 0;
|
occupiedTimeout = 0;
|
||||||
|
occupiedPriority = MINPRIORITY;
|
||||||
|
|
||||||
player = NULL;
|
player = NULL;
|
||||||
isPlayingVideo = false;
|
isPlayingVideo = false;
|
||||||
@ -285,7 +287,11 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
|
|||||||
if (NumUsableSlots && !HasInternalCam && !CamSlots.Get(j)->Assign(device[i], true))
|
if (NumUsableSlots && !HasInternalCam && !CamSlots.Get(j)->Assign(device[i], true))
|
||||||
continue; // CAM slot can't be used with this device
|
continue; // CAM slot can't be used with this device
|
||||||
bool ndr = false;
|
bool ndr = false;
|
||||||
if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basically able to do the job
|
bool TunedToTransponder = device[i]->IsTunedToTransponder(Channel);
|
||||||
|
if (TunedToTransponder || device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basically able to do the job
|
||||||
|
bool OccupiedOtherTransponder = !TunedToTransponder && device[i]->Occupied();
|
||||||
|
if (OccupiedOtherTransponder)
|
||||||
|
ndr = true;
|
||||||
if (NumUsableSlots && !HasInternalCam) {
|
if (NumUsableSlots && !HasInternalCam) {
|
||||||
if (cCamSlot *csi = device[i]->CamSlot()) {
|
if (cCamSlot *csi = device[i]->CamSlot()) {
|
||||||
cCamSlot *csj = CamSlots.Get(j);
|
cCamSlot *csj = CamSlots.Get(j);
|
||||||
@ -303,7 +309,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
|
|||||||
imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
|
imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
|
||||||
imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
|
imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
|
||||||
imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->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[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->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[i]->Receiving(); // avoid devices that are receiving
|
imp <<= 1; imp |= device[i]->Receiving() || OccupiedOtherTransponder; // avoid devices that are receiving
|
||||||
imp <<= 5; imp |= GetClippedNumProvidedSystems(5, device[i]) - 1; // avoid cards which support multiple delivery systems
|
imp <<= 5; imp |= GetClippedNumProvidedSystems(5, device[i]) - 1; // avoid cards which support multiple delivery systems
|
||||||
imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
|
imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
|
||||||
imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
|
imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
|
||||||
@ -321,6 +327,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
|
|||||||
if (NumUsableSlots && !HasInternalCam)
|
if (NumUsableSlots && !HasInternalCam)
|
||||||
s = CamSlots.Get(j);
|
s = CamSlots.Get(j);
|
||||||
}
|
}
|
||||||
|
//dsyslog("device %d provides channel %d prio %d ndr %d imp %.8X", device[i]->DeviceNumber() + 1, Channel->Number(), Priority, ndr, imp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!NumUsableSlots)
|
if (!NumUsableSlots)
|
||||||
@ -427,7 +434,8 @@ cDevice *cDevice::GetDeviceForTransponder(const cChannel *Channel, int Priority)
|
|||||||
if (d->ProvidesTransponder(Channel)) {
|
if (d->ProvidesTransponder(Channel)) {
|
||||||
if (d->MaySwitchTransponder(Channel))
|
if (d->MaySwitchTransponder(Channel))
|
||||||
return d; // this device may switch to the transponder without disturbing any receiver or live view
|
return d; // this device may switch to the transponder without disturbing any receiver or live view
|
||||||
else if (!d->Occupied() && !d->IsBonded()) { // MaySwitchTransponder() implicitly calls Occupied()
|
else if (!d->Occupied(Priority) && !d->IsBonded() && d->Priority(true) < LIVEPRIORITY) { // MaySwitchTransponder() implicitly calls Occupied()
|
||||||
|
// we select only devices with priority < LIVEPRIORITY, so device can be switched without impact on recordings or live viewing
|
||||||
if (d->Priority() < Priority && (!Device || d->Priority() < Device->Priority()))
|
if (d->Priority() < Priority && (!Device || d->Priority() < Device->Priority()))
|
||||||
Device = d; // use this one only if no other with less impact can be found
|
Device = d; // use this one only if no other with less impact can be found
|
||||||
}
|
}
|
||||||
@ -801,7 +809,7 @@ bool cDevice::IsTunedToTransponder(const cChannel *Channel) const
|
|||||||
|
|
||||||
bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
|
bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
|
||||||
{
|
{
|
||||||
return time(NULL) > occupiedTimeout && !Receiving() && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);
|
return !Occupied() && !Receiving() && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
|
bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
|
||||||
@ -959,16 +967,27 @@ void cDevice::ForceTransferMode(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::Occupied(void) const
|
int cDevice::Occupied(int Priority) const
|
||||||
{
|
{
|
||||||
|
if (Priority > occupiedPriority)
|
||||||
|
return 0;
|
||||||
int Seconds = occupiedTimeout - time(NULL);
|
int Seconds = occupiedTimeout - time(NULL);
|
||||||
return Seconds > 0 ? Seconds : 0;
|
return Seconds > 0 ? Seconds : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDevice::SetOccupied(int Seconds)
|
void cDevice::SetOccupied(int Seconds, int Priority, time_t From)
|
||||||
{
|
{
|
||||||
if (Seconds >= 0)
|
if (Seconds < 0)
|
||||||
occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT);
|
return;
|
||||||
|
if (From == 0)
|
||||||
|
From = time(NULL);
|
||||||
|
if (From == occupiedFrom)
|
||||||
|
occupiedPriority = max(Priority, occupiedPriority);
|
||||||
|
else {
|
||||||
|
occupiedPriority = Priority;
|
||||||
|
occupiedFrom = From;
|
||||||
|
}
|
||||||
|
occupiedTimeout = From + min(Seconds, MAXOCCUPIEDTIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
||||||
@ -1660,11 +1679,13 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
|
|||||||
return Played;
|
return Played;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::Priority(void) const
|
int cDevice::Priority(bool IgnoreOccupied) const
|
||||||
{
|
{
|
||||||
int priority = IDLEPRIORITY;
|
int priority = IDLEPRIORITY;
|
||||||
if (IsPrimaryDevice() && !Replaying() && HasProgramme())
|
if (IsPrimaryDevice() && !Replaying() && HasProgramme())
|
||||||
priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
|
priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
|
||||||
|
if (!IgnoreOccupied && time(NULL) <= occupiedTimeout && occupiedPriority > priority)
|
||||||
|
priority = occupiedPriority - 1; // so timers with occupiedPriority can start
|
||||||
cMutexLock MutexLock(&mutexReceiver);
|
cMutexLock MutexLock(&mutexReceiver);
|
||||||
for (int i = 0; i < MAXRECEIVERS; i++) {
|
for (int i = 0; i < MAXRECEIVERS; i++) {
|
||||||
if (receiver[i])
|
if (receiver[i])
|
||||||
|
21
device.h
21
device.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.h 5.3 2024/01/22 12:10:30 kls Exp $
|
* $Id: device.h 5.4 2024/03/29 21:46:50 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
@ -178,6 +178,9 @@ public:
|
|||||||
///< the transponder of the given Channel, without disturbing any receiver
|
///< the transponder of the given Channel, without disturbing any receiver
|
||||||
///< at priorities higher or equal to Priority.
|
///< at priorities higher or equal to Priority.
|
||||||
///< If no such device is currently available, NULL will be returned.
|
///< If no such device is currently available, NULL will be returned.
|
||||||
|
///< Devices recording (Device->Priority(true) >= LIVEPRIORITY) will not be returned,
|
||||||
|
///< even if Priority >= LIVEPRIORITY. Such higher priorities are only used to
|
||||||
|
///< override occupied.
|
||||||
static void Shutdown(void);
|
static void Shutdown(void);
|
||||||
///< Closes down all devices.
|
///< Closes down all devices.
|
||||||
///< Must be called at the end of the program.
|
///< Must be called at the end of the program.
|
||||||
@ -259,7 +262,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
mutable cMutex mutexChannel;
|
mutable cMutex mutexChannel;
|
||||||
|
time_t occupiedFrom;
|
||||||
time_t occupiedTimeout;
|
time_t occupiedTimeout;
|
||||||
|
int occupiedPriority;
|
||||||
protected:
|
protected:
|
||||||
static int currentChannel;
|
static int currentChannel;
|
||||||
public:
|
public:
|
||||||
@ -369,9 +374,10 @@ public:
|
|||||||
///< channel number while replaying.
|
///< channel number while replaying.
|
||||||
void ForceTransferMode(void);
|
void ForceTransferMode(void);
|
||||||
///< Forces the device into transfermode for the current channel.
|
///< Forces the device into transfermode for the current channel.
|
||||||
int Occupied(void) const;
|
int Occupied(int Priority = MINPRIORITY) const;
|
||||||
///< Returns the number of seconds this device is still occupied for.
|
///< Returns the number of seconds this device is still occupied for
|
||||||
void SetOccupied(int Seconds);
|
///< with a priority >= Priority.
|
||||||
|
void SetOccupied(int Seconds, int Priority = MINPRIORITY, time_t From = 0);
|
||||||
///< Sets the occupied timeout for this device to the given number of
|
///< Sets the occupied timeout for this device to the given number of
|
||||||
///< Seconds, This can be used to tune a device to a particular transponder
|
///< Seconds, This can be used to tune a device to a particular transponder
|
||||||
///< and make sure it will stay there for a certain amount of time, for
|
///< and make sure it will stay there for a certain amount of time, for
|
||||||
@ -379,6 +385,10 @@ public:
|
|||||||
///< after the device has been successfully tuned to the requested transponder.
|
///< after the device has been successfully tuned to the requested transponder.
|
||||||
///< Seconds will be silently limited to MAXOCCUPIEDTIMEOUT. Values less than
|
///< Seconds will be silently limited to MAXOCCUPIEDTIMEOUT. Values less than
|
||||||
///< 0 will be silently ignored.
|
///< 0 will be silently ignored.
|
||||||
|
///< The timeout is counted from the given From time (by default the current time).
|
||||||
|
///< Calling this function several times with the same From time will set the
|
||||||
|
///< priority to the maximum of the given values.
|
||||||
|
///< Priority() may return a value >= Priority until the timeout.
|
||||||
virtual bool HasLock(int TimeoutMs = 0) const;
|
virtual bool HasLock(int TimeoutMs = 0) const;
|
||||||
///< Returns true if the device has a lock on the requested transponder.
|
///< Returns true if the device has a lock on the requested transponder.
|
||||||
///< Default is true, a specific device implementation may return false
|
///< Default is true, a specific device implementation may return false
|
||||||
@ -833,9 +843,10 @@ private:
|
|||||||
mutable cMutex mutexReceiver;
|
mutable cMutex mutexReceiver;
|
||||||
cReceiver *receiver[MAXRECEIVERS];
|
cReceiver *receiver[MAXRECEIVERS];
|
||||||
public:
|
public:
|
||||||
int Priority(void) const;
|
int Priority(bool IgnoreOccupied = false) const;
|
||||||
///< Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),
|
///< Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),
|
||||||
///< or IDLEPRIORITY if no receiver is currently active.
|
///< or IDLEPRIORITY if no receiver is currently active.
|
||||||
|
///< If IgnoreOccupied is true, a priority set with SetOccupied() is ignored.
|
||||||
protected:
|
protected:
|
||||||
virtual bool OpenDvr(void);
|
virtual bool OpenDvr(void);
|
||||||
///< Opens the DVR of this device and prepares it to deliver a Transport
|
///< Opens the DVR of this device and prepares it to deliver a Transport
|
||||||
|
16
vdr.c
16
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.tvdr.de
|
* The project's page is at http://www.tvdr.de
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 5.15 2024/03/28 13:21:42 kls Exp $
|
* $Id: vdr.c 5.16 2024/03/29 21:46:50 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
#define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
|
#define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
|
||||||
#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
|
#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
|
||||||
#define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
|
#define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
|
||||||
#define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
|
#define TIMERCHECKDELTA 5 // seconds between checks for timers that need to see their channel
|
||||||
#define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
|
#define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
|
||||||
#define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
|
#define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
|
||||||
#define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
|
#define VPSLOOKAHEADTIME 24 // hours within which VPS timers will make sure their events are up to date
|
||||||
@ -1158,8 +1158,12 @@ int main(int argc, char *argv[])
|
|||||||
if (NeedsTransponder || InVpsMargin) {
|
if (NeedsTransponder || InVpsMargin) {
|
||||||
// Find a device that provides the required transponder:
|
// Find a device that provides the required transponder:
|
||||||
cDevice *Device = cDevice::GetDeviceForTransponder(Timer->Channel(), MINPRIORITY);
|
cDevice *Device = cDevice::GetDeviceForTransponder(Timer->Channel(), MINPRIORITY);
|
||||||
if (!Device && InVpsMargin)
|
if (InVpsMargin) {
|
||||||
Device = cDevice::GetDeviceForTransponder(Timer->Channel(), LIVEPRIORITY);
|
if (!Device)
|
||||||
|
Device = cDevice::GetDeviceForTransponder(Timer->Channel(), Timer->Priority() );
|
||||||
|
if (!Device)
|
||||||
|
Device = cDevice::GetDevice(Timer->Channel(), Timer->Priority(), false, false);
|
||||||
|
}
|
||||||
// Switch the device to the transponder:
|
// Switch the device to the transponder:
|
||||||
if (Device) {
|
if (Device) {
|
||||||
bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
|
bool HadProgramme = cDevice::PrimaryDevice()->HasProgramme();
|
||||||
@ -1167,9 +1171,9 @@ int main(int argc, char *argv[])
|
|||||||
if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
|
if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
|
||||||
cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
|
cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
|
||||||
dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
|
dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
|
||||||
if (Device->SwitchChannel(Timer->Channel(), false))
|
Device->SwitchChannel(Timer->Channel(), false);
|
||||||
Device->SetOccupied(TIMERDEVICETIMEOUT);
|
|
||||||
}
|
}
|
||||||
|
Device->SetOccupied(TIMERDEVICETIMEOUT, InVpsMargin ? Timer->Priority() : MINPRIORITY, Now);
|
||||||
if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme()) {
|
if (cDevice::PrimaryDevice()->HasDecoder() && HadProgramme && !cDevice::PrimaryDevice()->HasProgramme()) {
|
||||||
LastTimerChannel = Timer->Channel()->Number();
|
LastTimerChannel = Timer->Channel()->Number();
|
||||||
Skins.QueueMessage(mtInfo, tr("Upcoming recording!")); // the previous SwitchChannel() has switched away the current live channel
|
Skins.QueueMessage(mtInfo, tr("Upcoming recording!")); // the previous SwitchChannel() has switched away the current live channel
|
||||||
|
Loading…
x
Reference in New Issue
Block a user