Serialize channel switching to prevent device allocation failures.

This commit is contained in:
Rolf Ahrenberg 2017-11-13 22:12:10 +02:00
parent dbe67a2242
commit 72c3247dc2
4 changed files with 22 additions and 4 deletions

View File

@ -15,6 +15,8 @@
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL }; static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
cMutex cSatipDevice::mutexS = cMutex();
cSatipDevice::cSatipDevice(unsigned int indexP) cSatipDevice::cSatipDevice(unsigned int indexP)
: deviceIndexM(indexP), : deviceIndexM(indexP),
bytesDeliveredM(0), bytesDeliveredM(0),
@ -23,7 +25,7 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)), deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
channelM(), channelM(),
createdM(0), createdM(0),
mutexM() tunedM()
{ {
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE; unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
bufsize -= (bufsize % TS_SIZE); bufsize -= (bufsize % TS_SIZE);
@ -43,6 +45,8 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
cSatipDevice::~cSatipDevice() cSatipDevice::~cSatipDevice()
{ {
debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM); debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
// Release immediately any pending conditional wait
tunedM.Broadcast();
// Stop section handler // Stop section handler
StopSectionHandler(); StopSectionHandler();
DELETE_POINTER(pSectionFilterHandlerM); DELETE_POINTER(pSectionFilterHandlerM);
@ -345,6 +349,7 @@ bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP) 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); debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
if (channelP) { if (channelP) {
cDvbTransponderParameters dtp(channelP->Parameters()); 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)) { if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) {
channelM = *channelP; channelM = *channelP;
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server)); 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; return true;
} }
} }
@ -373,6 +380,13 @@ bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
return false; 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) 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); debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM);

View File

@ -18,7 +18,7 @@
class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf { class cSatipDevice : public cDevice, public cSatipPidStatistics, public cSatipBufferStatistics, public cSatipDeviceIf {
// static ones // static ones
public: public:
static unsigned int deviceCount; static cMutex mutexS;
static bool Initialize(unsigned int DeviceCount); static bool Initialize(unsigned int DeviceCount);
static void Shutdown(void); static void Shutdown(void);
static unsigned int Count(void); static unsigned int Count(void);
@ -28,7 +28,8 @@ public:
// private parts // private parts
private: private:
enum { enum {
eReadyTimeoutMs = 2000 // in milliseconds eReadyTimeoutMs = 2000, // in milliseconds
eTuningTimeoutMs = 1000 // in milliseconds
}; };
unsigned int deviceIndexM; unsigned int deviceIndexM;
int bytesDeliveredM; int bytesDeliveredM;
@ -40,7 +41,7 @@ private:
cSatipTuner *pTunerM; cSatipTuner *pTunerM;
cSatipSectionFilterHandler *pSectionFilterHandlerM; cSatipSectionFilterHandler *pSectionFilterHandlerM;
cTimeMs createdM; cTimeMs createdM;
cMutex mutexM; cCondVar tunedM;
// constructor & destructor // constructor & destructor
public: public:
@ -109,6 +110,7 @@ public:
// for internal device interface // for internal device interface
public: public:
virtual void WriteData(u_char *bufferP, int lengthP); virtual void WriteData(u_char *bufferP, int lengthP);
virtual void SetChannelTuned(void);
virtual int GetId(void); virtual int GetId(void);
virtual int GetPmtPid(void); virtual int GetPmtPid(void);
virtual int GetCISlot(void); virtual int GetCISlot(void);

View File

@ -13,6 +13,7 @@ public:
cSatipDeviceIf() {} cSatipDeviceIf() {}
virtual ~cSatipDeviceIf() {} virtual ~cSatipDeviceIf() {}
virtual void WriteData(u_char *bufferP, int lengthP) = 0; virtual void WriteData(u_char *bufferP, int lengthP) = 0;
virtual void SetChannelTuned(void) = 0;
virtual int GetId(void) = 0; virtual int GetId(void) = 0;
virtual int GetPmtPid(void) = 0; virtual int GetPmtPid(void) = 0;
virtual int GetCISlot(void) = 0; virtual int GetCISlot(void) = 0;

View File

@ -127,6 +127,7 @@ void cSatipTuner::Action(void)
break; break;
case tsTuned: case tsTuned:
debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM); debug4("%s: tsTuned [device %d]", __PRETTY_FUNCTION__, deviceIdM);
deviceM->SetChannelTuned();
reConnectM.Set(eConnectTimeoutMs); reConnectM.Set(eConnectTimeoutMs);
idleCheck.Set(eIdleCheckTimeoutMs); idleCheck.Set(eIdleCheckTimeoutMs);
lastIdleStatus = false; lastIdleStatus = false;