From 0431806f24151d1bc503854782891a23e4f27623 Mon Sep 17 00:00:00 2001 From: Rolf Ahrenberg Date: Sat, 15 Nov 2014 20:15:00 +0200 Subject: [PATCH] Implemented a preliminary state machine for tuner. --- HISTORY | 1 + rtsp.c | 7 +- tuner.c | 209 +++++++++++++++++++++++++++++++++++--------------------- tuner.h | 16 ++--- 4 files changed, 144 insertions(+), 89 deletions(-) diff --git a/HISTORY b/HISTORY index 4973cb0..655d6de 100644 --- a/HISTORY +++ b/HISTORY @@ -82,3 +82,4 @@ VDR Plugin 'satip' Revision History - Fixed EIT scan (Thanks to Stefan Schallenberg). - Refactored input thread to increase performance. - Added new STAT command into the SVDRP interface. +- Refactored tuner implementation. diff --git a/rtsp.c b/rtsp.c index 826c511..0d52af1 100644 --- a/rtsp.c +++ b/rtsp.c @@ -253,16 +253,17 @@ bool cSatipRtsp::Teardown(const char *uriP) bool cSatipRtsp::ValidateLatestResponse(void) { - debug("cSatipRtsp::%s(%d)", __FUNCTION__, tunerIdM); + bool result = false; if (handleM) { long rc = 0; CURLcode res = CURLE_OK; SATIP_CURL_EASY_GETINFO(handleM, CURLINFO_RESPONSE_CODE, &rc); if (rc == 200) - return true; + result = true; else if (rc != 0) error("Tuner detected invalid status code %ld [device %d]", rc, tunerIdM); } + debug("cSatipRtsp::%s(%d): %s", __FUNCTION__, tunerIdM, result ? "ok" : "failed"); - return false; + return result; } diff --git a/tuner.c b/tuner.c index 7c85431..cc2c397 100644 --- a/tuner.c +++ b/tuner.c @@ -30,10 +30,9 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) statusUpdateM(), pidUpdateCacheM(), sessionM(""), + tunerStatusM(tsIdle), fdM(epoll_create(eMaxFileDescriptors)), timeoutM(eMinKeepAliveIntervalMs), - openedM(false), - tunedM(false), hasLockM(false), signalStrengthM(-1), signalQualityM(-1), @@ -89,6 +88,9 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) cSatipTuner::~cSatipTuner() { debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); + + tunerStatusM = tsIdle; + // Stop thread sleepM.Signal(); if (Running()) @@ -120,7 +122,7 @@ cSatipTuner::~cSatipTuner() void cSatipTuner::Action(void) { debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceIdM); - cTimeMs timeout(eReConnectTimeoutMs); + cTimeMs reconnection(eConnectTimeoutMs); // Increase priority SetPriority(-1); // Do the thread loop @@ -129,8 +131,8 @@ void cSatipTuner::Action(void) int nfds = epoll_wait(fdM, events, eMaxFileDescriptors, eReadTimeoutMs); switch (nfds) { default: + reconnection.Set(eConnectTimeoutMs); for (int i = 0; i < nfds; ++i) { - timeout.Set(eReConnectTimeoutMs); if (events[i].data.fd == rtpSocketM->Fd()) { // Read data int length = rtpSocketM->ReadVideo(packetBufferM, min(deviceM->CheckData(), packetBufferLenM)); @@ -146,27 +148,66 @@ void cSatipTuner::Action(void) ParseReceptionParameters((const char *)buf); } } - // fall through! + // fall through into epoll timeout case 0: - // Update pids - UpdatePids(); - // Remember the heart beat - KeepAlive(); - // Read reception statistics via DESCRIBE and RTCP - if (ReadReceptionStatus()) { - // Quirk for devices without valid reception data - if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) { - hasLockM = true; - signalStrengthM = eDefaultSignalStrength; - signalQualityM = eDefaultSignalQuality; - } - } - // Reconnect if necessary - if (openedM && timeout.TimedOut()) { - Disconnect(); - Connect(); - timeout.Set(eReConnectTimeoutMs); - } + switch (tunerStatusM) { + case tsIdle: + //debug("cSatipTuner::%s(): tsIdle [device %d]", __FUNCTION__, deviceIdM); + break; + case tsRelease: + //debug("cSatipTuner::%s(): tsRelease [device %d]", __FUNCTION__, deviceIdM); + Disconnect(); + tunerStatusM = tsIdle; + break; + case tsSet: + //debug("cSatipTuner::%s(): tsSet [device %d]", __FUNCTION__, deviceIdM); + reconnection.Set(eConnectTimeoutMs); + Disconnect(); + if (Connect()) { + tunerStatusM = tsTuned; + UpdatePids(true); + } + else + tunerStatusM = tsIdle; + break; + case tsTuned: + //debug("cSatipTuner::%s(): tsTuned [device %d]", __FUNCTION__, deviceIdM); + reconnection.Set(eConnectTimeoutMs); + // Read reception statistics via DESCRIBE and RTCP + if (hasLockM || ReadReceptionStatus()) { + // Quirk for devices without valid reception data + if (currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkForceLock)) { + hasLockM = true; + signalStrengthM = eDefaultSignalStrength; + signalQualityM = eDefaultSignalQuality; + } + if (hasLockM) + tunerStatusM = tsLocked; + } + break; + case tsLocked: + //debug("cSatipTuner::%s(): tsLocked [device %d]", __FUNCTION__, deviceIdM); + tunerStatusM = tsLocked; + if (!UpdatePids()) { + debug("cSatipTuner::%s(): pid update failed - re-tuning [device %d]", __FUNCTION__, deviceIdM); + tunerStatusM = tsSet; + break; + } + if (!KeepAlive()) { + debug("cSatipTuner::%s(): keep-alive failed - re-tuning [device %d]", __FUNCTION__, deviceIdM); + tunerStatusM = tsSet; + break; + } + if (reconnection.TimedOut()) { + debug("cSatipTuner::%s(): connection timeout - re-tuning [device %d]", __FUNCTION__, deviceIdM); + tunerStatusM = tsSet; + break; + } + break; + default: + error("Unknown tuner status %d", tunerStatusM); + break; + } break; case -1: error("epoll_wait() failed"); @@ -178,14 +219,18 @@ void cSatipTuner::Action(void) bool cSatipTuner::Open(void) { + cMutexLock MutexLock(&mutexM); debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); - return Connect(); + tunerStatusM = tsSet; + return true; } bool cSatipTuner::Close(void) { + cMutexLock MutexLock(&mutexM); debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); - return Disconnect(); + tunerStatusM = tsRelease; + return true; } bool cSatipTuner::Connect(void) @@ -197,39 +242,29 @@ bool cSatipTuner::Connect(void) cString connectionUri = cString::sprintf("rtsp://%s", *streamAddrM); cString uri = cString::sprintf("%s/?%s", *connectionUri, *streamParamM); // Just retune - if (tunedM && (streamIdM >= 0)) { + if ((tunerStatusM >= tsTuned) && (streamIdM >= 0) && rtpSocketM && rtcpSocketM) { debug("cSatipTuner::%s(): retune [device %d]", __FUNCTION__, deviceIdM); - keepAliveM.Set(0); - KeepAlive(); + KeepAlive(true); // Flush any old content - if (rtpSocketM) - rtpSocketM->Flush(); - openedM = rtspM->Setup(*uri, rtpSocketM->Port(), rtcpSocketM->Port()); - return openedM; + rtpSocketM->Flush(); + return rtspM->Setup(*uri, rtpSocketM->Port(), rtcpSocketM->Port()); } keepAliveM.Set(timeoutM); - openedM = rtspM->Options(*connectionUri); - if (openedM) { + if (rtspM->Options(*connectionUri)) { if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId)) rtspM->SetSession(SkipZeroes(*sessionM)); if (rtspM->Setup(*uri, rtpSocketM->Port(), rtcpSocketM->Port())) { - tunedM = true; - UpdatePids(true); if (nextServerM) { cSatipDiscover::GetInstance()->UseServer(nextServerM, true); currentServerM = nextServerM; nextServerM = NULL; } } - else - openedM = false; + return true; } - - return openedM; } - openedM = false; - return openedM; + return false; } bool cSatipTuner::Disconnect(void) @@ -237,10 +272,11 @@ bool cSatipTuner::Disconnect(void) cMutexLock MutexLock(&mutexM); debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); - if (openedM && !isempty(*streamAddrM)) { + if ((tunerStatusM != tsIdle) && !isempty(*streamAddrM) && (streamIdM >= 0)) { cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); rtspM->Teardown(*uri); } + tunerStatusM = tsIdle; // Reset signal parameters hasLockM = false; @@ -249,8 +285,6 @@ bool cSatipTuner::Disconnect(void) if (currentServerM) cSatipDiscover::GetInstance()->UseServer(currentServerM, false); - openedM = false; - tunedM = false; statusUpdateM.Set(0); timeoutM = eMinKeepAliveIntervalMs; addPidsM.Clear(); @@ -337,12 +371,11 @@ bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const // Update stream address and parameter streamAddrM = rtspM->RtspUnescapeString(nextServerM->Address()); streamParamM = rtspM->RtspUnescapeString(parameterP); - // Reconnect - Connect(); + tunerStatusM = tsSet; } } else - Disconnect(); + tunerStatusM = tsRelease; return true; } @@ -366,9 +399,9 @@ bool cSatipTuner::SetPid(int pidP, int typeP, bool onP) bool cSatipTuner::UpdatePids(bool forceP) { - cMutexLock MutexLock(&mutexM); + //debug("cSatipTuner::%s(%d) tunerStatus=%s [device %d]", __FUNCTION__, forceP, TunerStatusString(tunerStatusM), deviceIdM); if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) && - tunedM && !isempty(*streamAddrM) && (streamIdM > 0)) { + (tunerStatusM >= tsTuned) && !isempty(*streamAddrM) && (streamIdM > 0)) { cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); bool usedummy = !!(currentServerM && currentServerM->Quirk(cSatipServer::eSatipQuirkPlayPids)); if (forceP || usedummy) { @@ -392,44 +425,66 @@ bool cSatipTuner::UpdatePids(bool forceP) uri = cString::sprintf("%s%d%s", *uri, delPidsM[i], (i == (delPidsM.Size() - 1)) ? "" : ","); } } - if (rtspM->Play(*uri)) { - addPidsM.Clear(); - delPidsM.Clear(); - return true; - } - Disconnect(); + if (!rtspM->Play(*uri)) + return false; + addPidsM.Clear(); + delPidsM.Clear(); } - return false; + return true; } -bool cSatipTuner::KeepAlive(void) +bool cSatipTuner::KeepAlive(bool forceP) { + //debug("cSatipTuner::%s(%d) tunerStatus=%s [device %d]", __FUNCTION__, forceP, TunerStatusString(tunerStatusM), deviceIdM); cMutexLock MutexLock(&mutexM); - if (tunedM && keepAliveM.TimedOut()) { - cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); + if (keepAliveM.TimedOut()) { keepAliveM.Set(timeoutM); - if (rtspM->Options(*uri)) + forceP = true; + } + if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) { + cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); + if (!rtspM->Options(*uri)) + return false; + } + + return true; +} + +bool cSatipTuner::ReadReceptionStatus(bool forceP) +{ + //debug("cSatipTuner::%s(%d) tunerStatus=%s [device %d]", __FUNCTION__, forceP, TunerStatusString(tunerStatusM), deviceIdM); + cMutexLock MutexLock(&mutexM); + if (statusUpdateM.TimedOut()) { + statusUpdateM.Set(eStatusUpdateTimeoutMs); + forceP = true; + } + if (forceP && !isempty(*streamAddrM) && (streamIdM > 0)) { + cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); + if (rtspM->Describe(*uri)) return true; - Disconnect(); } return false; } -bool cSatipTuner::ReadReceptionStatus(void) +const char *cSatipTuner::TunerStatusString(eTunerStatus statusP) { - cMutexLock MutexLock(&mutexM); - if (tunedM && !pidsM.Size() && statusUpdateM.TimedOut() ) { - cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM); - if (rtspM->Describe(*uri)) { - statusUpdateM.Set(eStatusUpdateTimeoutMs); - return true; - } - Disconnect(); - } - - return false; + switch (statusP) { + case tsIdle: + return "tsIdle"; + case tsRelease: + return "tsRelease"; + case tsSet: + return "tsSet"; + case tsLocked: + return "tsLocked"; + case tsTuned: + return "tsTuned"; + default: + break; + } + return "---"; } int cSatipTuner::SignalStrength(void) @@ -447,7 +502,7 @@ int cSatipTuner::SignalQuality(void) bool cSatipTuner::HasLock(void) { //debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); - return tunedM && hasLockM; + return (tunerStatusM >= tsTuned) && hasLockM; } cString cSatipTuner::GetSignalStatus(void) @@ -459,5 +514,5 @@ cString cSatipTuner::GetSignalStatus(void) cString cSatipTuner::GetInformation(void) { //debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); - return tunedM ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed"; + return (tunerStatusM >= tsTuned) ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed"; } diff --git a/tuner.h b/tuner.h index f223af7..ef96cf8 100644 --- a/tuner.h +++ b/tuner.h @@ -52,11 +52,11 @@ private: eDefaultSignalQuality = 224, eReadTimeoutMs = 500, // in milliseconds eStatusUpdateTimeoutMs = 1000, // in milliseconds - eConnectTimeoutMs = 1500, // in milliseconds ePidUpdateIntervalMs = 250, // in milliseconds - eReConnectTimeoutMs = 5000, // in milliseconds + eConnectTimeoutMs = 5000, // in milliseconds eMinKeepAliveIntervalMs = 30000 // in milliseconds }; + enum eTunerStatus { tsIdle, tsRelease, tsSet, tsTuned, tsLocked }; cCondWait sleepM; cSatipDeviceIf* deviceM; @@ -73,13 +73,11 @@ private: cMutex mutexM; cTimeMs keepAliveM; cTimeMs statusUpdateM; - cTimeMs signalInfoCacheM; cTimeMs pidUpdateCacheM; cString sessionM; + eTunerStatus tunerStatusM; int fdM; int timeoutM; - bool openedM; - bool tunedM; bool hasLockM; int signalStrengthM; int signalQualityM; @@ -90,10 +88,10 @@ private: bool Connect(void); bool Disconnect(void); - bool KeepAlive(void); - bool ReadReceptionStatus(void); - bool UpdateSignalInfoCache(void); + bool KeepAlive(bool forceP = false); + bool ReadReceptionStatus(bool forceP = false); bool UpdatePids(bool forceP = false); + const char *TunerStatusString(eTunerStatus statusP); protected: virtual void Action(void); @@ -101,7 +99,7 @@ protected: public: cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP); virtual ~cSatipTuner(); - bool IsTuned(void) const { return tunedM; } + bool IsTuned(void) const { return tunerStatusM > tsIdle; } bool SetSource(cSatipServer *serverP, const char *parameterP, const int indexP); bool SetPid(int pidP, int typeP, bool onP); bool Open(void);