[PATCH] Priority of transfer-mode should not be -1

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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:
>>> 1. The above patch with only the Receiving() change.
>>> 2. 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())
> +      return true;
>    for (int i = 0; i < MAXRECEIVERS; i++) {
>        if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count
>           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


[Index of Archives]     [Linux Media]     [Asterisk]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Big List of Linux Books]     [Fedora Users]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux