diff options
-rw-r--r-- | xbmc/pvr/addons/PVRClient.cpp | 208 | ||||
-rw-r--r-- | xbmc/pvr/addons/PVRClient.h | 11 | ||||
-rw-r--r-- | xbmc/pvr/addons/PVRClients.cpp | 34 | ||||
-rw-r--r-- | xbmc/pvr/addons/PVRClients.h | 14 | ||||
-rw-r--r-- | xbmc/pvr/timers/PVRTimerType.cpp | 26 | ||||
-rw-r--r-- | xbmc/pvr/timers/PVRTimerType.h | 6 | ||||
-rw-r--r-- | xbmc/pvr/timers/PVRTimers.cpp | 5 |
7 files changed, 192 insertions, 112 deletions
diff --git a/xbmc/pvr/addons/PVRClient.cpp b/xbmc/pvr/addons/PVRClient.cpp index 642fdbbcd4..9c553d7aa8 100644 --- a/xbmc/pvr/addons/PVRClient.cpp +++ b/xbmc/pvr/addons/PVRClient.cpp @@ -305,7 +305,6 @@ bool CPVRClient::GetAddonProperties() return false; PVR_ADDON_CAPABILITIES addonCapabilities = {}; - std::vector<std::shared_ptr<CPVRTimerType>> timerTypes; /* get the capabilities */ PVR_ERROR retVal = DoAddonCall( @@ -318,96 +317,8 @@ bool CPVRClient::GetAddonProperties() if (retVal != PVR_ERROR_NO_ERROR) return false; - /* timer types */ - retVal = DoAddonCall( - __func__, - [this, &addonCapabilities, &timerTypes](const AddonInstance* addon) { - std::unique_ptr<PVR_TIMER_TYPE[]> types_array( - new PVR_TIMER_TYPE[PVR_ADDON_TIMERTYPE_ARRAY_SIZE]); - int size = PVR_ADDON_TIMERTYPE_ARRAY_SIZE; - - PVR_ERROR retval = addon->toAddon->GetTimerTypes(addon, types_array.get(), &size); - - if (retval == PVR_ERROR_NOT_IMPLEMENTED) - { - // begin compat section - CLog::LogF(LOGWARNING, - "Add-on {} does not support timer types. It will work, but not benefit from " - "the timer features introduced with PVR Addon API 2.0.0", - GetFriendlyName()); - - // Create standard timer types (mostly) matching the timer functionality available in Isengard. - // This is for migration only and does not make changes to the addons obsolete. Addons should - // work and benefit from some UI changes (e.g. some of the timer settings dialog enhancements), - // but all old problems/bugs due to static attributes and values will remain the same as in - // Isengard. Also, new features (like epg search) are not available to addons automatically. - // This code can be removed once all addons actually support the respective PVR Addon API version. - - size = 0; - // manual one time - memset(&types_array[size], 0, sizeof(types_array[size])); - types_array[size].iId = size + 1; - types_array[size].iAttributes = - PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | - PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | - PVR_TIMER_TYPE_SUPPORTS_END_TIME | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | - PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; - ++size; - - // manual timer rule - memset(&types_array[size], 0, sizeof(types_array[size])); - types_array[size].iId = size + 1; - types_array[size].iAttributes = - PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING | - PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | - PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_END_TIME | - PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME | - PVR_TIMER_TYPE_SUPPORTS_FIRST_DAY | PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS | - PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; - ++size; - - if (addonCapabilities.bSupportsEPG) - { - // One-shot epg-based - memset(&types_array[size], 0, sizeof(types_array[size])); - types_array[size].iId = size + 1; - types_array[size].iAttributes = - PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | - PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | - PVR_TIMER_TYPE_SUPPORTS_END_TIME | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | - PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; - ++size; - } - - retval = PVR_ERROR_NO_ERROR; - // end compat section - } - - if (retval == PVR_ERROR_NO_ERROR) - { - timerTypes.reserve(size); - for (int i = 0; i < size; ++i) - { - if (types_array[i].iId == PVR_TIMER_TYPE_NONE) - { - CLog::LogF(LOGERROR, "Invalid timer type supplied by add-on {}.", GetID()); - continue; - } - timerTypes.emplace_back( - std::shared_ptr<CPVRTimerType>(new CPVRTimerType(types_array[i], m_iClientId))); - } - } - return retval; - }, - addonCapabilities.bSupportsTimers, false); - - if (retVal == PVR_ERROR_NOT_IMPLEMENTED) - retVal = PVR_ERROR_NO_ERROR; // timer support is optional. - - /* update the members */ std::unique_lock<CCriticalSection> lock(m_critSection); m_clientCapabilities = addonCapabilities; - m_timertypes = timerTypes; return retVal == PVR_ERROR_NO_ERROR; } @@ -1078,11 +989,124 @@ PVR_ERROR CPVRClient::UpdateTimer(const CPVRTimerInfoTag& timer) m_clientCapabilities.SupportsTimers()); } -PVR_ERROR CPVRClient::GetTimerTypes(std::vector<std::shared_ptr<CPVRTimerType>>& results) const +const std::vector<std::shared_ptr<CPVRTimerType>>& CPVRClient::GetTimerTypes() const { std::unique_lock<CCriticalSection> lock(m_critSection); - results = m_timertypes; - return PVR_ERROR_NO_ERROR; + return m_timertypes; +} + +PVR_ERROR CPVRClient::UpdateTimerTypes() +{ + std::vector<std::shared_ptr<CPVRTimerType>> timerTypes; + + PVR_ERROR retVal = DoAddonCall( + __func__, + [this, &timerTypes](const AddonInstance* addon) { + std::unique_ptr<PVR_TIMER_TYPE[]> types_array( + new PVR_TIMER_TYPE[PVR_ADDON_TIMERTYPE_ARRAY_SIZE]); + int size = PVR_ADDON_TIMERTYPE_ARRAY_SIZE; + + PVR_ERROR retval = addon->toAddon->GetTimerTypes(addon, types_array.get(), &size); + + if (retval == PVR_ERROR_NOT_IMPLEMENTED) + { + // begin compat section + CLog::LogF(LOGWARNING, + "Add-on {} does not support timer types. It will work, but not benefit from " + "the timer features introduced with PVR Addon API 2.0.0", + GetFriendlyName()); + + // Create standard timer types (mostly) matching the timer functionality available in Isengard. + // This is for migration only and does not make changes to the addons obsolete. Addons should + // work and benefit from some UI changes (e.g. some of the timer settings dialog enhancements), + // but all old problems/bugs due to static attributes and values will remain the same as in + // Isengard. Also, new features (like epg search) are not available to addons automatically. + // This code can be removed once all addons actually support the respective PVR Addon API version. + + size = 0; + // manual one time + memset(&types_array[size], 0, sizeof(types_array[size])); + types_array[size].iId = size + 1; + types_array[size].iAttributes = + PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | + PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | + PVR_TIMER_TYPE_SUPPORTS_END_TIME | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | + PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; + ++size; + + // manual timer rule + memset(&types_array[size], 0, sizeof(types_array[size])); + types_array[size].iId = size + 1; + types_array[size].iAttributes = + PVR_TIMER_TYPE_IS_MANUAL | PVR_TIMER_TYPE_IS_REPEATING | + PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | PVR_TIMER_TYPE_SUPPORTS_CHANNELS | + PVR_TIMER_TYPE_SUPPORTS_START_TIME | PVR_TIMER_TYPE_SUPPORTS_END_TIME | + PVR_TIMER_TYPE_SUPPORTS_PRIORITY | PVR_TIMER_TYPE_SUPPORTS_LIFETIME | + PVR_TIMER_TYPE_SUPPORTS_FIRST_DAY | PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS | + PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; + ++size; + + if (m_clientCapabilities.SupportsEPG()) + { + // One-shot epg-based + memset(&types_array[size], 0, sizeof(types_array[size])); + types_array[size].iId = size + 1; + types_array[size].iAttributes = + PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE | PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE | + PVR_TIMER_TYPE_SUPPORTS_CHANNELS | PVR_TIMER_TYPE_SUPPORTS_START_TIME | + PVR_TIMER_TYPE_SUPPORTS_END_TIME | PVR_TIMER_TYPE_SUPPORTS_PRIORITY | + PVR_TIMER_TYPE_SUPPORTS_LIFETIME | PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS; + ++size; + } + + retval = PVR_ERROR_NO_ERROR; + // end compat section + } + + if (retval == PVR_ERROR_NO_ERROR) + { + timerTypes.reserve(size); + for (int i = 0; i < size; ++i) + { + if (types_array[i].iId == PVR_TIMER_TYPE_NONE) + { + CLog::LogF(LOGERROR, "Invalid timer type supplied by add-on {}.", GetID()); + continue; + } + timerTypes.emplace_back(std::make_shared<CPVRTimerType>(types_array[i], m_iClientId)); + } + } + return retval; + }, + m_clientCapabilities.SupportsTimers(), false); + + if (retVal == PVR_ERROR_NO_ERROR) + { + std::vector<std::shared_ptr<CPVRTimerType>> newTimerTypes; + newTimerTypes.reserve(timerTypes.size()); + + std::unique_lock<CCriticalSection> lock(m_critSection); + + for (const auto& type : timerTypes) + { + const auto it = std::find_if(m_timertypes.cbegin(), m_timertypes.cend(), + [&type](const std::shared_ptr<CPVRTimerType>& entry) { + return entry->GetTypeId() == type->GetTypeId(); + }); + if (it == m_timertypes.cend()) + { + newTimerTypes.emplace_back(type); + } + else + { + (*it)->Update(*type); + newTimerTypes.emplace_back(*it); + } + } + + m_timertypes = newTimerTypes; + } + return retVal; } PVR_ERROR CPVRClient::GetStreamReadChunkSize(int& iChunkSize) diff --git a/xbmc/pvr/addons/PVRClient.h b/xbmc/pvr/addons/PVRClient.h index b088a579ec..c045431d25 100644 --- a/xbmc/pvr/addons/PVRClient.h +++ b/xbmc/pvr/addons/PVRClient.h @@ -489,11 +489,16 @@ public: PVR_ERROR UpdateTimer(const CPVRTimerInfoTag& timer); /*! - * @brief Get all timer types supported by the backend. - * @param results The container to store the result in. + * @brief Update all timer types supported by the backend. * @return PVR_ERROR_NO_ERROR if the list has been fetched successfully. */ - PVR_ERROR GetTimerTypes(std::vector<std::shared_ptr<CPVRTimerType>>& results) const; + PVR_ERROR UpdateTimerTypes(); + + /*! + * @brief Get the timer types supported by the backend, without updating them from the backend. + * @return the types. + */ + const std::vector<std::shared_ptr<CPVRTimerType>>& GetTimerTypes() const; //@} /** @name PVR live stream methods */ diff --git a/xbmc/pvr/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp index bceda373a5..db4aee11d5 100644 --- a/xbmc/pvr/addons/PVRClients.cpp +++ b/xbmc/pvr/addons/PVRClients.cpp @@ -600,15 +600,31 @@ bool CPVRClients::GetTimers(const std::vector<std::shared_ptr<CPVRClient>>& clie failedClients) == PVR_ERROR_NO_ERROR; } -PVR_ERROR CPVRClients::GetTimerTypes(std::vector<std::shared_ptr<CPVRTimerType>>& results) const -{ - return ForCreatedClients(__FUNCTION__, [&results](const std::shared_ptr<CPVRClient>& client) { - std::vector<std::shared_ptr<CPVRTimerType>> types; - PVR_ERROR ret = client->GetTimerTypes(types); - if (ret == PVR_ERROR_NO_ERROR) - results.insert(results.end(), types.begin(), types.end()); - return ret; - }); +PVR_ERROR CPVRClients::UpdateTimerTypes(const std::vector<std::shared_ptr<CPVRClient>>& clients, + std::vector<int>& failedClients) +{ + return ForClients( + __FUNCTION__, clients, + [](const std::shared_ptr<CPVRClient>& client) { return client->UpdateTimerTypes(); }, + failedClients); +} + +const std::vector<std::shared_ptr<CPVRTimerType>> CPVRClients::GetTimerTypes() const +{ + std::vector<std::shared_ptr<CPVRTimerType>> types; + + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& entry : m_clientMap) + { + const auto& client = entry.second; + if (client->ReadyToUse() && !client->IgnoreClient()) + { + const auto& clientTypes = client->GetTimerTypes(); + types.insert(types.end(), clientTypes.begin(), clientTypes.end()); + } + } + + return types; } PVR_ERROR CPVRClients::GetRecordings(const std::vector<std::shared_ptr<CPVRClient>>& clients, diff --git a/xbmc/pvr/addons/PVRClients.h b/xbmc/pvr/addons/PVRClients.h index 32248fa322..23ee19eade 100644 --- a/xbmc/pvr/addons/PVRClients.h +++ b/xbmc/pvr/addons/PVRClients.h @@ -212,11 +212,19 @@ struct SBackend std::vector<int>& failedClients); /*! - * @brief Get all supported timer types. - * @param results The container to store the result in. + * @brief Update all timer types from the given clients + * @param clients The clients to fetch data from. Leave empty to fetch data from all created clients. + * @param failedClients in case of errors will contain the ids of the clients for which the timer types could not be obtained. * @return PVR_ERROR_NO_ERROR if the operation succeeded, the respective PVR_ERROR value otherwise. */ - PVR_ERROR GetTimerTypes(std::vector<std::shared_ptr<CPVRTimerType>>& results) const; + PVR_ERROR UpdateTimerTypes(const std::vector<std::shared_ptr<CPVRClient>>& clients, + std::vector<int>& failedClients); + + /*! + * @brief Get all timer types supported by the backends, without updating them from the backends. + * @return the types. + */ + const std::vector<std::shared_ptr<CPVRTimerType>> GetTimerTypes() const; //@} diff --git a/xbmc/pvr/timers/PVRTimerType.cpp b/xbmc/pvr/timers/PVRTimerType.cpp index db20fa10af..fd4cc0eba6 100644 --- a/xbmc/pvr/timers/PVRTimerType.cpp +++ b/xbmc/pvr/timers/PVRTimerType.cpp @@ -27,8 +27,8 @@ using namespace PVR; const std::vector<std::shared_ptr<CPVRTimerType>> CPVRTimerType::GetAllTypes() { - std::vector<std::shared_ptr<CPVRTimerType>> allTypes; - CServiceBroker::GetPVRManager().Clients()->GetTimerTypes(allTypes); + std::vector<std::shared_ptr<CPVRTimerType>> allTypes = + CServiceBroker::GetPVRManager().Clients()->GetTimerTypes(); // Add local reminder timer types. Local reminders are always available. int iTypeId = PVR_TIMER_TYPE_NONE; @@ -107,8 +107,8 @@ const std::shared_ptr<CPVRTimerType> CPVRTimerType::GetFirstAvailableType(const { if (client) { - std::vector<std::shared_ptr<CPVRTimerType>> types; - if (client->GetTimerTypes(types) == PVR_ERROR_NO_ERROR && !types.empty()) + const std::vector<std::shared_ptr<CPVRTimerType>>& types = client->GetTimerTypes(); + if (!types.empty()) { return *(types.begin()); } @@ -214,6 +214,24 @@ bool CPVRTimerType::operator !=(const CPVRTimerType& right) const return !(*this == right); } +void CPVRTimerType::Update(const CPVRTimerType& type) +{ + m_iClientId = type.m_iClientId; + m_iTypeId = type.m_iTypeId; + m_iAttributes = type.m_iAttributes; + m_strDescription = type.m_strDescription; + m_priorityValues = type.m_priorityValues; + m_iPriorityDefault = type.m_iPriorityDefault; + m_lifetimeValues = type.m_lifetimeValues; + m_iLifetimeDefault = type.m_iLifetimeDefault; + m_maxRecordingsValues = type.m_maxRecordingsValues; + m_iMaxRecordingsDefault = type.m_iMaxRecordingsDefault; + m_preventDupEpisodesValues = type.m_preventDupEpisodesValues; + m_iPreventDupEpisodesDefault = type.m_iPreventDupEpisodesDefault; + m_recordingGroupValues = type.m_recordingGroupValues; + m_iRecordingGroupDefault = type.m_iRecordingGroupDefault; +} + void CPVRTimerType::InitDescription() { // if no description was given, compile it diff --git a/xbmc/pvr/timers/PVRTimerType.h b/xbmc/pvr/timers/PVRTimerType.h index 8ee9e225d6..34405a7e1b 100644 --- a/xbmc/pvr/timers/PVRTimerType.h +++ b/xbmc/pvr/timers/PVRTimerType.h @@ -75,6 +75,12 @@ namespace PVR bool operator !=(const CPVRTimerType& right) const; /*! + * @brief Update the data of this instance with the data given by another type instance. + * @param type The instance containing the updated data. + */ + void Update(const CPVRTimerType& type); + + /*! * @brief Get the PVR client id for this type. * @return The PVR client id. */ diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp index 760bb192f7..9537a52016 100644 --- a/xbmc/pvr/timers/PVRTimers.cpp +++ b/xbmc/pvr/timers/PVRTimers.cpp @@ -157,9 +157,12 @@ bool CPVRTimers::UpdateFromClients(const std::vector<std::shared_ptr<CPVRClient> m_bIsUpdating = true; } + CLog::LogFC(LOGDEBUG, LOGPVR, "Updating timer types"); + std::vector<int> failedClients; + CServiceBroker::GetPVRManager().Clients()->UpdateTimerTypes(clients, failedClients); + CLog::LogFC(LOGDEBUG, LOGPVR, "Updating timers"); CPVRTimersContainer newTimerList; - std::vector<int> failedClients; CServiceBroker::GetPVRManager().Clients()->GetTimers(clients, &newTimerList, failedClients); return UpdateEntries(newTimerList, failedClients); } |