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)
This commit is contained in:
Frank Schmirler 2013-11-01 15:33:19 +01:00
parent 458a21a62a
commit 1d4a7e06b4
7 changed files with 39 additions and 19 deletions

View File

@ -223,4 +223,5 @@ hivdr
for suggesting to add the HTTP "Server" header
hummel99
for helping to debug channel switch issues with priority > 0
for reporting and helping to debug channel switch issues with priority > 0
for reporting a race condition when switching the server's LiveTV device

View File

@ -1,7 +1,10 @@
VDR Plugin 'streamdev' Revision History
---------------------------------------
- Fixed channel switch issues with priority > 0
- 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)
- Fixed channel switch issues with priority > 0 (reported by hummel99)
- Removed noisy debug messages
- Fixed HTTP menu destruction
- API change of VDR 2.1.2

View File

@ -14,6 +14,11 @@
#include <stdarg.h>
#include <errno.h>
// device occupied timeout to prevent VDR main loop to immediately switch back
// when streamdev switched the live TV channel.
// Note that there is still a gap between the GetDevice() and SetOccupied()
// calls where the VDR main loop could strike
#define STREAMDEVTUNETIMEOUT 5
cServerConnection::cServerConnection(const char *Protocol, int Type):
cTBSocket(Type),
@ -23,6 +28,7 @@ cServerConnection::cServerConnection(const char *Protocol, int Type):
m_ReadBytes(0),
m_WriteBytes(0),
m_WriteIndex(0),
m_OccupiedDev(NULL),
m_SwitchTo(NULL)
{
}
@ -204,7 +210,7 @@ bool cServerConnection::UsedByLiveTV(cDevice *device)
(device->IsPrimaryDevice() && device->HasDecoder() && !device->Replaying());
}
cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
cDevice *cServerConnection::SwitchDevice(const cChannel *Channel, int Priority)
{
// turn off the streams of this connection
Detach();
@ -216,8 +222,22 @@ cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
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;
// make sure VDR main loop doesn't switch back
device->SetOccupied(STREAMDEVTUNETIMEOUT);
if (device->SwitchChannel(Channel, false)) {
// switched away live TV
m_OccupiedDev = device;
m_SwitchTo = Channel;
}
else {
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());
device->SetOccupied(0);
device = NULL;
}
}
else if (!device->SwitchChannel(Channel, false)) {
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());
device = NULL;
}
return device;
}
@ -240,6 +260,7 @@ void cServerConnection::MainThreadHook()
Channels.SwitchTo(m_SwitchTo->Number());
Skins.Message(mtInfo, tr("Streaming active"));
}
m_OccupiedDev->SetOccupied(0);
m_SwitchTo = NULL;
}
}

View File

@ -34,6 +34,8 @@ private:
uint m_WriteBytes;
uint m_WriteIndex;
/* Set to occupied device when live TV was interrupted */
cDevice *m_OccupiedDev;
/* Set to this connection's current channel when live TV was interrupted */
const cChannel *m_SwitchTo;
@ -106,10 +108,8 @@ public:
channel. This call has no side effects. */
static cDevice *CheckDevice(const cChannel *Channel, int Priority, bool LiveView, const cDevice *AvoidDevice = NULL);
/* Will retrieve an unused device for transmitting data. Receivers have
already been attached from the device if necessary. Use the returned
cDevice in a following call to StartTransfer */
cDevice *GetDevice(const cChannel *Channel, int Priority);
/* Find a suitable device and tune it to the requested channel. */
cDevice *SwitchDevice(const cChannel *Channel, int Priority);
/* Test if a call to GetDevice would return a usable device. */
bool ProvidesChannel(const cChannel *Channel, int Priority);

View File

@ -177,9 +177,8 @@ bool cConnectionHTTP::ProcessRequest(void)
else if (m_Channel != NULL) {
cDevice *device = NULL;
if (ProvidesChannel(m_Channel, StreamdevServerSetup.HTTPPriority))
device = GetDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
device = SwitchDevice(m_Channel, StreamdevServerSetup.HTTPPriority);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
cStreamdevLiveStreamer* liveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.HTTPPriority, this);
m_Streamer = liveStreamer;
if (liveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid[0] ? m_Apid : NULL, m_Dpid[0] ? m_Dpid : NULL)) {

View File

@ -44,9 +44,8 @@ void cConnectionIGMP::Welcome()
{
cDevice *device = NULL;
if (ProvidesChannel(m_Channel, StreamdevServerSetup.IGMPPriority))
device = GetDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
device = SwitchDevice(m_Channel, StreamdevServerSetup.IGMPPriority);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
m_LiveStreamer = new cStreamdevLiveStreamer(StreamdevServerSetup.IGMPPriority, this);
if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device);
@ -61,7 +60,7 @@ void cConnectionIGMP::Welcome()
}
}
else
esyslog("streamdev-server IGMP: GetDevice failed");
esyslog("streamdev-server IGMP: SwitchDevice failed");
}
bool cConnectionIGMP::Close()

View File

@ -1118,11 +1118,8 @@ bool cConnectionVTP::CmdTUNE(char *Opts)
if (!ProvidesChannel(chan, prio))
return Respond(560, "Channel not available (ProvidesChannel)");
}
if ((dev = GetDevice(chan, prio)) == NULL)
return Respond(560, "Channel not available (GetDevice)");
if (!dev->SwitchChannel(chan, false))
return Respond(560, "Channel not available (SwitchChannel)");
if ((dev = SwitchDevice(chan, prio)) == NULL)
return Respond(560, "Channel not available (SwitchDevice)");
delete m_LiveStreamer;
m_LiveStreamer = new cStreamdevLiveStreamer(prio, this);