bool cVNSIChannelFilter::PassFilter(const cChannel &channel) { cMutexLock lock(&m_Mutex); if(channel.GroupSep()) return true; if (!IsWhitelist(channel)) return false; std::vector<int>::iterator it; if (IsRadio(&channel)) { it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel)); if(it!=m_channelsRadio.end()) return false; } else { it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel)); if(it!=m_channelsVideo.end()) return false; } return true; }
cLiveStreamer::cLiveStreamer(cXVDRClient* parent, const cChannel *channel, int priority) : cThread("cLiveStreamer stream processor") , cRingBufferLinear(MEGABYTE(10), TS_SIZE * 2, true) , cReceiver(NULL, priority) , m_scanTimeout(10) , m_parent(parent) { m_Device = NULL; m_Queue = NULL; m_startup = true; m_SignalLost = false; m_LangStreamType = cStreamInfo::stMPEG2AUDIO; m_LanguageIndex = -1; m_uid = CreateChannelUID(channel); m_ready = false; m_protocolVersion = XVDR_PROTOCOLVERSION; m_waitforiframe = false; m_PatFilter = NULL; m_requestStreamChange = false; if(m_scanTimeout == 0) m_scanTimeout = XVDRServerConfig.stream_timeout; // create send queue m_Queue = new cLiveQueue(m_parent->GetSocket()); m_Queue->Start(); SetTimeouts(0, 10); Start(); }
void cLiveStreamer::ChannelChange(const cChannel* channel) { cMutexLock lock(&m_FilterMutex); if(CreateChannelUID(channel) != m_uid || !Running()) { return; } INFOLOG("ChannelChange()"); SwitchChannel(channel); }
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { if (Pid == 0x00 && Tid == 0x00) { SI::PAT pat(Data, false); if (!pat.CheckCRCAndParse()) return; SI::PAT::Association assoc; for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { if (!assoc.isNITPid()) { XVDRChannels.Lock(false); const cChannel *Channel = XVDRChannels.Get()->GetByServiceID(Source(), Transponder(), assoc.getServiceId()); if (Channel && (Channel == m_Channel)) { int prevPmtPid = m_pmtPid; if (0 != (m_pmtPid = assoc.getPid())) { m_pmtSid = assoc.getServiceId(); if (m_pmtPid != prevPmtPid) { Add(m_pmtPid, 0x02); m_pmtVersion = -1; } XVDRChannels.Unlock(); return; } } XVDRChannels.Unlock(); } } } else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) { SI::PMT pmt(Data, false); if (!pmt.CheckCRCAndParse() || pmt.getServiceId() != m_pmtSid) return; if (m_pmtVersion != -1) { if (m_pmtVersion != pmt.getVersionNumber()) { cFilter::Del(m_pmtPid, 0x02); m_pmtPid = 0; // this triggers PAT scan } return; } m_pmtVersion = pmt.getVersionNumber(); // get cached channel data if(m_ChannelCache.size() == 0) m_ChannelCache = cChannelCache::GetFromCache(CreateChannelUID(m_Channel)); // get all streams and check if there are new (currently unknown) streams SI::PMT::Stream stream; cChannelCache cache; for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) { cStreamInfo info; if (GetStreamInfo(stream, info) && cache.size() < MAXRECEIVEPIDS) { info.SetContent(); cache.AddStream(info); } } // no new streams found -> exit if (m_ChannelCache.ismetaof(cache)) return; m_Streamer->m_FilterMutex.Lock(); // create new stream demuxers m_Streamer->Detach(); cache.CreateDemuxers(m_Streamer); m_Streamer->m_ready = false; INFOLOG("Currently unknown new streams found, requesting stream change"); m_Streamer->RequestStreamChange(); // write changed data back to the cache m_ChannelCache = cache; cChannelCache::AddToCache(CreateChannelUID(m_Channel), m_ChannelCache); // try to attach receiver int c = 0; for(; c < 3 && !m_Streamer->Attach(); c++) { INFOLOG("Unable to attach receiver, retrying ..."); usleep(100 * 1000); } // unable to attach receiver if(c == 3) { ERRORLOG("failed to attach receiver, sending detach ..."); m_Streamer->sendDetach(); } m_Streamer->m_FilterMutex.Unlock(); } }
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) { if (Pid == 0x00 && Tid == 0x00) { SI::PAT pat(Data, false); if (!pat.CheckCRCAndParse()) return; SI::PAT::Association assoc; for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { if (!assoc.isNITPid()) { const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId()); if (Channel && (Channel == m_Channel)) { int prevPmtPid = m_pmtPid; if (0 != (m_pmtPid = assoc.getPid())) { m_pmtSid = assoc.getServiceId(); if (m_pmtPid != prevPmtPid) { Add(m_pmtPid, 0x02); m_pmtVersion = -1; } return; } } } } } else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) { SI::PMT pmt(Data, false); if (!pmt.CheckCRCAndParse() || pmt.getServiceId() != m_pmtSid) return; if (m_pmtVersion != -1) { if (m_pmtVersion != pmt.getVersionNumber()) { cFilter::Del(m_pmtPid, 0x02); m_pmtPid = 0; // this triggers PAT scan } return; } m_pmtVersion = pmt.getVersionNumber(); // get cached channel data if(m_ChannelCache.size() == 0) m_ChannelCache = cChannelCache::GetFromCache(CreateChannelUID(m_Channel)); // get all streams and check if there are new (currently unknown) streams SI::PMT::Stream stream; cChannelCache cache; for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) { struct StreamInfo info; if (GetStreamInfo(stream, info) && cache.size() < MAXRECEIVEPIDS) cache.AddStream(info); } // no new streams found -> exit if (cache == m_ChannelCache) return; m_Streamer->m_FilterMutex.Lock(); // create new stream demuxers cache.CreateDemuxers(m_Streamer); INFOLOG("Currently unknown new streams found, requesting stream change"); // write changed data back to the cache m_ChannelCache = cache; cChannelCache::AddToCache(CreateChannelUID(m_Channel), m_ChannelCache); m_Streamer->RequestStreamChange(); m_Streamer->m_FilterMutex.Unlock(); } }
int cLiveStreamer::SwitchChannel(const cChannel *channel) { if (channel == NULL) { return XVDR_RET_ERROR; } if(m_PatFilter != NULL && m_Device != NULL) { m_Device->Detach(m_PatFilter); delete m_PatFilter; m_PatFilter = NULL; } if(IsAttached()) { Detach(); } // check if any device is able to decrypt the channel - code taken from VDR int NumUsableSlots = 0; if (channel->Ca() >= CA_ENCRYPTED_MIN) { for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) { if (CamSlot->ModuleStatus() == msReady) { if (CamSlot->ProvidesCa(channel->Caids())) { if (!ChannelCamRelations.CamChecked(channel->GetChannelID(), CamSlot->SlotNumber())) { NumUsableSlots++; } } } } if (!NumUsableSlots) { return XVDR_RET_ENCRYPTED; } } // get device for this channel { cMutexLock lock(&m_DeviceMutex); m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, false); } if (m_Device == NULL) { // return status "recording running" if there is an active timer time_t now = time(NULL); for (cTimer *ti = Timers.First(); ti; ti = Timers.Next(ti)) { if (ti->Recording() && ti->Matches(now)) { return XVDR_RET_RECRUNNING; } } return XVDR_RET_DATALOCKED; } INFOLOG("Found available device %d", m_Device->DeviceNumber() + 1); if (!m_Device->SwitchChannel(channel, false)) { ERRORLOG("Can't switch to channel %i - %s", channel->Number(), channel->Name()); return XVDR_RET_ERROR; } // get cached demuxer data cChannelCache cache = cChannelCache::GetFromCache(m_uid); // channel not found in cache -> add it from vdr if(cache.size() == 0) { INFOLOG("adding channel to cache"); cChannelCache::AddToCache(channel); cache = cChannelCache::GetFromCache(m_uid); } // channel already in cache else { INFOLOG("Channel information found in cache"); } // recheck cache item if(cache.size() != 0) { INFOLOG("Creating demuxers"); cache.CreateDemuxers(this); } RequestStreamChange(); INFOLOG("Successfully switched to channel %i - %s", channel->Number(), channel->Name()); if(m_waitforiframe) { INFOLOG("Will wait for first I-Frame ..."); } // clear cached data Clear(); m_Queue->Cleanup(); m_uid = CreateChannelUID(channel); if(!Attach()) { INFOLOG("Unable to attach receiver !"); return XVDR_RET_DATALOCKED; } INFOLOG("Starting PAT scanner"); m_PatFilter = new cLivePatFilter(this); m_PatFilter->SetChannel(channel); m_Device->AttachFilter(m_PatFilter); INFOLOG("done switching."); return XVDR_RET_OK; }
int cLiveStreamer::StreamChannel(const cChannel *channel, int sock, bool waitforiframe) { if (channel == NULL) { ERRORLOG("Starting streaming of channel without valid channel"); return XVDR_RET_ERROR; } m_uid = CreateChannelUID(channel); m_waitforiframe = waitforiframe; if(m_waitforiframe) { INFOLOG("Will wait for first I-Frame ..."); } // check if any device is able to decrypt the channel - code taken from VDR int NumUsableSlots = 0; if (channel->Ca() >= CA_ENCRYPTED_MIN) { for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) { if (CamSlot->ModuleStatus() == msReady) { if (CamSlot->ProvidesCa(channel->Caids())) { if (!ChannelCamRelations.CamChecked(channel->GetChannelID(), CamSlot->SlotNumber())) { NumUsableSlots++; } } } } if (!NumUsableSlots) { ERRORLOG("Unable to decrypt channel %i - %s", channel->Number(), channel->Name()); return XVDR_RET_ENCRYPTED; } } // get device for this channel m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, true); // try a bit harder if we can't find a device if(m_Device == NULL) m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, false); INFOLOG("--------------------------------------"); INFOLOG("Channel streaming request: %i - %s", channel->Number(), channel->Name()); if (m_Device == NULL) { ERRORLOG("Can't get device for channel %i - %s", channel->Number(), channel->Name()); // return status "recording running" if there is an active timer time_t now = time(NULL); if(Timers.GetMatch(now) != NULL) return XVDR_RET_RECRUNNING; return XVDR_RET_DATALOCKED; } INFOLOG("Found available device %d", m_Device->DeviceNumber() + 1); if (!m_Device->SwitchChannel(channel, false)) { ERRORLOG("Can't switch to channel %i - %s", channel->Number(), channel->Name()); return XVDR_RET_ERROR; } // create send queue if (m_Queue == NULL) { m_Queue = new cLiveQueue(sock); m_Queue->Start(); } m_PatFilter = new cLivePatFilter(this, channel); // get cached demuxer data cChannelCache cache = cChannelCache::GetFromCache(m_uid); // channel not found in cache -> add it from vdr if(cache.size() == 0) { INFOLOG("adding channel to cache"); cChannelCache::AddToCache(channel); cache = cChannelCache::GetFromCache(m_uid); } // channel already in cache else { INFOLOG("Channel information found in cache"); } // recheck cache item if(cache.size() != 0) { INFOLOG("Creating demuxers"); cache.CreateDemuxers(this); } if(!Attach()) { INFOLOG("Unable to attach receiver !"); return XVDR_RET_DATALOCKED; } RequestStreamChange(); DEBUGLOG("Starting PAT scanner"); m_Device->AttachFilter(m_PatFilter); INFOLOG("Successfully switched to channel %i - %s", channel->Number(), channel->Name()); Start(); return XVDR_RET_OK; }