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 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 - streamdev-client returns true in its AvoidRecording() method introduced
with VDR 1.7.19. Note however that the impact of NumProvidedSystems is with VDR 1.7.19. Note however that the impact of NumProvidedSystems is
higher. higher.

View File

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

View File

@ -13,7 +13,8 @@ cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType S
cServerConnection(Name, SOCK_DGRAM), cServerConnection(Name, SOCK_DGRAM),
m_LiveStreamer(NULL), m_LiveStreamer(NULL),
m_ClientPort(ClientPort), m_ClientPort(ClientPort),
m_StreamType(StreamType) m_StreamType(StreamType),
m_Channel(NULL)
{ {
} }
@ -22,41 +23,47 @@ cConnectionIGMP::~cConnectionIGMP()
delete m_LiveStreamer; delete m_LiveStreamer;
} }
bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst) bool cConnectionIGMP::SetChannel(cChannel *Channel, in_addr_t Dst)
{ {
if (Channel != NULL) { if (Channel) {
cDevice *device = NULL; m_Channel = Channel;
if (ProvidesChannel(Channel, 0)) struct in_addr ip;
device = GetDevice(Channel, 0); ip.s_addr = Dst;
if (device != NULL) { if (Connect(inet_ntoa(ip), m_ClientPort))
device->SwitchChannel(Channel, false); return true;
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");
}
else else
esyslog("streamdev-server IGMP: GetDevice failed"); esyslog("streamdev-server IGMP: Connect failed: %m");
return false;
} }
else else
esyslog("streamdev-server IGMP: Channel not found"); esyslog("streamdev-server IGMP: Channel not found");
return false; 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() void cConnectionIGMP::Stop()
{ {
if (m_LiveStreamer) { if (m_LiveStreamer) {

View File

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