Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[vdr] [PATCH] Possible fix for EPG scan ("video data stream broken")
Hi,
while debugging I noticed that when starting a recording while EPG
scan is active the following piece of code in method
cDvbDevice::SetChannelDevice prevents starting transfer mode (at
least on a single card system):
if (EITScanner.Active()) {
StartTransferMode = false;
TurnOnLivePIDs = false;
}
I think this causes the recording thread not receiving data for some
time (20sec ScanTimeout for EITScanner + some time for several
Channel switches incl. displaying "Channel not available"). This
amount of time can quite reach the timeout of 30sec in the recording
thread.
As workaround I inserted a call of EITScanner.Activity() in
cRecordControls::Start in before SwitchChannel is called.
In method cEITScanner::Activity I rearranged the assignments for
currentChannel and lastActivity. So EITScanner::Active immediatly
returns false.
Furthermore I made a small optimization at the beginning
cEITScanner::Process for single card setups. This prevents building
and deleting the scanlist every 20 secs when EPGScanTimeout is not
reached.
I will have to test this patch over night but up to then comments a
welcome. This patch contains also the cDvbTuner patch (timeout now
300ms) and some debugging messages.
Stefan
diff -Nru vdr-1.3.12/dvbdevice.c vdr-1.3.12-patched/dvbdevice.c
--- vdr-1.3.12/dvbdevice.c 2004-06-19 11:33:42.000000000 +0200
+++ vdr-1.3.12-patched/dvbdevice.c 2004-07-31 16:42:13.705232395 +0200
@@ -35,7 +35,6 @@
#define DO_REC_AND_PLAY_ON_PRIMARY_DEVICE 1
#define DO_MULTIPLE_RECORDINGS 1
-//#define WAIT_FOR_LOCK_AFTER_TUNING 1
#define DEV_VIDEO "/dev/video"
#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
@@ -80,6 +79,7 @@
eTunerStatus tunerStatus;
cMutex mutex;
cCondVar newSet;
+ cCondVar evLocked;
bool SetFrontend(void);
virtual void Action(void);
public:
@@ -132,6 +132,8 @@
startTime = time(NULL);
channel = *Channel;
newSet.Broadcast();
+ if (tunerStatus < tsLocked)
+ evLocked.TimedWait(mutex, 6000);
}
static unsigned int FrequencyToHz(unsigned int f)
@@ -241,6 +243,15 @@
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
return false;
}
+
+ /* discard stale events */
+ dvb_frontend_event event;
+ while (1)
+ {
+ if (ioctl(fd_frontend, FE_GET_EVENT, &event) == -1)
+ break;
+ }
+
if (ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend) < 0) {
esyslog("ERROR: frontend %d: %m", cardIndex);
return false;
@@ -248,6 +259,7 @@
return true;
}
+
void cDvbTuner::Action(void)
{
active = true;
@@ -256,19 +268,28 @@
if (tunerStatus == tsSet)
tunerStatus = SetFrontend() ? tsTuned : tsIdle;
if (tunerStatus == tsTuned) {
- fe_status_t status = fe_status_t(0);
- CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
- if (status & FE_HAS_LOCK)
- tunerStatus = tsLocked;
+ pollfd pfd;
+ pfd.fd = fd_frontend;
+ pfd.events = POLLIN | POLLPRI;
+ int rc = poll(&pfd, 1, 5000);
+ if (rc == 0)
+ isyslog("WARNING: frontend %d poll timed out!", cardIndex + 1);
+ else if (rc == -1)
+ esyslog("ERROR: frontend %d poll failed - errno %d!", cardIndex + 1, errno);
}
if (tunerStatus != tsIdle) {
dvb_frontend_event event;
- if (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
+ while (ioctl(fd_frontend, FE_GET_EVENT, &event) == 0) {
if (event.status & FE_REINIT) {
tunerStatus = tsSet;
- esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex);
+ esyslog("ERROR: frontend %d was reinitialized - re-tuning", cardIndex + 1);
continue;
}
+ if ((tunerStatus == tsTuned) && (event.status & FE_HAS_LOCK)) {
+ usleep(300*1000);
+ tunerStatus = tsLocked;
+ evLocked.Broadcast();
+ }
}
}
if (ciHandler) {
@@ -293,7 +314,8 @@
tunerStatus = tsLocked;
}
// in the beginning we loop more often to let the CAM connection start up fast
- newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
+ if (tunerStatus != tsTuned)
+ newSet.TimedWait(mutex, (ciHandler && (time(NULL) - startTime < 20)) ? 100 : 1000);
}
}
@@ -709,6 +731,8 @@
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
+ dsyslog("SetChannelDevice: Channel %s, LiveView %s", Channel->Name(), LiveView ? "true" : "false");
+
bool IsEncrypted = Channel->Ca() > CACONFBASE && !ciHandler; // only LL-firmware can do non-live CA channels
bool DoTune = !dvbTuner->IsTunedTo(Channel);
@@ -738,6 +762,7 @@
// XXX 1.3: use the same mechanism as below (!EITScanner.UsesDevice(this))
if (EITScanner.Active()) {
+ dsyslog("EITScanner is active");
StartTransferMode = false;
TurnOnLivePIDs = false;
}
@@ -748,13 +773,12 @@
TurnOffLiveMode();
dvbTuner->Set(Channel, DoTune, !EITScanner.UsesDevice(this)); //XXX 1.3: this is an ugly hack - find a cleaner solution//XXX
-
-#ifdef WAIT_FOR_LOCK_AFTER_TUNING
- //XXX TODO preliminary fix for the "Unknown picture type" error
- time_t t0 = time(NULL);
- while (!dvbTuner->Locked() && time(NULL) - t0 < 5)
- usleep(100);
-#endif
+
+ if (!dvbTuner->Locked()) {
+ esyslog("ERROR: failed to tune to channel %d \"%s\"", Channel->Number(), Channel->Name());
+ return false;
+ }
+
// PID settings:
if (TurnOnLivePIDs) {
diff -Nru vdr-1.3.12/eitscan.c vdr-1.3.12-patched/eitscan.c
--- vdr-1.3.12/eitscan.c 2004-04-16 15:33:34.000000000 +0200
+++ vdr-1.3.12-patched/eitscan.c 2004-07-31 16:41:03.044258645 +0200
@@ -114,20 +114,26 @@
void cEITScanner::Activity(void)
{
+ dsyslog("cEITScanner::Activity called");
+ lastActivity = time(NULL);
if (currentChannel) {
- Channels.SwitchTo(currentChannel);
+ int Channel = currentChannel;
currentChannel = 0;
+ Channels.SwitchTo(Channel);
}
- lastActivity = time(NULL);
}
void cEITScanner::Process(void)
{
+ time_t now = time(NULL);
+ if (!scanList && lastActivity && cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity < Setup.EPGScanTimeout * 3600)
+ return;
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
- time_t now = time(NULL);
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
+ dsyslog("cEITScanner::Process: start processing");
if (Channels.Lock(false, 10)) {
if (!scanList) {
+ dsyslog("cEITScanner::Process: create new scanlist");
scanList = new cScanList;
scanList->AddTransponders(&Channels);
if (transponderList) {
@@ -136,6 +142,7 @@
transponderList = NULL;
}
}
+ dsyslog("cEITScanner::Process: scanlist contains %d entries", scanList->Count());
for (bool AnyDeviceSwitched = false; !AnyDeviceSwitched; ) {
cScanData *ScanData = NULL;
for (int i = 0; i < cDevice::NumDevices(); i++) {
@@ -171,6 +178,7 @@
ScanData = NULL;
}
if (!scanList->Count()) {
+ dsyslog("cEITScanner::Process: scanlist is now empty");
delete scanList;
scanList = NULL;
if (lastActivity == 0) // this was a triggered scan
diff -Nru vdr-1.3.12/menu.c vdr-1.3.12-patched/menu.c
--- vdr-1.3.12/menu.c 2004-06-13 22:26:51.000000000 +0200
+++ vdr-1.3.12-patched/menu.c 2004-07-31 15:46:25.110509999 +0200
@@ -2861,6 +2861,7 @@
if (device == cTransferControl::ReceiverDevice())
cControl::Shutdown(); // in case this device was used for Transfer Mode
}
+ EITScanner.Activity();
dsyslog("switching device %d to channel %d", device->DeviceNumber() + 1, channel->Number());
if (!device->SwitchChannel(channel, false)) {
cThread::EmergencyExit(true);
Home |
Main Index |
Thread Index