From 0bf841555b6122e2fee470ad6167d13cb6bd2196 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 | 201 ++++++++++++++++++++++++++++++++++++-------------------- tuner.h | 16 ++--- 4 files changed, 140 insertions(+), 85 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 61baa97..329038e 100644 --- a/rtsp.c +++ b/rtsp.c @@ -250,16 +250,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 a05c16b..c514841 100644 --- a/tuner.c +++ b/tuner.c @@ -28,9 +28,8 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP) statusUpdateM(), pidUpdateCacheM(), sessionM(""), + tunerStatusM(tsIdle), timeoutM(eMinKeepAliveIntervalMs), - openedM(false), - tunedM(false), hasLockM(false), signalStrengthM(-1), signalQualityM(-1), @@ -64,6 +63,8 @@ cSatipTuner::~cSatipTuner() { debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceIdM); + tunerStatusM = tsIdle; + // Stop thread sleepM.Signal(); if (Running()) @@ -85,28 +86,67 @@ cSatipTuner::~cSatipTuner() void cSatipTuner::Action(void) { debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceIdM); - cTimeMs timeout(eReConnectTimeoutMs); + cTimeMs reconnection(eConnectTimeoutMs); // Do the thread loop while (Running()) { - // 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; + } sleepM.Wait(100); // to avoid busy loop and reduce cpu load } debug("cSatipTuner::%s(): exiting [device %d]", __FUNCTION__, deviceIdM); @@ -114,14 +154,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) @@ -133,38 +177,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) && rtpM && rtcpM) { debug("cSatipTuner::%s(): retune [device %d]", __FUNCTION__, deviceIdM); - keepAliveM.Set(0); - KeepAlive(); + KeepAlive(true); // Flush any old content rtpM->Flush(); - openedM = rtspM->Setup(*uri, rtpM->Port(), rtcpM->Port()); - return openedM; + return rtspM->Setup(*uri, rtpM->Port(), rtcpM->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, rtpM->Port(), rtcpM->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) @@ -172,10 +207,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; @@ -184,8 +220,6 @@ bool cSatipTuner::Disconnect(void) if (currentServerM) cSatipDiscover::GetInstance()->UseServer(currentServerM, false); - openedM = false; - tunedM = false; statusUpdateM.Set(0); timeoutM = eMinKeepAliveIntervalMs; addPidsM.Clear(); @@ -272,12 +306,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; sleepM.Signal(); return true; } @@ -303,9 +336,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) { @@ -329,44 +362,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) @@ -384,7 +439,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) @@ -396,5 +451,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 282f32a..f4c391a 100644 --- a/tuner.h +++ b/tuner.h @@ -53,11 +53,11 @@ private: eDefaultSignalStrength = 15, eDefaultSignalQuality = 224, 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; @@ -72,12 +72,10 @@ private: cMutex mutexM; cTimeMs keepAliveM; cTimeMs statusUpdateM; - cTimeMs signalInfoCacheM; cTimeMs pidUpdateCacheM; cString sessionM; + eTunerStatus tunerStatusM; int timeoutM; - bool openedM; - bool tunedM; bool hasLockM; int signalStrengthM; int signalQualityM; @@ -88,10 +86,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); @@ -99,7 +97,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);