Skip to content

Commit 1d4a7e0

Browse files
author
Frank Schmirler
committed
Set device occupied when streamdev switches away LiveTV on the server, to
reduce the risk that the VDR main loop immediately switches back, resulting in a black screen on the client (reported by hummel99)
1 parent 458a21a commit 1d4a7e0

File tree

7 files changed

+39
-19
lines changed

7 files changed

+39
-19
lines changed

CONTRIBUTORS

+2-1
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,5 @@ hivdr
223223
for suggesting to add the HTTP "Server" header
224224

225225
hummel99
226-
for helping to debug channel switch issues with priority > 0
226+
for reporting and helping to debug channel switch issues with priority > 0
227+
for reporting a race condition when switching the server's LiveTV device

HISTORY

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
VDR Plugin 'streamdev' Revision History
22
---------------------------------------
33

4-
- Fixed channel switch issues with priority > 0
4+
- Set device occupied when streamdev switches away LiveTV on the server, to
5+
reduce the risk that the VDR main loop immediately switches back, resulting
6+
in a black screen on the client (reported by hummel99)
7+
- Fixed channel switch issues with priority > 0 (reported by hummel99)
58
- Removed noisy debug messages
69
- Fixed HTTP menu destruction
710
- API change of VDR 2.1.2

server/connection.c

+24-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
#include <stdarg.h>
1515
#include <errno.h>
1616

17+
// device occupied timeout to prevent VDR main loop to immediately switch back
18+
// when streamdev switched the live TV channel.
19+
// Note that there is still a gap between the GetDevice() and SetOccupied()
20+
// calls where the VDR main loop could strike
21+
#define STREAMDEVTUNETIMEOUT 5
1722

1823
cServerConnection::cServerConnection(const char *Protocol, int Type):
1924
cTBSocket(Type),
@@ -23,6 +28,7 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
2328
m_ReadBytes(0),
2429
m_WriteBytes(0),
2530
m_WriteIndex(0),
31+
m_OccupiedDev(NULL),
2632
m_SwitchTo(NULL)
2733
{
2834
}
@@ -204,7 +210,7 @@ bool cServerConnection::UsedByLiveTV(cDevice *device)
204210
(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
205211
}
206212

207-
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
213+
cDevice *cServerConnection::SwitchDevice(const cChannel *Channel, int Priority)
208214
{
209215
// turn off the streams of this connection
210216
Detach();
@@ -216,8 +222,22 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
216222
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());
217223
}
218224
else if (!device->IsTunedToTransponder(Channel) && UsedByLiveTV(device)) {
219-
// switched away live TV
220-
m_SwitchTo = Channel;
225+
// make sure VDR main loop doesn't switch back
226+
device->SetOccupied(STREAMDEVTUNETIMEOUT);
227+
if (device->SwitchChannel(Channel, false)) {
228+
// switched away live TV
229+
m_OccupiedDev = device;
230+
m_SwitchTo = Channel;
231+
}
232+
else {
233+
dsyslog("streamdev: SwitchChannel (live) failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
234+
device->SetOccupied(0);
235+
device = NULL;
236+
}
237+
}
238+
else if (!device->SwitchChannel(Channel, false)) {
239+
dsyslog("streamdev: SwitchChannel failed for channel %d (%s) at priority %d (PrimaryDevice=%d, ActualDevice=%d, device=%d)", Channel->Number(), Channel->Name(), Priority, cDevice::PrimaryDevice()->CardIndex(), cDevice::ActualDevice()->CardIndex(), device->CardIndex());
240+
device = NULL;
221241
}
222242
return device;
223243
}
@@ -240,6 +260,7 @@ void cServerConnection::MainThreadHook()
240260
Channels.SwitchTo(m_SwitchTo->Number());
241261
Skins.Message(mtInfo, tr("Streaming active"));
242262
}
263+
m_OccupiedDev->SetOccupied(0);
243264
m_SwitchTo = NULL;
244265
}
245266
}

server/connection.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class cServerConnection: public cListObject, public cTBSocket
3434
uint m_WriteBytes;
3535
uint m_WriteIndex;
3636

37+
/* Set to occupied device when live TV was interrupted */
38+
cDevice *m_OccupiedDev;
3739
/* Set to this connection's current channel when live TV was interrupted */
3840
const cChannel *m_SwitchTo;
3941

@@ -106,10 +108,8 @@ class cServerConnection: public cListObject, public cTBSocket
106108
channel. This call has no side effects. */
107109
static cDevice *CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice = NULL);
108110

109-
/* Will retrieve an unused device for transmitting data. Receivers have
110-
already been attached from the device if necessary. Use the returned
111-
cDevice in a following call to StartTransfer */
112-
cDevice *GetDevice(const cChannel *Channel, int Priority);
111+
/* Find a suitable device and tune it to the requested channel. */
112+
cDevice *SwitchDevice(const cChannel *Channel, int Priority);
113113

114114
/* Test if a call to GetDevice would return a usable device. */
115115
bool ProvidesChannel(const cChannel *Channel, int Priority);

server/connectionHTTP.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,8 @@ bool cConnectionHTTP::ProcessRequest(void)
177177
else if (m_Channel != NULL) {
178178
cDevice *device = NULL;
179179
if (ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority))
180-
device = GetDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
180+
device = SwitchDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
181181
if (device != NULL) {
182-
device->SwitchChannel(m_Channel, false);
183182
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.HTTPPriority, this);
184183
m_Streamer = liveStreamer;
185184
if (liveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {

server/connectionIGMP.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ void cConnectionIGMP::Welcome()
4444
{
4545
cDevice *device = NULL;
4646
if (ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority))
47-
device = GetDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
47+
device = SwitchDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
4848
if (device != NULL) {
49-
device->SwitchChannel(m_Channel, false);
5049
m_LiveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.IGMPPriority, this);
5150
if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType)) {
5251
m_LiveStreamer->SetDevice(device);
@@ -61,7 +60,7 @@ void cConnectionIGMP::Welcome()
6160
}
6261
}
6362
else
64-
esyslog("streamdev-server IGMP: GetDevice failed");
63+
esyslog("streamdev-server IGMP: SwitchDevice failed");
6564
}
6665

6766
bool cConnectionIGMP::Close()

server/connectionVTP.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -1118,11 +1118,8 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
11181118
if (!ProvidesChannel(chan, prio))
11191119
return Respond(560, "Channel not available (ProvidesChannel)");
11201120
}
1121-
if ((dev = GetDevice(chan, prio)) == NULL)
1122-
return Respond(560, "Channel not available (GetDevice)");
1123-
1124-
if (!dev->SwitchChannel(chan, false))
1125-
return Respond(560, "Channel not available (SwitchChannel)");
1121+
if ((dev = SwitchDevice(chan, prio)) == NULL)
1122+
return Respond(560, "Channel not available (SwitchDevice)");
11261123

11271124
delete m_LiveStreamer;
11281125
m_LiveStreamer = new cStreamdevLiveStreamer(prio, this);

0 commit comments

Comments
 (0)