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,40 +23,46 @@ 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))
device = GetDevice(Channel, 0);
if (device != NULL) {
device->SwitchChannel(Channel, false);
struct in_addr ip; struct in_addr ip;
ip.s_addr = Dst; ip.s_addr = Dst;
if (Connect(inet_ntoa(ip), m_ClientPort)) { if (Connect(inet_ntoa(ip), m_ClientPort))
return true;
else
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); m_LiveStreamer = new cStreamdevLiveStreamer(0, this);
if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) { if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType)) {
m_LiveStreamer->SetDevice(device); m_LiveStreamer->SetDevice(device);
if (!SetDSCP()) if (!SetDSCP())
LOG_ERROR_STR("unable to set DSCP sockopt"); LOG_ERROR_STR("unable to set DSCP sockopt");
Dprintf("streamer start\n"); Dprintf("streamer start\n");
m_LiveStreamer->Start(this); m_LiveStreamer->Start(this);
return true;
} }
else else {
esyslog("streamdev-server IGMP: SetDevice failed"); esyslog("streamdev-server IGMP: SetChannel failed");
DELETENULL(m_LiveStreamer); DELETENULL(m_LiveStreamer);
} }
else
esyslog("streamdev-server IGMP: Connect failed: %m");
} }
else else
esyslog("streamdev-server IGMP: GetDevice failed"); esyslog("streamdev-server IGMP: GetDevice failed");
} }
else
esyslog("streamdev-server IGMP: Channel not found");
return false;
}
void cConnectionIGMP::Stop() void cConnectionIGMP::Stop()
{ {

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 */