diff --git a/device.c b/device.c index 9242f68..b6e5ee6 100644 --- a/device.c +++ b/device.c @@ -15,6 +15,8 @@ static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL }; +cMutex cSatipDevice::mutexS = cMutex(); + cSatipDevice::cSatipDevice(unsigned int indexP) : deviceIndexM(indexP), bytesDeliveredM(0), @@ -23,7 +25,7 @@ cSatipDevice::cSatipDevice(unsigned int indexP) deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), channelM(), createdM(0), - mutexM() + tunedM() { unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE; bufsize -= (bufsize % TS_SIZE); @@ -43,6 +45,8 @@ cSatipDevice::cSatipDevice(unsigned int indexP) cSatipDevice::~cSatipDevice() { debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); + // Release immediately any pending conditional wait + tunedM.Broadcast(); // Stop section handler StopSectionHandler(); DELETE_POINTER(pSectionFilterHandlerM); @@ -345,6 +349,7 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) { + cMutexLock MutexLock(&mutexS); // Global lock to prevent any simultaneous zapping debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM); if (channelP) { cDvbTransponderParameters dtp(channelP->Parameters()); @@ -362,6 +367,8 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) { channelM = *channelP; deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server)); + // Wait for actual channel tuning to prevent simultaneous frontend allocation failures + tunedM.TimedWait(mutexS, eTuningTimeoutMs); return true; } } @@ -373,6 +380,13 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) return false; } +void cSatipDevice::SetChannelTuned(void) +{ + debug9("%s () [device %u]", __PRETTY_FUNCTION__, deviceIndexM); + // Release immediately any pending conditional wait + tunedM.Broadcast(); +} + bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP) { debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM); diff --git a/device.h b/device.h index 52b828b..7d7e7da 100644 --- a/device.h +++ b/device.h @@ -18,7 +18,7 @@ class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf { // static ones public: - static unsigned int deviceCount; + static cMutex mutexS; static bool Initialize(unsigned int DeviceCount); static void Shutdown(void); static unsigned int Count(void); @@ -28,7 +28,8 @@ public: // private parts private: enum { - eReadyTimeoutMs = 2000 // in milliseconds + eReadyTimeoutMs = 2000, // in milliseconds + eTuningTimeoutMs = 1000 // in milliseconds }; unsigned int deviceIndexM; int bytesDeliveredM; @@ -40,7 +41,7 @@ private: cSatipTuner *pTunerM; cSatipSectionFilterHandler *pSectionFilterHandlerM; cTimeMs createdM; - cMutex mutexM; + cCondVar tunedM; // constructor & destructor public: @@ -109,6 +110,7 @@ public: // for internal device interface public: virtual void WriteData(u_char *bufferP, int lengthP); + virtual void SetChannelTuned(void); virtual int GetId(void); virtual int GetPmtPid(void); virtual int GetCISlot(void); diff --git a/deviceif.h b/deviceif.h index 9fe1636..e0a418f 100644 --- a/deviceif.h +++ b/deviceif.h @@ -13,6 +13,7 @@ public: cSatipDeviceIf() {} virtual ~cSatipDeviceIf() {} virtual void WriteData(u_char *bufferP, int lengthP) = 0; + virtual void SetChannelTuned(void) = 0; virtual int GetId(void) = 0; virtual int GetPmtPid(void) = 0; virtual int GetCISlot(void) = 0; diff --git a/tuner.c b/tuner.c index 0cc0ad9..2cb980b 100644 --- a/tuner.c +++ b/tuner.c @@ -127,6 +127,7 @@ void cSatipTuner::Action(void) break; case tsTuned: debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM); + deviceM->SetChannelTuned(); reConnectM.Set(eConnectTimeoutMs); idleCheck.Set(eIdleCheckTimeoutMs); lastIdleStatus = false;