From b367e44169804c27de50047c079b1b3a5c555c52 Mon Sep 17 00:00:00 2001 From: janbar Date: Sun, 16 Nov 2014 11:47:56 +0100 Subject: [PATCH] [pvr.mythtv] Bump version 1.10.1 - Add episode info (subtitle) to EPG title - Adding WSAPI Security Pin parameter - Clean FileOps cache by max age - Improves loading of resources - Adding new settings to handle icons visibility - fix typo --- addons/pvr.mythtv/addon/addon.xml.in | 2 +- addons/pvr.mythtv/addon/changelog.txt | 12 +- addons/pvr.mythtv/addon/resources/channel.png | Bin 0 -> 6965 bytes .../resources/language/English/strings.po | 16 +- .../language/French (Canada)/strings.po | 4 + .../resources/language/French/strings.po | 12 + .../pvr.mythtv/addon/resources/recording.png | Bin 0 -> 6976 bytes .../pvr.mythtv/addon/resources/settings.xml | 3 + addons/pvr.mythtv/src/avinfo.cpp | 2 +- addons/pvr.mythtv/src/client.cpp | 51 ++++ addons/pvr.mythtv/src/client.h | 6 + .../src/cppmyth/MythScheduleManager.cpp | 6 +- .../src/cppmyth/MythScheduleManager.h | 4 +- addons/pvr.mythtv/src/demux.cpp | 6 +- addons/pvr.mythtv/src/demuxer/tsDemuxer.h | 2 +- addons/pvr.mythtv/src/fileOps.cpp | 116 ++++++++- addons/pvr.mythtv/src/fileOps.h | 14 +- addons/pvr.mythtv/src/pvrclient-mythtv.cpp | 241 ++++++++++-------- addons/pvr.mythtv/src/pvrclient-mythtv.h | 28 +- 19 files changed, 375 insertions(+), 150 deletions(-) create mode 100644 addons/pvr.mythtv/addon/resources/channel.png create mode 100644 addons/pvr.mythtv/addon/resources/recording.png diff --git a/addons/pvr.mythtv/addon/addon.xml.in b/addons/pvr.mythtv/addon/addon.xml.in index e77e2f578..24d91788e 100644 --- a/addons/pvr.mythtv/addon/addon.xml.in +++ b/addons/pvr.mythtv/addon/addon.xml.in @@ -1,7 +1,7 @@ diff --git a/addons/pvr.mythtv/addon/changelog.txt b/addons/pvr.mythtv/addon/changelog.txt index 40a3d0d99..7d07fc673 100644 --- a/addons/pvr.mythtv/addon/changelog.txt +++ b/addons/pvr.mythtv/addon/changelog.txt @@ -1,4 +1,14 @@ -v1.9.29 +v1.10.1 +- Options to disable channel icons and recordings or fanart images + +v1.10.0 +- jansson 2.7: fix compilation on ios8/arm64 +- Cleaned cache by max age +- Improves loading of channels and recordings +- Adding WS API Security Pin parameter +- Adding episode info (subtitle) to EPG title + +v1.29.0 - fixed resource leak on file cache failure v1.9.28 diff --git a/addons/pvr.mythtv/addon/resources/channel.png b/addons/pvr.mythtv/addon/resources/channel.png new file mode 100644 index 0000000000000000000000000000000000000000..f3968f91f805e5ee63336a5858f117655c3055ba GIT binary patch literal 6965 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 MVq{@hVc-(;KYi0Qc>n+a literal 0 HcmV?d00001 diff --git a/addons/pvr.mythtv/addon/resources/language/English/strings.po b/addons/pvr.mythtv/addon/resources/language/English/strings.po index b2946fff0..0e1413abe 100644 --- a/addons/pvr.mythtv/addon/resources/language/English/strings.po +++ b/addons/pvr.mythtv/addon/resources/language/English/strings.po @@ -73,7 +73,11 @@ msgctxt "#30013" msgid "MythTV Backend Port for API services" msgstr "" -#empty strings from id 30014 to 30018 +msgctxt "#30014" +msgid "MythTV Security Pin for API services" +msgstr "" + +#empty strings from id 30015 to 30018 msgctxt "#30019" msgid "General" @@ -189,7 +193,15 @@ msgctxt "#30062" msgid "Block backend shutdown" msgstr "" -#empty strings from id 30063 to 30099 +msgctxt "#30063" +msgid "Enable channel icons" +msgstr "" + +msgctxt "#30064" +msgid "Enable recording fanart/thumbnails" +msgstr "" + +#empty strings from id 30065 to 30099 # Systeminformation labels msgctxt "#30100" diff --git a/addons/pvr.mythtv/addon/resources/language/French (Canada)/strings.po b/addons/pvr.mythtv/addon/resources/language/French (Canada)/strings.po index fb8d66c60..f65215518 100644 --- a/addons/pvr.mythtv/addon/resources/language/French (Canada)/strings.po +++ b/addons/pvr.mythtv/addon/resources/language/French (Canada)/strings.po @@ -72,6 +72,10 @@ msgctxt "#30013" msgid "MythTV Backend Port for API services" msgstr "Port du dorsal MythTV pour les services API" +msgctxt "#30014" +msgid "MythTV Security Pin for API services" +msgstr "Code PIN de sécurité pour les services API" + msgctxt "#30019" msgid "General" msgstr "Général" diff --git a/addons/pvr.mythtv/addon/resources/language/French/strings.po b/addons/pvr.mythtv/addon/resources/language/French/strings.po index 4c6993d70..484763f0b 100644 --- a/addons/pvr.mythtv/addon/resources/language/French/strings.po +++ b/addons/pvr.mythtv/addon/resources/language/French/strings.po @@ -72,6 +72,10 @@ msgctxt "#30013" msgid "MythTV Backend Port for API services" msgstr "Port du serveur MythTV pour les services API" +msgctxt "#30014" +msgid "MythTV Security Pin for API services" +msgstr "Code PIN de sécurité pour les services API" + msgctxt "#30019" msgid "General" msgstr "Général" @@ -180,6 +184,14 @@ msgctxt "#30062" msgid "Block backend shutdown" msgstr "Bloquer l'arrêt du serveur" +msgctxt "#30063" +msgid "Enable channel icons" +msgstr "Afficher l'icône des chaînes" + +msgctxt "#30064" +msgid "Enable recording fanart/thumbnails" +msgstr "Afficher la vignette des enregistrements" + msgctxt "#30100" msgid "Protocol version: %i - Database version: %i" msgstr "Version du protocole: %i - Version de la base de données: %i" diff --git a/addons/pvr.mythtv/addon/resources/recording.png b/addons/pvr.mythtv/addon/resources/recording.png new file mode 100644 index 0000000000000000000000000000000000000000..49233317e0268dcc20405e61db4086602e4f4486 GIT binary patch literal 6976 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 literal 0 HcmV?d00001 diff --git a/addons/pvr.mythtv/addon/resources/settings.xml b/addons/pvr.mythtv/addon/resources/settings.xml index 6da293b14..425fdc381 100644 --- a/addons/pvr.mythtv/addon/resources/settings.xml +++ b/addons/pvr.mythtv/addon/resources/settings.xml @@ -4,6 +4,7 @@ + @@ -29,5 +30,7 @@ + + diff --git a/addons/pvr.mythtv/src/avinfo.cpp b/addons/pvr.mythtv/src/avinfo.cpp index cb8611f8a..b387d22e3 100644 --- a/addons/pvr.mythtv/src/avinfo.cpp +++ b/addons/pvr.mythtv/src/avinfo.cpp @@ -20,7 +20,7 @@ * */ -#include "xbmc_codec_types.h" +#include #include "avinfo.h" #include "client.h" diff --git a/addons/pvr.mythtv/src/client.cpp b/addons/pvr.mythtv/src/client.cpp index 8e4032e50..cbef59a5b 100644 --- a/addons/pvr.mythtv/src/client.cpp +++ b/addons/pvr.mythtv/src/client.cpp @@ -35,10 +35,13 @@ std::string g_szMythHostname = DEFAULT_HOST; ///< std::string g_szMythHostEther = ""; ///< The Host MAC address of the mythtv server int g_iProtoPort = DEFAULT_PROTO_PORT; ///< The mythtv protocol port (default is 6543) int g_iWSApiPort = DEFAULT_WSAPI_PORT; ///< The mythtv sevice API port (default is 6544) +std::string g_szWSSecurityPin = DEFAULT_WSAPI_SECURITY_PIN; ///< The default security pin for the mythtv wsapi bool g_bExtraDebug = DEFAULT_EXTRA_DEBUG; ///< Output extensive debug information to the log bool g_bLiveTV = DEFAULT_LIVETV; ///< LiveTV support (or recordings only) bool g_bLiveTVPriority = DEFAULT_LIVETV_PRIORITY; ///< MythTV Backend setting to allow live TV to move scheduled shows int g_iLiveTVConflictStrategy = DEFAULT_LIVETV_CONFLICT_STRATEGY; ///< Conflict resolving strategy (0= +bool g_bChannelIcons = DEFAULT_CHANNEL_ICONS; ///< Load Channel Icons +bool g_bRecordingIcons = DEFAULT_RECORDING_ICONS; ///< Load Recording Icons (Fanart/Thumbnails) int g_iRecTemplateType = DEFAULT_RECORD_TEMPLATE; ///< Template type for new record (0=Internal, 1=MythTV) bool g_bRecAutoMetadata = true; bool g_bRecAutoCommFlag = false; @@ -170,6 +173,17 @@ ADDON_STATUS ADDON_Create(void *hdl, void *props) g_iWSApiPort = DEFAULT_WSAPI_PORT; } + /* Read setting "wssecuritypin" from settings.xml */ + if (XBMC->GetSetting("wssecuritypin", buffer)) + g_szWSSecurityPin = buffer; + else + { + /* If setting is unknown fallback to defaults */ + XBMC->Log(LOG_ERROR, "Couldn't get 'wssecuritypin' setting, falling back to '%s' as default", DEFAULT_WSAPI_SECURITY_PIN); + g_szWSSecurityPin = DEFAULT_WSAPI_SECURITY_PIN; + } + buffer[0] = 0; + /* Read setting "extradebug" from settings.xml */ if (!XBMC->GetSetting("extradebug", &g_bExtraDebug)) { @@ -271,6 +285,22 @@ ADDON_STATUS ADDON_Create(void *hdl, void *props) g_bBlockMythShutdown = DEFAULT_BLOCK_SHUTDOWN; } + /* Read setting "channel_icons" from settings.xml */ + if (!XBMC->GetSetting("channel_icons", &g_bChannelIcons)) + { + /* If setting is unknown fallback to defaults */ + XBMC->Log(LOG_ERROR, "Couldn't get 'channel_icons' setting, falling back to '%b' as default", DEFAULT_CHANNEL_ICONS); + g_bChannelIcons = DEFAULT_CHANNEL_ICONS; + } + + /* Read setting "recording_icons" from settings.xml */ + if (!XBMC->GetSetting("recording_icons", &g_bRecordingIcons)) + { + /* If setting is unknown fallback to defaults */ + XBMC->Log(LOG_ERROR, "Couldn't get 'recording_icons' setting, falling back to '%b' as default", DEFAULT_RECORDING_ICONS); + g_bRecordingIcons = DEFAULT_RECORDING_ICONS; + } + free (buffer); XBMC->Log(LOG_DEBUG, "Loading settings...done"); @@ -446,12 +476,33 @@ ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue) return ADDON_STATUS_NEED_RESTART; } } + else if (str == "wssecuritypin") + { + std::string tmp_sWSSecurityPin; + XBMC->Log(LOG_INFO, "Changed Setting 'wssecuritypin' from %s to %s", g_szWSSecurityPin.c_str(), (const char*)settingValue); + tmp_sWSSecurityPin = g_szWSSecurityPin; + g_szWSSecurityPin = (const char*)settingValue; + if (tmp_sWSSecurityPin != g_szWSSecurityPin) + return ADDON_STATUS_NEED_RESTART; + } else if (str == "demuxing") { XBMC->Log(LOG_INFO, "Changed Setting 'demuxing' from %u to %u", g_bDemuxing, *(bool*)settingValue); if (g_bDemuxing != *(bool*)settingValue) return ADDON_STATUS_NEED_RESTART; } + else if (str == "channel_icons") + { + XBMC->Log(LOG_INFO, "Changed Setting 'channel_icons' from %u to %u", g_bChannelIcons, *(bool*)settingValue); + if (g_bChannelIcons != *(bool*)settingValue) + return ADDON_STATUS_NEED_RESTART; + } + else if (str == "recording_icons") + { + XBMC->Log(LOG_INFO, "Changed Setting 'recording_icons' from %u to %u", g_bRecordingIcons, *(bool*)settingValue); + if (g_bRecordingIcons != *(bool*)settingValue) + return ADDON_STATUS_NEED_RESTART; + } else if (str == "host_ether") { XBMC->Log(LOG_INFO, "Changed Setting 'host_ether' from %s to %s", g_szMythHostEther.c_str(), (const char*)settingValue); diff --git a/addons/pvr.mythtv/src/client.h b/addons/pvr.mythtv/src/client.h index c3e45d347..fb2106cd6 100644 --- a/addons/pvr.mythtv/src/client.h +++ b/addons/pvr.mythtv/src/client.h @@ -41,6 +41,9 @@ #define DEFAULT_LIVETV true #define DEFAULT_PROTO_PORT 6543 #define DEFAULT_WSAPI_PORT 6544 +#define DEFAULT_WSAPI_SECURITY_PIN "0000" +#define DEFAULT_CHANNEL_ICONS true +#define DEFAULT_RECORDING_ICONS true #define DEFAULT_RECORD_TEMPLATE 1 #define SUBTITLE_SEPARATOR " - " @@ -84,10 +87,13 @@ extern std::string g_szMythHostname; ///< The Host name or IP of the extern std::string g_szMythHostEther; ///< The Host MAC address of the mythtv server extern int g_iProtoPort; ///< The mythtv protocol port (default is 6543) extern int g_iWSApiPort; ///< The mythtv service API port (default is 6544) +extern std::string g_szWSSecurityPin; ///< The default security pin for the mythtv wsapi extern bool g_bExtraDebug; ///< Debug logging extern bool g_bLiveTV; ///< LiveTV support (or recordings only) extern bool g_bLiveTVPriority; ///< MythTV Backend setting to allow live TV to move scheduled shows extern int g_iLiveTVConflictStrategy; ///< Live TV conflict resolving strategy (0=Has later, 1=Stop TV, 2=Cancel recording) +extern bool g_bChannelIcons; ///< Load Channel Icons +extern bool g_bRecordingIcons; ///< Load Recording Icons (Fanart/Thumbnails) extern int g_iRecTemplateType; ///< Template type for new record (0=Internal, 1=MythTV) ///* Internal Record template */ extern bool g_bRecAutoMetadata; diff --git a/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.cpp b/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.cpp index 645a092e5..73cd8aaa7 100644 --- a/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.cpp +++ b/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.cpp @@ -105,14 +105,14 @@ bool MythRecordingRuleNode::IsInactiveRule() const //// MythScheduleManager //// -MythScheduleManager::MythScheduleManager(const std::string& server, unsigned protoPort, unsigned wsapiPort) +MythScheduleManager::MythScheduleManager(const std::string& server, unsigned protoPort, unsigned wsapiPort, const std::string& wsapiSecurityPin) : m_lock() , m_control(NULL) , m_protoVersion(0) , m_versionHelper(NULL) , m_showNotRecording(false) { - m_control = new Myth::Control(server, protoPort, wsapiPort); + m_control = new Myth::Control(server, protoPort, wsapiPort, wsapiSecurityPin); this->Update(); } @@ -140,7 +140,7 @@ void MythScheduleManager::Setup() } } -uint32_t MythScheduleManager::MakeIndex(ScheduledPtr scheduled) const +uint32_t MythScheduleManager::MakeIndex(const ScheduledPtr &scheduled) const { // Recordings must keep same identifier even after refreshing cache (cf Update). // Numeric hash of UID is used to make the constant numeric identifier. diff --git a/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.h b/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.h index 12bdbeed1..dffa78b13 100644 --- a/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.h +++ b/addons/pvr.mythtv/src/cppmyth/MythScheduleManager.h @@ -78,7 +78,7 @@ class MythScheduleManager MSM_ERROR_SUCCESS = 1 }; - MythScheduleManager(const std::string& server, unsigned protoPort, unsigned wsapiPort); + MythScheduleManager(const std::string& server, unsigned protoPort, unsigned wsapiPort, const std::string& wsapiSecurityPin); ~MythScheduleManager(); // Called by GetTimers @@ -139,7 +139,7 @@ class MythScheduleManager VersionHelper *m_versionHelper; void Setup(); - uint32_t MakeIndex(ScheduledPtr scheduled) const; + uint32_t MakeIndex(const ScheduledPtr &scheduled) const; // The list of rule nodes typedef std::list NodeList; diff --git a/addons/pvr.mythtv/src/demux.cpp b/addons/pvr.mythtv/src/demux.cpp index 1beb8c2bc..f0e80d059 100644 --- a/addons/pvr.mythtv/src/demux.cpp +++ b/addons/pvr.mythtv/src/demux.cpp @@ -20,10 +20,10 @@ * */ -#include "platform/os.h" +#include -#include "libXBMC_pvr.h" -#include "xbmc_codec_types.h" +#include +#include #include "demux.h" #include "client.h" diff --git a/addons/pvr.mythtv/src/demuxer/tsDemuxer.h b/addons/pvr.mythtv/src/demuxer/tsDemuxer.h index 0c06f05a8..5be959bbe 100644 --- a/addons/pvr.mythtv/src/demuxer/tsDemuxer.h +++ b/addons/pvr.mythtv/src/demuxer/tsDemuxer.h @@ -25,7 +25,7 @@ #include "common.h" #include "tsPacket.h" #include "elementaryStream.h" -#include "platform/threads/mutex.h" +#include #include #include diff --git a/addons/pvr.mythtv/src/fileOps.cpp b/addons/pvr.mythtv/src/fileOps.cpp index 32bf86276..5c4488318 100644 --- a/addons/pvr.mythtv/src/fileOps.cpp +++ b/addons/pvr.mythtv/src/fileOps.cpp @@ -27,31 +27,35 @@ #include #include -#define FILEOPS_STREAM_BUFFER_SIZE 32000 // Buffer size to download artworks +#define FILEOPS_STREAM_BUFFER_SIZE 32000 // Buffer size to download artworks +#define FILEOPS_STAMP_FILENAME "stamp" // Base name for cache stamp file +#define FILEOPS_NOSTAMP (time_t)(-1) +#define FILEOPS_CHANNEL_DUMMY_ICON "channel.png" +#define FILEOPS_RECORDING_DUMMY_ICON "recording.png" using namespace ADDON; using namespace PLATFORM; -FileOps::FileOps(const std::string& server, unsigned wsapiport) +FileOps::FileOps(FileConsumer *consumer, const std::string& server, unsigned wsapiport, const std::string& wsapiSecurityPin) : CThread() +, m_consumer(consumer) , m_wsapi(NULL) , m_localBasePath(g_szUserPath.c_str()) +, m_localBaseStampName() +, m_localBaseStamp(FILEOPS_NOSTAMP) , m_queueContent() , m_jobQueue() { - m_localBasePath = m_localBasePath + "cache" + PATH_SEPARATOR_CHAR; - - // Create the cache directories if it does not exist - if (!XBMC->DirectoryExists(m_localBasePath.c_str()) && !XBMC->CreateDirectory(m_localBasePath.c_str())) - XBMC->Log(LOG_ERROR,"%s - Failed to create cache directory %s", __FUNCTION__, m_localBasePath.c_str()); - - m_wsapi = new Myth::WSAPI(server, wsapiport); + // Initialize base path for cache directories + m_localBasePath.append("cache").append(PATH_SEPARATOR_STRING); + m_localBaseStampName.append(m_localBasePath).append(FILEOPS_STAMP_FILENAME); + InitBasePath(); + m_wsapi = new Myth::WSAPI(server, wsapiport, wsapiSecurityPin); CreateThread(); } FileOps::~FileOps() { - CleanCache(); StopThread(-1); // Set stopping. don't wait as we need to signal the thread first m_queueContent.Signal(); StopThread(); // Wait for thread to stop @@ -62,6 +66,8 @@ std::string FileOps::GetChannelIconPath(const MythChannel& channel) { if (channel.IsNull() || channel.Icon().empty()) return ""; + if (!g_bChannelIcons) + return g_szClientPath + PATH_SEPARATOR_STRING + "resources" + PATH_SEPARATOR_STRING + FILEOPS_CHANNEL_DUMMY_ICON; std::string uid = Myth::IdToString(channel.ID()); if (g_bExtraDebug) @@ -92,6 +98,8 @@ std::string FileOps::GetPreviewIconPath(const MythProgramInfo& recording) { if (recording.IsNull()) return ""; + if (!g_bRecordingIcons) + return g_szClientPath + PATH_SEPARATOR_STRING + "resources" + PATH_SEPARATOR_STRING + FILEOPS_RECORDING_DUMMY_ICON; std::string uid = recording.UID(); if (g_bExtraDebug) @@ -122,6 +130,15 @@ std::string FileOps::GetArtworkPath(const MythProgramInfo& recording, FileType t { if (recording.IsNull()) return ""; + if (!g_bRecordingIcons) + switch (type) + { + case FileTypePreview: + case FileTypeCoverart: + return g_szClientPath + PATH_SEPARATOR_STRING + "resources" + PATH_SEPARATOR_STRING + FILEOPS_RECORDING_DUMMY_ICON; + default: + return ""; + } std::string uid = recording.UID(); if (g_bExtraDebug) @@ -184,6 +201,16 @@ void *FileOps::Process() // For caching new files, the tread is woken up by m_queueContent.Signal(); m_queueContent.Wait(c_timeoutProcess * 1000); + if (m_jobQueue.empty() && !IsStopped()) + { + if (m_localBaseStamp != FILEOPS_NOSTAMP && difftime(time(NULL), m_localBaseStamp) >= c_cacheMaxAge) + { + CleanCache(); + if (m_consumer) + m_consumer->HandleCleanedCache(); + } + } + while (!m_jobQueue.empty() && !IsStopped()) { CLockObject lock(m_lock); @@ -342,6 +369,70 @@ bool FileOps::CacheFile(void *file, Myth::Stream *source) return true; } +static void WriteCacheStamp(const char *path, time_t ts) +{ + void * hdl = XBMC->OpenFileForWrite(path, true); + if (hdl == NULL) + { + XBMC->Log(LOG_ERROR,"%s: Write stamp file %s failed", __FUNCTION__, path); + return; + } + std::string now(Myth::TimeToString(ts, true)); + XBMC->WriteFile(hdl, now.c_str(), now.length()); + XBMC->CloseFile(hdl); +} + +static time_t ReadCacheStamp(const char *path) +{ + time_t ts = FILEOPS_NOSTAMP; + char buf[21]; // Time string as ISO-8601/UTC: %y-%m-%d"T"%H:%M:%S"Z" + memset(buf, 0, sizeof(buf)); + void * hdl = XBMC->OpenFile(path, 0); + if (hdl == NULL) + { + XBMC->Log(LOG_ERROR,"%s: Read stamp file %s failed", __FUNCTION__, path); + // Try write a new one + ts = time(NULL); + WriteCacheStamp(path, ts); + return ts; + } + if (XBMC->ReadFile(hdl, (void*)buf, (int64_t)(sizeof(buf) - 1))) + ts = Myth::StringToTime(buf); // It returns FILEOPS_NOSTAMP for invalid buf + XBMC->CloseFile(hdl); + // If stamp is invalid we overwrite it + if (ts == FILEOPS_NOSTAMP) + { + XBMC->Log(LOG_ERROR,"%s: Bad stamp string '%s'", __FUNCTION__, buf); + ts = time(NULL); + WriteCacheStamp(path, ts); + } + return ts; +} + +void FileOps::InitBasePath() +{ + XBMC->Log(LOG_DEBUG, "%s: Configure cache directory %s", __FUNCTION__, m_localBasePath.c_str()); + + CLockObject lock(m_lock); + + // Create the cache directories if it does not exist + if (!XBMC->DirectoryExists(m_localBasePath.c_str()) && !XBMC->CreateDirectory(m_localBasePath.c_str())) + { + XBMC->Log(LOG_ERROR,"%s: Failed to create cache directory %s", __FUNCTION__, m_localBasePath.c_str()); + return; + } + if (!XBMC->FileExists(m_localBaseStampName.c_str(), false)) + { + m_localBaseStamp = time(NULL); + WriteCacheStamp(m_localBaseStampName.c_str(), m_localBaseStamp); + return; + } + m_localBaseStamp = ReadCacheStamp(m_localBaseStampName.c_str()); + XBMC->Log(LOG_DEBUG,"%s: Cache stamp is %s", __FUNCTION__, ctime(&m_localBaseStamp)); + if (difftime(time(NULL), m_localBaseStamp) >= c_cacheMaxAge) + CleanCache(); +} + void FileOps::CleanCache() { // Currently XBMC's addon lib doesn't provide a way to list files in a directory. @@ -375,7 +466,10 @@ void FileOps::CleanCache() m_preview.clear(); m_artworks.clear(); - XBMC->Log(LOG_DEBUG, "%s: Cleaned cache %s", __FUNCTION__, m_localBasePath.c_str()); + // Reset stamp file + m_localBaseStamp = time(NULL); + WriteCacheStamp(m_localBaseStampName.c_str(), m_localBaseStamp); + XBMC->Log(LOG_DEBUG, "%s: New cache stamp is %s", __FUNCTION__, ctime(&m_localBaseStamp)); } std::string FileOps::GetFileName(const std::string& path, char separator) diff --git a/addons/pvr.mythtv/src/fileOps.h b/addons/pvr.mythtv/src/fileOps.h index 00e0c0075..9fe83d4cb 100644 --- a/addons/pvr.mythtv/src/fileOps.h +++ b/addons/pvr.mythtv/src/fileOps.h @@ -32,6 +32,13 @@ #include #include +class FileConsumer +{ +public: + virtual ~FileConsumer() {}; + virtual void HandleCleanedCache() = 0; +}; + class FileOps : public PLATFORM::CThread { public: @@ -86,8 +93,9 @@ class FileOps : public PLATFORM::CThread static const int c_timeoutProcess = 10; // Wake the thread every 10s static const int c_maximumAttemptsOnReadError = 3; // Retry when reading file failed + static const int c_cacheMaxAge = 2635200; // Clean cache every 2635200s (30.5 days) - FileOps(const std::string& server, unsigned wsapiport); + FileOps(FileConsumer *consumer, const std::string& server, unsigned wsapiport, const std::string& wsapiSecurityPin); virtual ~FileOps(); std::string GetChannelIconPath(const MythChannel& channel); @@ -103,6 +111,7 @@ class FileOps : public PLATFORM::CThread bool CheckFile(const std::string &localFilename); void *OpenFile(const std::string &localFilename); bool CacheFile(void *file, Myth::Stream *source); + void InitBasePath(); void CleanCache(); static std::string GetFileName(const std::string& path, char separator = PATH_SEPARATOR_CHAR); @@ -112,8 +121,11 @@ class FileOps : public PLATFORM::CThread std::map m_preview; std::map, std::string> m_artworks; + FileConsumer *m_consumer; Myth::WSAPI *m_wsapi; std::string m_localBasePath; + std::string m_localBaseStampName; + time_t m_localBaseStamp; struct JobItem { JobItem(const std::string& localFilename, FileType type, const MythProgramInfo& recording) diff --git a/addons/pvr.mythtv/src/pvrclient-mythtv.cpp b/addons/pvr.mythtv/src/pvrclient-mythtv.cpp index 520e33a3d..4fed404a2 100644 --- a/addons/pvr.mythtv/src/pvrclient-mythtv.cpp +++ b/addons/pvr.mythtv/src/pvrclient-mythtv.cpp @@ -42,8 +42,6 @@ PVRClientMythTV::PVRClientMythTV() , m_powerSaving(false) , m_fileOps(NULL) , m_scheduleManager(NULL) -, m_categories() -, m_channelGroups() , m_demux(NULL) , m_recordingChangePinCount(0) { @@ -102,7 +100,7 @@ void PVRClientMythTV::SetDebug() bool PVRClientMythTV::Connect() { SetDebug(); - m_control = new Myth::Control(g_szMythHostname, g_iProtoPort, g_iWSApiPort, g_bBlockMythShutdown); + m_control = new Myth::Control(g_szMythHostname, g_iProtoPort, g_iWSApiPort, g_szWSSecurityPin, g_bBlockMythShutdown); if (!m_control->IsOpen()) { SAFE_DELETE(m_control); @@ -115,7 +113,7 @@ bool PVRClientMythTV::Connect() if (!m_control->CheckService()) { SAFE_DELETE(m_control); - XBMC->Log(LOG_ERROR,"Failed to connect to MythTV backend on %s:%d", g_szMythHostname.c_str(), g_iWSApiPort); + XBMC->Log(LOG_ERROR,"Failed to connect to MythTV backend on %s:%d with pin %s", g_szMythHostname.c_str(), g_iWSApiPort, g_szWSSecurityPin.c_str()); return false; } @@ -129,10 +127,10 @@ bool PVRClientMythTV::Connect() m_eventHandler->SubscribeForEvent(m_eventSubscriberId, Myth::EVENT_RECORDING_LIST_CHANGE); // Create schedule manager - m_scheduleManager = new MythScheduleManager(g_szMythHostname, g_iProtoPort, g_iWSApiPort); + m_scheduleManager = new MythScheduleManager(g_szMythHostname, g_iProtoPort, g_iWSApiPort, g_szWSSecurityPin); // Create file operation helper (image caching) - m_fileOps = new FileOps(g_szMythHostname, g_iWSApiPort); + m_fileOps = new FileOps(this, g_szMythHostname, g_iWSApiPort, g_szWSSecurityPin); // Start event handler m_eventHandler->Start(); @@ -257,6 +255,7 @@ void PVRClientMythTV::HandleBackendMessage(const Myth::EventMessage& msg) XBMC->QueueNotification(QUEUE_INFO, XBMC->GetLocalizedString(30303)); // Connection to MythTV restored } // Refreshing all + HandleChannelChange(); HandleScheduleChange(); HandleRecordingListChange(Myth::EventMessage()); } @@ -272,6 +271,13 @@ void PVRClientMythTV::HandleBackendMessage(const Myth::EventMessage& msg) } } +void PVRClientMythTV::HandleChannelChange() +{ + FillChannelsAndChannelGroups(); + PVR->TriggerChannelUpdate(); + PVR->TriggerChannelGroupsUpdate(); +} + void PVRClientMythTV::HandleScheduleChange() { if (!m_scheduleManager) @@ -416,6 +422,11 @@ void PVRClientMythTV::RunHouseKeeping() } } +void PVRClientMythTV::HandleCleanedCache() +{ + PVR->TriggerRecordingUpdate(); +} + PVR_ERROR PVRClientMythTV::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd) { if (g_bExtraDebug) @@ -438,7 +449,8 @@ PVR_ERROR PVRClientMythTV::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANN // EPG_TAG expects strings as char* and not as copies (like the other PVR types). // Therefore we have to make sure that we don't pass invalid (freed) memory to TransferEpgEntry. // In particular we have to use local variables and must not pass returned string values directly. - tag.strTitle = it->second->title.c_str(); + std::string epgTitle = MakeProgramTitle(it->second->title, it->second->subTitle); + tag.strTitle = epgTitle.c_str(); tag.strPlot = it->second->description.c_str(); tag.strGenreDescription = it->second->category.c_str(); tag.iUniqueBroadcastId = MakeBroadcastID(it->second->channel.chanId, it->first); @@ -472,9 +484,8 @@ int PVRClientMythTV::GetNumChannels() if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); - LoadChannelsAndChannelGroups(); - - return m_channelsById.size(); + CLockObject lock(m_channelsLock); + return m_PVRChannels.size(); } PVR_ERROR PVRClientMythTV::GetChannels(ADDON_HANDLE handle, bool bRadio) @@ -482,50 +493,39 @@ PVR_ERROR PVRClientMythTV::GetChannels(ADDON_HANDLE handle, bool bRadio) if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s: radio: %s", __FUNCTION__, (bRadio ? "true" : "false")); - LoadChannelsAndChannelGroups(); - m_PVRChannelUidById.clear(); - - // Create a map<(sourceid, channum, callsign), chanid> to merge channels with same channum and callsign within same group - std::map >, unsigned int> channelIdentifiers; + CLockObject lock(m_channelsLock); + // Load channels list + if (m_PVRChannels.empty()) + FillChannelsAndChannelGroups(); // Transfer channels of the requested type (radio / tv) - for (ChannelIdMap::iterator it = m_channelsById.begin(); it != m_channelsById.end(); ++it) + for (PVRChannelList::const_iterator it = m_PVRChannels.begin(); it != m_PVRChannels.end(); ++it) { - if (it->second.IsRadio() == bRadio && !it->second.IsNull()) + if (it->bIsRadio == bRadio) { - // Skip channels with same channum and callsign - std::pair > channelIdentifier = std::make_pair(it->second.SourceID(), std::make_pair(it->second.Number(), it->second.Callsign())); - std::map >, unsigned int>::iterator itm = channelIdentifiers.find(channelIdentifier); - if (itm != channelIdentifiers.end()) + ChannelIdMap::const_iterator itm = m_channelsById.find(it->iUniqueId); + if (itm != m_channelsById.end() && !itm->second.IsNull()) { - XBMC->Log(LOG_DEBUG, "%s: skipping channel: %d", __FUNCTION__, it->second.ID()); - // Map channel with merged channel - m_PVRChannelUidById.insert(std::make_pair(it->first, itm->second)); - continue; - } - channelIdentifiers.insert(std::make_pair(channelIdentifier, it->first)); - // Map channel to itself - m_PVRChannelUidById.insert(std::make_pair(it->first, it->first)); + PVR_CHANNEL tag; + memset(&tag, 0, sizeof(PVR_CHANNEL)); - PVR_CHANNEL tag; - memset(&tag, 0, sizeof(PVR_CHANNEL)); + tag.iUniqueId = itm->first; + tag.iChannelNumber = itm->second.NumberMajor(); + tag.iSubChannelNumber = itm->second.NumberMinor(); + PVR_STRCPY(tag.strChannelName, itm->second.Name().c_str()); + tag.bIsHidden = !itm->second.Visible(); + tag.bIsRadio = itm->second.IsRadio(); - tag.iUniqueId = it->first; - tag.iChannelNumber = it->second.NumberMajor(); - tag.iSubChannelNumber = it->second.NumberMinor(); - PVR_STRCPY(tag.strChannelName, it->second.Name().c_str()); - tag.bIsHidden = !it->second.Visible(); - tag.bIsRadio = it->second.IsRadio(); + std::string icon = m_fileOps->GetChannelIconPath(itm->second); + PVR_STRCPY(tag.strIconPath, icon.c_str()); - std::string icon = m_fileOps->GetChannelIconPath(it->second); - PVR_STRCPY(tag.strIconPath, icon.c_str()); + // Unimplemented + PVR_STRCPY(tag.strStreamURL, ""); + PVR_STRCPY(tag.strInputFormat, ""); + tag.iEncryptionSystem = 0; - // Unimplemented - PVR_STRCPY(tag.strStreamURL, ""); - PVR_STRCPY(tag.strInputFormat, ""); - tag.iEncryptionSystem = 0; - - PVR->TransferChannelEntry(handle, &tag); + PVR->TransferChannelEntry(handle, &tag); + } } } @@ -540,9 +540,8 @@ int PVRClientMythTV::GetChannelGroupsAmount() if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); - LoadChannelsAndChannelGroups(); - - return m_channelGroups.size(); + CLockObject lock(m_channelsLock); + return m_PVRChannelGroups.size(); } PVR_ERROR PVRClientMythTV::GetChannelGroups(ADDON_HANDLE handle, bool bRadio) @@ -550,22 +549,21 @@ PVR_ERROR PVRClientMythTV::GetChannelGroups(ADDON_HANDLE handle, bool bRadio) if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s: radio: %s", __FUNCTION__, (bRadio ? "true" : "false")); - LoadChannelsAndChannelGroups(); + CLockObject lock(m_channelsLock); // Transfer channel groups of the given type (radio / tv) - for (ChannelGroupMap::iterator channelGroupsIt = m_channelGroups.begin(); channelGroupsIt != m_channelGroups.end(); ++channelGroupsIt) + for (PVRChannelGroupMap::iterator itg = m_PVRChannelGroups.begin(); itg != m_PVRChannelGroups.end(); ++itg) { PVR_CHANNEL_GROUP tag; memset(&tag, 0, sizeof(PVR_CHANNEL_GROUP)); - PVR_STRCPY(tag.strGroupName, channelGroupsIt->first.c_str()); + PVR_STRCPY(tag.strGroupName, itg->first.c_str()); tag.bIsRadio = bRadio; // Only add the group if we have at least one channel of the correct type - for (std::vector::iterator channelGroupIt = channelGroupsIt->second.begin(); channelGroupIt != channelGroupsIt->second.end(); ++channelGroupIt) + for (PVRChannelList::const_iterator itc = itg->second.begin(); itc != itg->second.end(); ++itc) { - ChannelIdMap::iterator channelIt = m_channelsById.find(*channelGroupIt); - if (channelIt != m_channelsById.end() && channelIt->second.IsRadio() == bRadio) + if (itc->bIsRadio == bRadio) { PVR->TransferChannelGroup(handle, &tag); break; @@ -584,10 +582,10 @@ PVR_ERROR PVRClientMythTV::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR if (g_bExtraDebug) XBMC->Log(LOG_DEBUG, "%s: group: %s", __FUNCTION__, group.strGroupName); - LoadChannelsAndChannelGroups(); + CLockObject lock(m_channelsLock); - ChannelGroupMap::iterator channelGroupsIt = m_channelGroups.find(group.strGroupName); - if (channelGroupsIt == m_channelGroups.end()) + PVRChannelGroupMap::iterator itg = m_PVRChannelGroups.find(group.strGroupName); + if (itg == m_PVRChannelGroups.end()) { XBMC->Log(LOG_ERROR,"%s: Channel group not found", __FUNCTION__); return PVR_ERROR_INVALID_PARAMETERS; @@ -595,16 +593,15 @@ PVR_ERROR PVRClientMythTV::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR // Transfer the channel group members for the requested group unsigned channelNumber = 0; - for (std::vector::iterator channelGroupIt = channelGroupsIt->second.begin(); channelGroupIt != channelGroupsIt->second.end(); ++channelGroupIt) + for (PVRChannelList::const_iterator itc = itg->second.begin(); itc != itg->second.end(); ++itc) { - ChannelIdMap::iterator channelIt = m_channelsById.find(*channelGroupIt); - if (channelIt != m_channelsById.end() && channelIt->second.IsRadio() == group.bIsRadio) + if (itc->bIsRadio == group.bIsRadio) { PVR_CHANNEL_GROUP_MEMBER tag; memset(&tag, 0, sizeof(PVR_CHANNEL_GROUP_MEMBER)); tag.iChannelNumber = ++channelNumber; - tag.iChannelUniqueId = (unsigned)FindPVRChannelUid(channelIt->second.ID()); + tag.iChannelUniqueId = itc->iUniqueId; PVR_STRCPY(tag.strGroupName, group.strGroupName); PVR->TransferChannelGroupMember(handle, &tag); } @@ -616,42 +613,82 @@ PVR_ERROR PVRClientMythTV::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR return PVR_ERROR_NO_ERROR; } -void PVRClientMythTV::LoadChannelsAndChannelGroups() +int PVRClientMythTV::FillChannelsAndChannelGroups() { - if (!m_channelsById.empty()) - return; + int count = 0; + XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); + + CLockObject lock(m_channelsLock); + m_PVRChannels.clear(); + m_PVRChannelGroups.clear(); + m_PVRChannelUidById.clear(); + m_channelsById.clear(); + + // Create a channels map to merge channels with same channum and callsign within same group + typedef std::pair chanuid_t; + typedef std::map mapuid_t; + mapuid_t channelIdentifiers; // For each source create a channels group Myth::VideoSourceListPtr sources = m_control->GetVideoSourceList(); for (Myth::VideoSourceList::iterator its = sources->begin(); its != sources->end(); ++its) { Myth::ChannelListPtr channels = m_control->GetChannelList((*its)->sourceId); - std::vector channelIDs; + PVRChannelList channelIDs; channelIDs.reserve(channels->size()); + channelIdentifiers.clear(); for (Myth::ChannelList::iterator itc = channels->begin(); itc != channels->end(); ++itc) { MythChannel channel((*itc)); - m_channelsById.insert(std::make_pair(channel.ID(), channel)); - m_channelsByNumber.insert(std::make_pair(channel.Number(), channel)); - channelIDs.push_back(channel.ID()); + PVRChannelItem item; + item.iUniqueId = channel.ID(); + item.bIsRadio = channel.IsRadio(); + m_channelsById.insert(std::make_pair(item.iUniqueId, channel)); + // Skip channels with same channum and callsign within group + chanuid_t channelIdentifier = std::make_pair(channel.Number(), channel.Callsign()); + mapuid_t::iterator itm = channelIdentifiers.find(channelIdentifier); + if (itm != channelIdentifiers.end()) + { + XBMC->Log(LOG_DEBUG, "%s: skipping channel: %d", __FUNCTION__, item.iUniqueId); + // Map channel with merged channel + m_PVRChannelUidById.insert(std::make_pair(item.iUniqueId, itm->second)); + } + else + { + // Add new channel in group + channelIDs.push_back(item); + channelIdentifiers.insert(std::make_pair(channelIdentifier, item.iUniqueId)); + // Map channel to itself + m_PVRChannelUidById.insert(std::make_pair(item.iUniqueId, item.iUniqueId)); + m_PVRChannels.push_back(item); + ++count; + } } - m_channelGroups.insert(std::make_pair((*its)->sourceName, channelIDs)); + m_PVRChannelGroups.insert(std::make_pair((*its)->sourceName, channelIDs)); } + + XBMC->Log(LOG_DEBUG, "%s: Loaded %d channel(s) %d group(s)", __FUNCTION__, count, (unsigned)m_PVRChannelGroups.size()); + return count; +} + +MythChannel PVRClientMythTV::FindChannel(uint32_t channelId) const +{ + CLockObject lock(m_channelsLock); + ChannelIdMap::const_iterator it = m_channelsById.find(channelId); + if (it != m_channelsById.end()) + return it->second; + return MythChannel(); } int PVRClientMythTV::FindPVRChannelUid(uint32_t channelId) const { + CLockObject lock(m_channelsLock); PVRChannelMap::const_iterator it = m_PVRChannelUidById.find(channelId); if (it != m_PVRChannelUidById.end()) return it->second; return -1; // PVR dummy channel UID } -void PVRClientMythTV::UpdateRecordings() -{ - PVR->TriggerRecordingUpdate(); -} - int PVRClientMythTV::GetRecordingsAmount(void) { int res = 0; @@ -660,16 +697,10 @@ int PVRClientMythTV::GetRecordingsAmount(void) CLockObject lock(m_recordingsLock); - if (m_recordings.empty()) - // Load recorings list - res = FillRecordings(); - else + for (ProgramInfoMap::iterator it = m_recordings.begin(); it != m_recordings.end(); ++it) { - for (ProgramInfoMap::iterator it = m_recordings.begin(); it != m_recordings.end(); ++it) - { - if (!it->second.IsNull() && it->second.IsVisible()) - res++; - } + if (!it->second.IsNull() && it->second.IsVisible()) + res++; } if (res == 0) XBMC->Log(LOG_INFO, "%s: No recording", __FUNCTION__); @@ -725,7 +756,7 @@ PVR_ERROR PVRClientMythTV::GetRecordings(ADDON_HANDLE handle) //@TODO: tag.iLastPlayedPosition std::string id = it->second.UID(); - std::string title = this->MakeProgramTitle(it->second.Title(), it->second.Subtitle()); + std::string title = MakeProgramTitle(it->second.Title(), it->second.Subtitle()); PVR_STRCPY(tag.strRecordingId, id.c_str()); PVR_STRCPY(tag.strTitle, title.c_str()); @@ -805,8 +836,7 @@ void PVRClientMythTV::ForceUpdateRecording(ProgramInfoMap::iterator it) int PVRClientMythTV::FillRecordings() { int count = 0; - if (g_bExtraDebug) - XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); + XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); // Check event connection if (!m_eventHandler->IsConnected()) @@ -823,6 +853,7 @@ int PVRClientMythTV::FillRecordings() if (prog.IsVisible() && !prog.IsLiveTV()) ++count; } + XBMC->Log(LOG_DEBUG, "%s: Loaded %d visible recording(s)", __FUNCTION__, count); return count; } @@ -1137,14 +1168,9 @@ PVR_ERROR PVRClientMythTV::GetRecordingEdl(const PVR_RECORDING &recording, PVR_E return PVR_ERROR_NO_ERROR; } -MythChannel PVRClientMythTV::FindRecordingChannel(const MythProgramInfo& programInfo) +MythChannel PVRClientMythTV::FindRecordingChannel(const MythProgramInfo& programInfo) const { - ChannelIdMap::iterator channelByIdIt = m_channelsById.find(programInfo.ChannelID()); - if (channelByIdIt != m_channelsById.end()) - { - return channelByIdIt->second; - } - return MythChannel(); + return FindChannel(programInfo.ChannelID()); } bool PVRClientMythTV::IsMyLiveRecording(const MythProgramInfo& programInfo) @@ -1188,7 +1214,7 @@ PVR_ERROR PVRClientMythTV::GetTimers(ADDON_HANDLE handle) std::string rulemarker = ""; tag.startTime = it->second->StartTime(); tag.endTime = it->second->EndTime(); - tag.iClientChannelUid = (int)FindPVRChannelUid(it->second->ChannelID()); + tag.iClientChannelUid = FindPVRChannelUid(it->second->ChannelID()); tag.iPriority = it->second->Priority(); int genre = m_categories.Category(it->second->Category()); tag.iGenreSubType = genre & 0x0F; @@ -1268,7 +1294,7 @@ PVR_ERROR PVRClientMythTV::GetTimers(ADDON_HANDLE handle) std::string title = it->second->Title(); if (!rulemarker.empty()) title.append(" ").append(rulemarker); - PVR_STRCPY(tag.strTitle, this->MakeProgramTitle(title, it->second->Subtitle()).c_str()); + PVR_STRCPY(tag.strTitle, MakeProgramTitle(title, it->second->Subtitle()).c_str()); // Summary PVR_STRCPY(tag.strSummary, it->second->Description().c_str()); @@ -1379,11 +1405,6 @@ MythRecordingRule PVRClientMythTV::PVRtoMythRecordingRule(const PVR_TIMER &timer time_t et = timer.endTime; time_t now = time(NULL); std::string title = timer.strTitle; - std::string cs; - - ChannelIdMap::iterator channelIt = m_channelsById.find(timer.iClientChannelUid); - if (channelIt != m_channelsById.end()) - cs = channelIt->second.Callsign(); // Fix timeslot as needed if (st == 0) @@ -1470,12 +1491,13 @@ MythRecordingRule PVRClientMythTV::PVRtoMythRecordingRule(const PVR_TIMER &timer if (!epgFound) { + MythChannel ch = FindChannel(timer.iClientChannelUid); rule.SetStartTime(st); rule.SetEndTime(et); rule.SetTitle(timer.strTitle); rule.SetCategory(m_categories.Category(timer.iGenreType)); rule.SetChannelID(timer.iClientChannelUid); - rule.SetCallsign(cs); + rule.SetCallsign(ch.Callsign()); } else { @@ -1574,16 +1596,8 @@ bool PVRClientMythTV::OpenLiveStream(const PVR_CHANNEL &channel) // Begin critical section CLockObject lock(m_lock); // First we have to get the selected channel - LoadChannelsAndChannelGroups(); - ChannelIdMap::iterator channelByIdIt = m_channelsById.find(channel.iUniqueId); - if (channelByIdIt == m_channelsById.end()) - { - XBMC->Log(LOG_ERROR,"%s: Channel not found", __FUNCTION__); - return false; - } - // Copy and check - Myth::ChannelPtr chan = channelByIdIt->second.GetPtr(); - if (!chan) + MythChannel chan = FindChannel(channel.iUniqueId); + if (chan.IsNull()) { XBMC->Log(LOG_ERROR,"%s: Invalid channel", __FUNCTION__); return false; @@ -1598,7 +1612,7 @@ bool PVRClientMythTV::OpenLiveStream(const PVR_CHANNEL &channel) // Set tuning delay m_liveStream->SetTuneDelay(g_iTuneDelay); // Try to open - if (m_liveStream->SpawnLiveTV(*chan)) + if (m_liveStream->SpawnLiveTV(*(chan.GetPtr()))) { if(g_bDemuxing) m_demux = new Demux(m_liveStream); @@ -1847,7 +1861,7 @@ bool PVRClientMythTV::OpenRecordedStream(const PVR_RECORDING &recording) m_recordingStream = new Myth::RecordingPlayback(*m_eventHandler); else { - // Query backend server IP + // Query backend server IP std::string backend_addr(m_control->GetBackendServerIP6(prog.HostName())); if (backend_addr.empty()) backend_addr = m_control->GetBackendServerIP(prog.HostName()); @@ -2091,6 +2105,7 @@ void PVRClientMythTV::AllowBackendShutdown() std::string PVRClientMythTV::MakeProgramTitle(const std::string& title, const std::string& subtitle) { + // Must contain the original title at the begining std::string epgtitle; if (subtitle.empty()) epgtitle = title; diff --git a/addons/pvr.mythtv/src/pvrclient-mythtv.h b/addons/pvr.mythtv/src/pvrclient-mythtv.h index 145c13ecd..98e3bc663 100644 --- a/addons/pvr.mythtv/src/pvrclient-mythtv.h +++ b/addons/pvr.mythtv/src/pvrclient-mythtv.h @@ -39,7 +39,7 @@ #include #include -class PVRClientMythTV : public Myth::EventSubscriber +class PVRClientMythTV : public Myth::EventSubscriber, FileConsumer { public: PVRClientMythTV(); @@ -59,11 +59,15 @@ class PVRClientMythTV : public Myth::EventSubscriber // Implements EventSubscriber void HandleBackendMessage(const Myth::EventMessage& msg); + void HandleChannelChange(); void HandleScheduleChange(); void HandleAskRecording(const Myth::EventMessage& msg); void HandleRecordingListChange(const Myth::EventMessage& msg); void RunHouseKeeping(); + // Implement FileConsumer + void HandleCleanedCache(); + // EPG PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd); @@ -77,7 +81,6 @@ class PVRClientMythTV : public Myth::EventSubscriber PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group); // Recordings - void UpdateRecordings(); int GetRecordingsAmount(void); PVR_ERROR GetRecordings(ADDON_HANDLE handle); PVR_ERROR DeleteRecording(const PVR_RECORDING &recording); @@ -148,15 +151,18 @@ class PVRClientMythTV : public Myth::EventSubscriber Categories m_categories; // Channels - typedef std::map ChannelIdMap; - typedef std::multimap ChannelNumberMap; - typedef std::map > ChannelGroupMap; + typedef std::map ChannelIdMap; ChannelIdMap m_channelsById; - ChannelNumberMap m_channelsByNumber; - ChannelGroupMap m_channelGroups; - typedef std::map PVRChannelMap; + typedef struct { unsigned int iUniqueId; bool bIsRadio; } PVRChannelItem; + typedef std::vector PVRChannelList; + typedef std::map PVRChannelGroupMap; + PVRChannelList m_PVRChannels; + PVRChannelGroupMap m_PVRChannelGroups; + typedef std::map PVRChannelMap; PVRChannelMap m_PVRChannelUidById; - void LoadChannelsAndChannelGroups(); + mutable PLATFORM::CMutex m_channelsLock; + int FillChannelsAndChannelGroups(); + MythChannel FindChannel(uint32_t channelId) const; int FindPVRChannelUid(uint32_t channelId) const; // Demuxer TS @@ -164,11 +170,11 @@ class PVRClientMythTV : public Myth::EventSubscriber // Recordings ProgramInfoMap m_recordings; - PLATFORM::CMutex m_recordingsLock; + mutable PLATFORM::CMutex m_recordingsLock; unsigned m_recordingChangePinCount; void ForceUpdateRecording(ProgramInfoMap::iterator it); int FillRecordings(); - MythChannel FindRecordingChannel(const MythProgramInfo& programInfo); + MythChannel FindRecordingChannel(const MythProgramInfo& programInfo) const; bool IsMyLiveRecording(const MythProgramInfo& programInfo); // Timers