fixed regression of "live TV must be switched in VDR main thread" change:

deadlock in IGMP streaming server when switching live TV.

Previously cComponentIGMP::Accept did all the work including the channel
switch with the new cConnectionIGMP waiting for MainThreadHook. But as the
new connection is stored *after* Accept, MainThreadHook didn't see it and
so wasn't able to switch. The streamdev main thread waited forever.

Moved the main work into cComponentIGMP::Welcome.
This commit is contained in:
Frank Schmirler 2011-10-18 08:50:54 +02:00
parent 2fae067cfe
commit 615f101b9d
4 changed files with 41 additions and 30 deletions

View File

@ -1,6 +1,8 @@
VDR Plugin 'streamdev' Revision History
---------------------------------------
- fixed regression of "live TV must be switched in VDR main thread" change:
deadlock in IGMP streaming server when switching live TV.
- streamdev-client returns true in its AvoidRecording() method introduced
with VDR 1.7.19. Note however that the impact of NumProvidedSystems is
higher.

View File

@ -434,7 +434,7 @@ void cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group)
if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) {
cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN);
Group->connection = (cConnectionIGMP*) NewClient();
if (!Group->connection->Start(channel, Group->group)) {
if (!Group->connection->SetChannel(channel, Group->group)) {
DELETENULL(Group->connection);
}
}

View File

@ -13,7 +13,8 @@ cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType S
cServerConnection(Name, SOCK_DGRAM),
m_LiveStreamer(NULL),
m_ClientPort(ClientPort),
m_StreamType(StreamType)
m_StreamType(StreamType),
m_Channel(NULL)
{
}
@ -22,41 +23,47 @@ cConnectionIGMP::~cConnectionIGMP()
delete m_LiveStreamer;
}
bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
bool cConnectionIGMP::SetChannel(cChannel *Channel, in_addr_t Dst)
{
if (Channel != NULL) {
cDevice *device = NULL;
if (ProvidesChannel(Channel, 0))
device = GetDevice(Channel, 0);
if (device != NULL) {
device->SwitchChannel(Channel, false);
struct in_addr ip;
ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort)) {
m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
Dprintf("streamer start\n");
m_LiveStreamer->Start(this);
return true;
}
else
esyslog("streamdev-server IGMP: SetDevice failed");
DELETENULL(m_LiveStreamer);
}
else
esyslog("streamdev-server IGMP: Connect failed: %m");
}
if (Channel) {
m_Channel = Channel;
struct in_addr ip;
ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort))
return true;
else
esyslog("streamdev-server IGMP: GetDevice failed");
esyslog("streamdev-server IGMP: Connect failed: %m");
return false;
}
else
esyslog("streamdev-server IGMP: Channel not found");
return false;
}
void cConnectionIGMP::Welcome()
{
cDevice *device = NULL;
if (ProvidesChannel(m_Channel, 0))
device = GetDevice(m_Channel, 0);
if (device != NULL) {
device->SwitchChannel(m_Channel, false);
m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device);
if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt");
Dprintf("streamer start\n");
m_LiveStreamer->Start(this);
}
else {
esyslog("streamdev-server IGMP: SetChannel failed");
DELETENULL(m_LiveStreamer);
}
}
else
esyslog("streamdev-server IGMP: GetDevice failed");
}
void cConnectionIGMP::Stop()
{
if (m_LiveStreamer) {

View File

@ -20,12 +20,14 @@ private:
cStreamdevLiveStreamer *m_LiveStreamer;
int m_ClientPort;
eStreamType m_StreamType;
cChannel *m_Channel;
public:
cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType);
virtual ~cConnectionIGMP();
bool Start(cChannel *Channel, in_addr_t Dst);
bool SetChannel(cChannel *Channel, in_addr_t Dst);
virtual void Welcome(void);
void Stop();
/* Not used here */