Anssi Hannula wrote:
Klaus Schmidinger wrote:
Anssi Hannula wrote:
Klaus Schmidinger wrote:
Anssi Hannula wrote:
Klaus Schmidinger wrote:
I'm afraid this patch has a nasty side effect.
Asssume the following scenario:
- two devices, primary is 1
- all channels are available on both devices, except for channels 10, 11 and 12 which can only be received by device 2
- channels 10 and 11 are on the same transponder, channel 12 is on a
different one
- switch directly to channel 10 -> transfer mode starts
- press "Up" to switch to channel 11, but that channel is skipped and it switches to channel 12
So I guess I can't accept this patch.
Thank you for taking a look.
However, I don't see why there is such a problem in the above scenario:
- let's consider PrimaryLimit is 0 (the default)
- SwitchChannel() gets called (device.c line 581)
- PrimaryDevice()->ProvidesChannel() returns false (line 591)
- GetDevice() is called (line 281)
- for the device 1 ProvidesChannel() returns false (line 288)
- ProvidesChannel() is called for device 2 (dvbdevice.c line 767)
- Priority = 0, this->Priority() = -1, so hasPriority = true
- ProvidesChannel() result = true is set in line 785
- ProvidesChannel() return true and ndr = false (device.c line 288)
- (device[i]->Receiving() && !ndr) evaluates true (line 290)
- pri = 0 so device 2 is selected
- SwitchChannel() calls another SwitchChannel (line 601)
- SwitchChannel() calls SetChannel (line 568)
- and so on
Hopefully I'll have time to test this scenario later today.
Well, just try it - it did behave here as described.
Well, I tried it in the following scenario:
- two devices, primary is 1
- all channels available on device 2 only
- channels 1 and 2 are on the same transponder, 3 and 4 on a different
one
- manually switch to channel 1
- press up -> vdr switches to 2
- up again -> vdr switches to 3
- up again -> vdr switches to 4
It works ok. Do you have PrimaryLimit != 0? As it turns out, there is indeed a bug in
Well, I normally have PrimaryLimit=0, but I've set it to 10 for testing. Sorry, forgot to mention that.
the patch which appears when PrimaryLimit is something else than 0 and affects the channelup & channeldown. If you do, try one of the following:
- The above patch with only the Receiving() change.
- The above patch fully and additionally Priority of GetDevice() call
in device.c line 591 changed from 0 to Setup.PrimaryLimit. 3. PrimaryLimit = 0
Sorry, it's late today - but see below, maybe this is all no longer a problem, anyway ;-)
It is, but hopefully not for long :)
Looking back at your original posting, I believe the actual problem that triggered all this was that streamdev would interrupt live viewing in Transfer Mode, right?
Yes.
Well, what if streamdev, when selecting the device to use, could avoid the ActualDevice()?
To test this (without modifying the cDevice API) you could introduce a
bool AvoidActualDevice = false;
right before
cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
and inside that function check that variable, and if it is true and the checked device is the ActualDevice(), continue the 'for' loop:
I think it would be much better to fix this bug (VDR doesn't prefer free devices over transfer-moded) rather than add this kind of workaround.
VDR does prefer free devices over ones used for Transfer Mode:
No, it doesn't, if the transfer-moded device is a budget card:
Device *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) { ... else if (!device[i]->Receiving() && !device[i]->HasDecoder()) pri = 2; // free and not a full featured card
This causes the device to be selected no matter if it is in transfer mode or not.
Ok, you're right about that.
It seems to me that the above "2" case and the below "3" case should be swapped.
However, Receiving() is supposed to be "Returns true if we are currently receiving." so I think it should still check for transfermode, as it is then definitely receiving. Then the "free and not the actual device" case could be dropped from GetDevice().
else if (!device[i]->Receiving() && device[i] != ActualDevice()) pri = 3; // free and not the actual device else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice()) pri = 4; // free and not the primary device
... }
Hmm, come to think of it: could it be that your original problem no longer exists since VDR 1.3.46?
2006-04-09: Version 1.3.46
...
- Now avoiding the 'actual' device when starting a recording, so that a
Transfer Mode for live tv isn't interrupted.
Nope, I'm running 1.4.0 and I also confirmed the problem still exists with vanilla VDR.
I've now attached two patches. One adds a check for transfer mode in Receiving() and drops the then-useless "free and not the actual device" case from GetDevice(). The other one is optional: it changes the effective transfer-mode receiver priority from fixed 0 to PrimaryLimit, so that the transfer-mode is also "protected" by PrimaryLimit.
diff -Nurp -x '*~' vdr-1.4.0/device.c vdr-1.4.0-fix2/device.c --- vdr-1.4.0/device.c 2006-04-14 17:34:43.000000000 +0300 +++ vdr-1.4.0-fix2/device.c 2006-05-14 01:10:25.000000000 +0300 @@ -293,18 +293,16 @@ cDevice *cDevice::GetDevice(const cChann pri = 1; // free and fewer Ca's else if (!device[i]->Receiving() && !device[i]->HasDecoder()) pri = 2; // free and not a full featured card
else if (!device[i]->Receiving() && device[i] != ActualDevice())
pri = 3; // free and not the actual device else if (!device[i]->Receiving() && !device[i]->IsPrimaryDevice())
pri = 4; // free and not the primary device
pri = 3; // free and not the primary device else if (!device[i]->Receiving())
pri = 5; // free
pri = 4; // free else if (d && device[i]->Priority() < d->Priority())
pri = 6; // receiving but priority is lower
pri = 5; // receiving but priority is lower else if (d && device[i]->Priority() == d->Priority() && device[i]->ProvidesCa(Channel) < d->ProvidesCa(Channel))
pri = 7; // receiving with same priority but fewer Ca's
pri = 6; // receiving with same priority but fewer Ca's else
pri = 8; // all others
pri = 7; // all others if (pri <= select) { select = pri; d = device[i];
@@ -1183,6 +1181,8 @@ int cDevice::ProvidesCa(const cChannel *
bool cDevice::Receiving(bool CheckAny) const {
- if (this == cTransferControl::ReceiverDevice())
for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count return true;return true;
diff -Nurp -x '*~' vdr-1.4.0/device.c vdr-1.4.0-fix/device.c --- vdr-1.4.0/device.c 2006-04-14 17:34:43.000000000 +0300 +++ vdr-1.4.0-fix/device.c 2006-05-14 01:06:32.000000000 +0300 @@ -588,7 +586,7 @@ bool cDevice::SwitchChannel(int Directio cChannel *channel; while ((channel = Channels.GetByNumber(n, Direction)) != NULL) { // try only channels which are currently available
if (PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit) || PrimaryDevice()->CanReplay() && GetDevice(channel, 0))
if (PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit) || PrimaryDevice()->CanReplay() && GetDevice(channel, Setup.PrimaryLimit)) break; n = channel->Number() + Direction; }
@@ -627,7 +625,7 @@ eSetChannelResult cDevice::SetChannel(co // use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) {
cDevice *CaDevice = GetDevice(Channel, 0, &NeedsDetachReceivers);
cDevice *CaDevice = GetDevice(Channel, Setup.PrimaryLimit, &NeedsDetachReceivers); if (CaDevice && CanReplay()) { cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel if (CaDevice->SetChannel(Channel, false) == scrOk) { // calling SetChannel() directly, not SwitchChannel()!
@@ -1158,7 +1156,7 @@ int cDevice::Ca(void) const
int cDevice::Priority(void) const {
- int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
- int priority = ActualDevice() == this ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY; for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i]) priority = max(receiver[i]->priority, priority);
I'll need to give this more thought - won't have time for it today.
Klaus