From 482d898333facf53bd3208cf5e44a0cf3e1f4f3b Mon Sep 17 00:00:00 2001 From: phunkyfish Date: Thu, 8 Oct 2020 14:59:55 +0100 Subject: [PATCH] Use std::thread, std::mutex, condition_variable instead of event Signed-off-by: Bernd Kuhls --- src/lib/tsreader/DeMultiplexer.cpp | 2 +- src/lib/tsreader/DeMultiplexer.h | 4 +- src/lib/tsreader/FileReader.cpp | 2 +- src/lib/tsreader/MemoryBuffer.cpp | 15 +++-- src/lib/tsreader/MemoryBuffer.h | 7 +- src/lib/tsreader/MemoryReader.h | 1 + src/lib/tsreader/MemorySink.cpp | 2 +- src/lib/tsreader/MemorySink.h | 4 +- src/lib/tsreader/MepoRTSPClient.cpp | 28 ++++---- src/lib/tsreader/MepoRTSPClient.h | 10 ++- src/lib/tsreader/MultiFileReader.cpp | 9 ++- src/os-dependent.h | 95 ++++++++++++++++++++++++++++ src/pvrclient-mediaportal.cpp | 29 ++++----- src/pvrclient-mediaportal.h | 21 +++--- 14 files changed, 168 insertions(+), 61 deletions(-) diff --git a/src/lib/tsreader/DeMultiplexer.cpp b/src/lib/tsreader/DeMultiplexer.cpp index 436e452..3d0d9a2 100644 --- a/src/lib/tsreader/DeMultiplexer.cpp +++ b/src/lib/tsreader/DeMultiplexer.cpp @@ -104,7 +104,7 @@ namespace MPTV if (m_filter.IsSeeking()) return 0; // Ambass : to check - P8PLATFORM::CLockObject lock(m_sectionRead); + std::lock_guard lock(m_sectionRead); if (NULL == m_reader) return 0; diff --git a/src/lib/tsreader/DeMultiplexer.h b/src/lib/tsreader/DeMultiplexer.h index c7cd577..72ed87d 100644 --- a/src/lib/tsreader/DeMultiplexer.h +++ b/src/lib/tsreader/DeMultiplexer.h @@ -37,7 +37,7 @@ #include "PacketSync.h" #include "TSHeader.h" #include "PatParser.h" -#include "p8-platform/threads/mutex.h" +#include namespace MPTV { @@ -60,7 +60,7 @@ namespace MPTV private: unsigned long long m_LastDataFromRtsp; bool m_bEndOfFile; - P8PLATFORM::CMutex m_sectionRead; + std::mutex m_sectionRead; FileReader* m_reader; CPatParser m_patParser; CTsReader& m_filter; diff --git a/src/lib/tsreader/FileReader.cpp b/src/lib/tsreader/FileReader.cpp index 73b23af..358b05f 100644 --- a/src/lib/tsreader/FileReader.cpp +++ b/src/lib/tsreader/FileReader.cpp @@ -35,7 +35,7 @@ #include "FileReader.h" #include //for kodi::Log #include "TSDebug.h" -#include "p8-platform/threads/threads.h" +#include "os-dependent.h" #include //std::min, std::max #include "utils.h" #include diff --git a/src/lib/tsreader/MemoryBuffer.cpp b/src/lib/tsreader/MemoryBuffer.cpp index 0e736f2..b5400da 100644 --- a/src/lib/tsreader/MemoryBuffer.cpp +++ b/src/lib/tsreader/MemoryBuffer.cpp @@ -29,7 +29,7 @@ #ifdef LIVE555 -#include "p8-platform/threads/mutex.h" +#include "os-dependent.h" #include "MemoryBuffer.h" #include //for kodi::Log #include "TSDebug.h" @@ -56,7 +56,7 @@ bool CMemoryBuffer::IsRunning() void CMemoryBuffer::Clear() { - P8PLATFORM::CLockObject BufferLock(m_BufferLock); + std::lock_guard BufferLock(m_BufferLock); std::vector::iterator it = m_Array.begin(); for (auto& item : m_Array) @@ -104,14 +104,17 @@ size_t CMemoryBuffer::ReadFromBuffer(unsigned char *pbData, size_t lDataLength) { if (!m_bRunning) return 0; - m_event.Wait(5000); + + std::unique_lock lock(m_BufferLock); + m_condition.wait_for(lock, std::chrono::milliseconds(5000)); + if (!m_bRunning) return 0; } // kodi::Log(ADDON_LOG_DEBUG, "get..%d/%d", lDataLength, m_BytesInBuffer); size_t bytesWritten = 0; - P8PLATFORM::CLockObject BufferLock(m_BufferLock); + std::lock_guard BufferLock(m_BufferLock); while (bytesWritten < lDataLength) { @@ -172,7 +175,7 @@ long CMemoryBuffer::PutBuffer(unsigned char *pbData, size_t lDataLength) memcpy(item->data, pbData, lDataLength); bool sleep = false; { - P8PLATFORM::CLockObject BufferLock(m_BufferLock); + std::lock_guard BufferLock(m_BufferLock); m_Array.push_back(item); m_BytesInBuffer += lDataLength; @@ -192,7 +195,7 @@ long CMemoryBuffer::PutBuffer(unsigned char *pbData, size_t lDataLength) } if (m_BytesInBuffer > 0) { - m_event.Broadcast(); + m_condition.notify_one(); } } diff --git a/src/lib/tsreader/MemoryBuffer.h b/src/lib/tsreader/MemoryBuffer.h index 080553b..4f8708f 100644 --- a/src/lib/tsreader/MemoryBuffer.h +++ b/src/lib/tsreader/MemoryBuffer.h @@ -30,7 +30,8 @@ #ifdef LIVE555 -#include "p8-platform/threads/mutex.h" +#include +#include #include class CMemoryBuffer @@ -55,9 +56,9 @@ class CMemoryBuffer protected: std::vector m_Array; - P8PLATFORM::CMutex m_BufferLock; + std::mutex m_BufferLock; size_t m_BytesInBuffer; - P8PLATFORM::CEvent m_event; + std::condition_variable m_condition; bool m_bRunning; }; #endif //LIVE555 diff --git a/src/lib/tsreader/MemoryReader.h b/src/lib/tsreader/MemoryReader.h index fef4f98..288984b 100644 --- a/src/lib/tsreader/MemoryReader.h +++ b/src/lib/tsreader/MemoryReader.h @@ -32,6 +32,7 @@ #include "FileReader.h" #include "MemoryBuffer.h" +#include "os-dependent.h" namespace MPTV { diff --git a/src/lib/tsreader/MemorySink.cpp b/src/lib/tsreader/MemorySink.cpp index dafef56..af8b74c 100644 --- a/src/lib/tsreader/MemorySink.cpp +++ b/src/lib/tsreader/MemorySink.cpp @@ -84,7 +84,7 @@ void CMemorySink::addData(unsigned char* data, size_t dataSize, struct timeval U return; } - P8PLATFORM::CLockObject BufferLock(m_BufferLock); + std::lock_guard BufferLock(m_BufferLock); m_bReEntrant = true; m_buffer.PutBuffer(data, dataSize); diff --git a/src/lib/tsreader/MemorySink.h b/src/lib/tsreader/MemorySink.h index cc0f3c8..22d91c6 100644 --- a/src/lib/tsreader/MemorySink.h +++ b/src/lib/tsreader/MemorySink.h @@ -35,7 +35,7 @@ #endif #include "MemoryBuffer.h" -#include "p8-platform/threads/mutex.h" +#include class CMemorySink: public MediaSink { @@ -57,7 +57,7 @@ class CMemorySink: public MediaSink private: // redefined virtual functions: virtual Boolean continuePlaying(); - P8PLATFORM::CMutex m_BufferLock; + std::mutex m_BufferLock; unsigned char* m_pSubmitBuffer; int m_iSubmitBufferPos; bool m_bReEntrant; diff --git a/src/lib/tsreader/MepoRTSPClient.cpp b/src/lib/tsreader/MepoRTSPClient.cpp index ccd6761..688ae84 100644 --- a/src/lib/tsreader/MepoRTSPClient.cpp +++ b/src/lib/tsreader/MepoRTSPClient.cpp @@ -54,7 +54,7 @@ CRTSPClient::CRTSPClient() m_env = NULL; m_fDuration = 0.0f; m_url[0] = '\0'; - m_bRunning = false; + m_running = false; } CRTSPClient::~CRTSPClient() @@ -496,7 +496,9 @@ void CRTSPClient::StartBufferThread() if (!m_BufferThreadActive) { - CreateThread(); + m_running = true; + m_thread = std::thread([&] { Process(); }); + m_BufferThreadActive = true; } kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::StartBufferThread done"); @@ -505,11 +507,12 @@ void CRTSPClient::StartBufferThread() void CRTSPClient::StopBufferThread() { kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::StopBufferThread"); - m_bRunning = false; + m_running = false; if (!m_BufferThreadActive) return; - StopThread(); + if (m_thread.joinable()) + m_thread.join(); m_BufferThreadActive = false; kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::StopBufferThread done"); @@ -539,25 +542,22 @@ void CRTSPClient::FillBuffer(unsigned long byteCount) kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::Fillbuffer...%d/%d\n", byteCount, m_buffer->Size() ); } -void *CRTSPClient::Process() +void CRTSPClient::Process() { m_BufferThreadActive = true; - m_bRunning = true; kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient:: thread started"); - while (m_env != NULL && !IsStopped()) + while (m_env != NULL && m_running) { m_env->taskScheduler().doEventLoop(); - if (m_bRunning == false) + if (m_running == false) break; } kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient:: thread stopped"); m_BufferThreadActive = false; - - return NULL; } void CRTSPClient::Continue() @@ -582,8 +582,12 @@ bool CRTSPClient::Pause() if (m_ourClient != NULL && m_session != NULL) { kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::Pause() stopthread"); - StopThread(10000); // Ambass : sometimes 100mS ( prev value ) is not enough and thread is not stopped. - // now stopping takes around 5 secs ?!?! why ???? + // Ambass : sometimes 100mS ( prev value ) is not enough and thread is not stopped. + // now stopping takes around 5 secs ?!?! why ???? + m_running = false; + if (m_thread.joinable()) + m_thread.join(); + kodi::Log(ADDON_LOG_DEBUG, "CRTSPClient::Pause() thread stopped"); RTSPClient* rtspClient=(RTSPClient*)m_ourClient; rtspClient->pauseMediaSession(*m_session); diff --git a/src/lib/tsreader/MepoRTSPClient.h b/src/lib/tsreader/MepoRTSPClient.h index bd6e578..9bb0421 100644 --- a/src/lib/tsreader/MepoRTSPClient.h +++ b/src/lib/tsreader/MepoRTSPClient.h @@ -31,7 +31,8 @@ #ifdef LIVE555 -#include "p8-platform/threads/threads.h" +#include +#include #include "lib/tsreader/MemoryBuffer.h" #include "liveMedia.hh" @@ -41,7 +42,7 @@ #define RTSP_URL_BUFFERSIZE 2048 -class CRTSPClient: public P8PLATFORM::CThread +class CRTSPClient { public: CRTSPClient(); @@ -101,7 +102,7 @@ class CRTSPClient: public P8PLATFORM::CThread // Thread private: - virtual void *Process(void); + void Process(); void StartBufferThread(); void StopBufferThread(); bool m_BufferThreadActive; @@ -113,5 +114,8 @@ class CRTSPClient: public P8PLATFORM::CThread bool m_bRunning; bool m_bPaused; char m_outFileName[1000]; + + std::atomic m_running = {false}; + std::thread m_thread; }; #endif //LIVE555 diff --git a/src/lib/tsreader/MultiFileReader.cpp b/src/lib/tsreader/MultiFileReader.cpp index 21fd7b2..5106418 100644 --- a/src/lib/tsreader/MultiFileReader.cpp +++ b/src/lib/tsreader/MultiFileReader.cpp @@ -35,17 +35,16 @@ #include "MultiFileReader.h" #include //for kodi::Log #include +#include #include "TSDebug.h" #include #include "utils.h" #include -#include "p8-platform/threads/threads.h" #include +#include "os-dependent.h" #include -using namespace P8PLATFORM; - //Maximum time in msec to wait for the buffer file to become available - Needed for DVB radio (this sometimes takes some time) #define MAX_BUFFER_TIMEOUT 1500 @@ -121,12 +120,12 @@ namespace MPTV if (RefreshTSBufferFile() == S_FALSE) { // For radio the buffer sometimes needs some time to become available, so wait and try it more than once - P8PLATFORM::CTimeout timeout(MAX_BUFFER_TIMEOUT); + kodi::tools::CEndTime timeout(MAX_BUFFER_TIMEOUT); do { std::this_thread::sleep_for(std::chrono::milliseconds(100)); - if (timeout.TimeLeft() == 0) + if (timeout.MillisLeft() == 0) { kodi::Log(ADDON_LOG_ERROR, "MultiFileReader: timed out while waiting for buffer file to become available"); kodi::QueueNotification(QUEUE_ERROR, "", "Time out while waiting for buffer file"); diff --git a/src/os-dependent.h b/src/os-dependent.h index cdc6980..28c162c 100644 --- a/src/os-dependent.h +++ b/src/os-dependent.h @@ -11,6 +11,13 @@ #if (defined(_WIN32) || defined(_WIN64)) +#include + +/* Handling of 2-byte Windows wchar strings */ +#define WcsLen wcslen +#define WcsToMbs wcstombs +typedef wchar_t Wchar_t; /* sizeof(wchar_t) = 2 bytes on Windows */ + #ifndef _SSIZE_T_DEFINED #ifdef _WIN64 typedef __int64 ssize_t; @@ -20,20 +27,108 @@ typedef _W64 int ssize_t; #define _SSIZE_T_DEFINED #endif +/* Prevent deprecation warnings */ +#define strnicmp _strnicmp + +#define PATH_SEPARATOR_CHAR '\\' + #else #if (defined(TARGET_LINUX) || defined(TARGET_DARWIN)) #include #include #include + +#define strnicmp(X,Y,N) strncasecmp(X,Y,N) + inline unsigned long long GetTickCount64(void) { auto now = std::chrono::steady_clock::now(); return std::chrono::duration_cast(now.time_since_epoch()).count(); }; + +#define PATH_SEPARATOR_CHAR '/' + +#if defined(__APPLE__) +// for HRESULT +#include +#endif + +/* Handling of 2-byte Windows wchar strings on non-Windows targets + * Used by The MediaPortal and ForTheRecord pvr addons + */ +typedef uint16_t Wchar_t; /* sizeof(wchar_t) = 4 bytes on Linux, but the MediaPortal buffer files have 2-byte wchars */ + +/* This is a replacement of the Windows wcslen() function which assumes that + * wchar_t is a 2-byte character. + * It is used for processing Windows wchar strings + */ +inline size_t WcsLen(const Wchar_t *str) +{ + const unsigned short *eos = (const unsigned short*)str; + while( *eos++ ) ; + return( (size_t)(eos - (const unsigned short*)str) -1); +}; + +/* This is a replacement of the Windows wcstombs() function which assumes that + * wchar_t is a 2-byte character. + * It is used for processing Windows wchar strings + */ +inline size_t WcsToMbs(char *s, const Wchar_t *w, size_t n) +{ + size_t i = 0; + const unsigned short *wc = (const unsigned short*) w; + while(wc[i] && (i < n)) + { + s[i] = wc[i]; + ++i; + } + if (i < n) s[i] = '\0'; + + return (i); +}; + #endif /* TARGET_LINUX || TARGET_DARWIN */ #endif +typedef long LONG; +#if !defined(__APPLE__) +typedef LONG HRESULT; +#endif + +#ifndef FAILED +#define FAILED(Status) ((HRESULT)(Status)<0) +#endif + +#ifndef SUCCEEDED +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#endif + +#define _FILE_OFFSET_BITS 64 +#define FILE_BEGIN 0 +#define FILE_CURRENT 1 +#define FILE_END 2 + +#ifndef S_OK +#define S_OK 0L +#endif + +#ifndef S_FALSE +#define S_FALSE 1L +#endif + +// Error codes +#define ERROR_FILENAME_EXCED_RANGE 206L +#define ERROR_INVALID_NAME 123L + +#ifndef E_OUTOFMEMORY +#define E_OUTOFMEMORY 0x8007000EL +#endif + +#ifndef E_FAIL +#define E_FAIL 0x8004005EL +#endif + // Additional typedefs typedef uint8_t byte; diff --git a/src/pvrclient-mediaportal.cpp b/src/pvrclient-mediaportal.cpp index 851b940..c1052e3 100644 --- a/src/pvrclient-mediaportal.cpp +++ b/src/pvrclient-mediaportal.cpp @@ -28,8 +28,6 @@ #include #include -#include - using namespace kodi::tools; using namespace std; using namespace MPTV; @@ -70,7 +68,6 @@ cPVRClientMediaPortal::cPVRClientMediaPortal(KODI_HANDLE instance, const std::st m_BackendTime = 0; m_tsreader = NULL; m_genretable = NULL; - m_iLastRecordingUpdate = 0; m_signalStateCounter = 0; m_iSignal = 0; m_iSNR = 0; @@ -99,7 +96,7 @@ string cPVRClientMediaPortal::SendCommand(const char* command) string cPVRClientMediaPortal::SendCommand(const string& command) { - P8PLATFORM::CLockObject critsec(m_mutex); + std::lock_guard critsec(m_mutex); if ( !m_tcpclient->send(command) ) { @@ -174,10 +171,10 @@ ADDON_STATUS cPVRClientMediaPortal::TryConnect() case PVR_CONNECTION_STATE_SERVER_UNREACHABLE: kodi::Log(ADDON_LOG_ERROR, "Could not connect to MediaPortal TV Server backend."); // Start background thread for connecting to the backend - if (!IsRunning()) + if (!m_running) { - kodi::Log(ADDON_LOG_INFO, "Waiting for a connection in the background."); - CreateThread(); + m_running = true; + m_thread = std::thread([&] { Process(); }); } return ADDON_STATUS_LOST_CONNECTION; case PVR_CONNECTION_STATE_CONNECTING: @@ -190,7 +187,7 @@ ADDON_STATUS cPVRClientMediaPortal::TryConnect() PVR_CONNECTION_STATE cPVRClientMediaPortal::Connect(bool updateConnectionState) { - P8PLATFORM::CLockObject critsec(m_connectionMutex); + std::lock_guard critsec(m_connectionMutex); string result; @@ -317,9 +314,11 @@ void cPVRClientMediaPortal::Disconnect() kodi::Log(ADDON_LOG_INFO, "Disconnect"); - if (IsRunning()) + if (m_running) { - StopThread(1000); + m_running = false; + if (m_thread.joinable()) + m_thread.join(); } if (m_tcpclient->is_valid() && m_bTimeShiftStarted) @@ -361,14 +360,14 @@ bool cPVRClientMediaPortal::IsUp() } } -void* cPVRClientMediaPortal::Process(void) +void cPVRClientMediaPortal::Process() { kodi::Log(ADDON_LOG_DEBUG, "Background thread started."); bool keepWaiting = true; PVR_CONNECTION_STATE state; - while (!IsStopped() && keepWaiting) + while (m_running && keepWaiting) { state = Connect(false); @@ -396,8 +395,6 @@ void* cPVRClientMediaPortal::Process(void) SetConnectionState(state); kodi::Log(ADDON_LOG_DEBUG, "Background thread finished."); - - return NULL; } @@ -1188,7 +1185,7 @@ PVR_ERROR cPVRClientMediaPortal::GetRecordings(bool deleted, kodi::addon::PVRRec } } - m_iLastRecordingUpdate = P8PLATFORM::GetTimeMs(); + m_iLastRecordingUpdate = std::chrono::system_clock::now(); return PVR_ERROR_NO_ERROR; } @@ -1383,7 +1380,7 @@ PVR_ERROR cPVRClientMediaPortal::GetTimers(kodi::addon::PVRTimersResultSet& resu } } - if ( P8PLATFORM::GetTimeMs() > m_iLastRecordingUpdate + 15000) + if ( std::chrono::system_clock::now() > m_iLastRecordingUpdate + std::chrono::milliseconds(15000)) { kodi::addon::CInstancePVRClient::TriggerRecordingUpdate(); } diff --git a/src/pvrclient-mediaportal.h b/src/pvrclient-mediaportal.h index 3087634..e5da832 100644 --- a/src/pvrclient-mediaportal.h +++ b/src/pvrclient-mediaportal.h @@ -7,6 +7,10 @@ #pragma once +#include +#include +#include +#include #include /* Master defines for client control */ @@ -17,8 +21,6 @@ #include "Cards.h" #include "epg.h" #include "channels.h" -#include "p8-platform/threads/mutex.h" -#include "p8-platform/threads/threads.h" /* Use a forward declaration here. Including RTSPClient.h via TSReader.h at this point gives compile errors */ namespace MPTV @@ -28,9 +30,7 @@ namespace MPTV class cRecording; class ATTRIBUTE_HIDDEN cPVRClientMediaPortal - : public kodi::addon::CInstancePVRClient, - public P8PLATFORM::PreventCopy, - public P8PLATFORM::CThread + : public kodi::addon::CInstancePVRClient { public: /* Class interface */ @@ -110,7 +110,7 @@ class ATTRIBUTE_HIDDEN cPVRClientMediaPortal private: /* TVServerKodi Listening Thread */ - void* Process(void); + void Process(); PVR_CONNECTION_STATE Connect(bool updateConnectionState = true); void LoadGenreTable(void); @@ -134,9 +134,9 @@ class ATTRIBUTE_HIDDEN cPVRClientMediaPortal time_t m_BackendTime; CCards m_cCards; CGenreTable* m_genretable; - P8PLATFORM::CMutex m_mutex; - P8PLATFORM::CMutex m_connectionMutex; - int64_t m_iLastRecordingUpdate; + std::mutex m_mutex; + std::mutex m_connectionMutex; + std::chrono::system_clock::time_point m_iLastRecordingUpdate; MPTV::CTsReader* m_tsreader; std::map m_channels; int m_signalStateCounter; @@ -145,6 +145,9 @@ class ATTRIBUTE_HIDDEN cPVRClientMediaPortal cRecording* m_lastSelectedRecording; + std::atomic m_running = {false}; + std::thread m_thread; + //Used for TV Server communication: std::string SendCommand(const char* command); std::string SendCommand(const std::string& command);