[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / PVRManager.cpp
blob47bc3a43fce4cf9e03d07c3d1a97f9e031b08f6d
1 /*
2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "PVRManager.h"
11 #include "FileItem.h"
12 #include "ServiceBroker.h"
13 #include "guilib/LocalizeStrings.h"
14 #include "interfaces/AnnouncementManager.h"
15 #include "messaging/ApplicationMessenger.h"
16 #include "pvr/PVRComponentRegistration.h"
17 #include "pvr/PVRDatabase.h"
18 #include "pvr/PVRPlaybackState.h"
19 #include "pvr/addons/PVRClient.h"
20 #include "pvr/addons/PVRClients.h"
21 #include "pvr/channels/PVRChannel.h"
22 #include "pvr/channels/PVRChannelGroup.h"
23 #include "pvr/channels/PVRChannelGroupAllChannels.h"
24 #include "pvr/channels/PVRChannelGroups.h"
25 #include "pvr/channels/PVRChannelGroupsContainer.h"
26 #include "pvr/channels/PVRChannelsPath.h"
27 #include "pvr/epg/EpgContainer.h"
28 #include "pvr/epg/EpgInfoTag.h"
29 #include "pvr/guilib/PVRGUIActionsChannels.h"
30 #include "pvr/guilib/PVRGUIActionsPlayback.h"
31 #include "pvr/guilib/PVRGUIChannelIconUpdater.h"
32 #include "pvr/guilib/PVRGUIProgressHandler.h"
33 #include "pvr/guilib/guiinfo/PVRGUIInfo.h"
34 #include "pvr/providers/PVRProvider.h"
35 #include "pvr/providers/PVRProviders.h"
36 #include "pvr/recordings/PVRRecording.h"
37 #include "pvr/recordings/PVRRecordings.h"
38 #include "pvr/timers/PVRTimerInfoTag.h"
39 #include "pvr/timers/PVRTimers.h"
40 #include "settings/Settings.h"
41 #include "utils/JobManager.h"
42 #include "utils/Stopwatch.h"
43 #include "utils/StringUtils.h"
44 #include "utils/URIUtils.h"
45 #include "utils/log.h"
47 #include <algorithm>
48 #include <memory>
49 #include <mutex>
50 #include <string>
51 #include <utility>
52 #include <vector>
54 using namespace PVR;
55 using namespace std::chrono_literals;
57 namespace
60 class CPVRJob
62 public:
63 virtual ~CPVRJob() = default;
65 virtual bool DoWork() = 0;
66 virtual const std::string GetType() const = 0;
68 protected:
71 template<typename F>
72 class CPVRLambdaJob : public CPVRJob
74 public:
75 CPVRLambdaJob() = delete;
76 CPVRLambdaJob(const std::string& type, F&& f) : m_type(type), m_f(std::forward<F>(f)) {}
78 bool DoWork() override
80 m_f();
81 return true;
84 const std::string GetType() const override { return m_type; }
86 private:
87 std::string m_type;
88 F m_f;
91 } // unnamed namespace
93 namespace PVR
96 class CPVRManagerJobQueue
98 public:
99 CPVRManagerJobQueue() : m_triggerEvent(false) {}
101 void Start();
102 void Stop();
103 void Clear();
105 template<typename F>
106 void Append(const std::string& type, F&& f)
108 AppendJob(new CPVRLambdaJob<F>(type, std::forward<F>(f)));
111 void ExecutePendingJobs();
113 bool WaitForJobs(unsigned int milliSeconds)
115 return m_triggerEvent.Wait(std::chrono::milliseconds(milliSeconds));
118 private:
119 void AppendJob(CPVRJob* job);
121 CCriticalSection m_critSection;
122 CEvent m_triggerEvent;
123 std::vector<CPVRJob*> m_pendingUpdates;
124 bool m_bStopped = true;
127 } // namespace PVR
129 void CPVRManagerJobQueue::Start()
131 std::unique_lock<CCriticalSection> lock(m_critSection);
132 m_bStopped = false;
133 m_triggerEvent.Set();
136 void CPVRManagerJobQueue::Stop()
138 std::unique_lock<CCriticalSection> lock(m_critSection);
139 m_bStopped = true;
140 m_triggerEvent.Reset();
143 void CPVRManagerJobQueue::Clear()
145 std::unique_lock<CCriticalSection> lock(m_critSection);
146 for (CPVRJob* updateJob : m_pendingUpdates)
147 delete updateJob;
149 m_pendingUpdates.clear();
150 m_triggerEvent.Set();
153 void CPVRManagerJobQueue::AppendJob(CPVRJob* job)
155 std::unique_lock<CCriticalSection> lock(m_critSection);
157 // check for another pending job of given type...
158 if (std::any_of(m_pendingUpdates.cbegin(), m_pendingUpdates.cend(),
159 [job](CPVRJob* updateJob) { return updateJob->GetType() == job->GetType(); }))
161 delete job;
162 return;
165 m_pendingUpdates.push_back(job);
166 m_triggerEvent.Set();
169 void CPVRManagerJobQueue::ExecutePendingJobs()
171 std::vector<CPVRJob*> pendingUpdates;
174 std::unique_lock<CCriticalSection> lock(m_critSection);
176 if (m_bStopped)
177 return;
179 pendingUpdates = std::move(m_pendingUpdates);
180 m_triggerEvent.Reset();
183 CPVRJob* job = nullptr;
184 while (!pendingUpdates.empty())
186 job = pendingUpdates.front();
187 pendingUpdates.erase(pendingUpdates.begin());
189 job->DoWork();
190 delete job;
194 CPVRManager::CPVRManager()
195 : CThread("PVRManager"),
196 m_providers(new CPVRProviders),
197 m_channelGroups(new CPVRChannelGroupsContainer),
198 m_recordings(new CPVRRecordings),
199 m_timers(new CPVRTimers),
200 m_addons(new CPVRClients),
201 m_guiInfo(new CPVRGUIInfo),
202 m_components(new CPVRComponentRegistration),
203 m_epgContainer(new CPVREpgContainer(m_events)),
204 m_pendingUpdates(new CPVRManagerJobQueue),
205 m_database(new CPVRDatabase),
206 m_parentalTimer(new CStopWatch),
207 m_playbackState(new CPVRPlaybackState),
208 m_settings({CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED,
209 CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD,
210 CSettings::SETTING_PVRPARENTAL_ENABLED, CSettings::SETTING_PVRPARENTAL_DURATION})
212 CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
213 m_actionListener.Init(*this);
215 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance created");
218 CPVRManager::~CPVRManager()
220 m_actionListener.Deinit(*this);
221 CServiceBroker::GetAnnouncementManager()->RemoveAnnouncer(this);
223 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance destroyed");
226 void CPVRManager::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
227 const std::string& sender,
228 const std::string& message,
229 const CVariant& data)
231 if (!IsStarted())
232 return;
234 if ((flag & (ANNOUNCEMENT::GUI)))
236 if (message == "OnScreensaverActivated")
237 m_addons->OnPowerSavingActivated();
238 else if (message == "OnScreensaverDeactivated")
239 m_addons->OnPowerSavingDeactivated();
243 std::shared_ptr<CPVRDatabase> CPVRManager::GetTVDatabase() const
245 std::unique_lock<CCriticalSection> lock(m_critSection);
246 if (!m_database || !m_database->IsOpen())
247 CLog::LogF(LOGERROR, "Failed to open the PVR database");
249 return m_database;
252 std::shared_ptr<CPVRProviders> CPVRManager::Providers() const
254 std::unique_lock<CCriticalSection> lock(m_critSection);
255 return m_providers;
258 std::shared_ptr<CPVRChannelGroupsContainer> CPVRManager::ChannelGroups() const
260 std::unique_lock<CCriticalSection> lock(m_critSection);
261 return m_channelGroups;
264 std::shared_ptr<CPVRRecordings> CPVRManager::Recordings() const
266 std::unique_lock<CCriticalSection> lock(m_critSection);
267 return m_recordings;
270 std::shared_ptr<CPVRTimers> CPVRManager::Timers() const
272 std::unique_lock<CCriticalSection> lock(m_critSection);
273 return m_timers;
276 std::shared_ptr<CPVRClients> CPVRManager::Clients() const
278 // note: m_addons is const (only set/reset in ctor/dtor). no need for a lock here.
279 return m_addons;
282 std::shared_ptr<CPVRClient> CPVRManager::GetClient(const CFileItem& item) const
284 int iClientID = PVR_INVALID_CLIENT_ID;
286 if (item.HasPVRChannelInfoTag())
287 iClientID = item.GetPVRChannelInfoTag()->ClientID();
288 else if (item.HasPVRRecordingInfoTag())
289 iClientID = item.GetPVRRecordingInfoTag()->ClientID();
290 else if (item.HasPVRTimerInfoTag())
291 iClientID = item.GetPVRTimerInfoTag()->ClientID();
292 else if (item.HasEPGInfoTag())
293 iClientID = item.GetEPGInfoTag()->ClientID();
294 else if (URIUtils::IsPVRChannel(item.GetPath()))
296 const std::shared_ptr<const CPVRChannel> channel = m_channelGroups->GetByPath(item.GetPath());
297 if (channel)
298 iClientID = channel->ClientID();
300 else if (URIUtils::IsPVRChannelGroup(item.GetPath()))
302 const CPVRChannelsPath path(item.GetPath());
303 iClientID = path.GetGroupClientID();
305 else if (URIUtils::IsPVRRecording(item.GetPath()))
307 const std::shared_ptr<const CPVRRecording> recording = m_recordings->GetByPath(item.GetPath());
308 if (recording)
309 iClientID = recording->ClientID();
311 return GetClient(iClientID);
314 std::shared_ptr<CPVRClient> CPVRManager::GetClient(int iClientId) const
316 return m_addons->GetCreatedClient(iClientId);
319 std::shared_ptr<CPVRPlaybackState> CPVRManager::PlaybackState() const
321 // note: m_playbackState is const (only set/reset in ctor/dtor). no need for a lock here.
322 return m_playbackState;
325 CPVREpgContainer& CPVRManager::EpgContainer()
327 // note: m_epgContainer is const (only set/reset in ctor/dtor). no need for a lock here.
328 return *m_epgContainer;
331 void CPVRManager::Clear()
333 m_playbackState->Clear();
334 m_pendingUpdates->Clear();
336 std::unique_lock<CCriticalSection> lock(m_critSection);
338 m_guiInfo.reset();
339 m_timers.reset();
340 m_recordings.reset();
341 m_providers.reset();
342 m_channelGroups.reset();
343 m_parentalTimer.reset();
344 m_database.reset();
347 void CPVRManager::ResetProperties()
349 std::unique_lock<CCriticalSection> lock(m_critSection);
350 Clear();
352 m_database = std::make_shared<CPVRDatabase>();
353 m_providers = std::make_shared<CPVRProviders>();
354 m_channelGroups = std::make_shared<CPVRChannelGroupsContainer>();
355 m_recordings = std::make_shared<CPVRRecordings>();
356 m_timers = std::make_shared<CPVRTimers>();
357 m_guiInfo = std::make_unique<CPVRGUIInfo>();
358 m_parentalTimer = std::make_unique<CStopWatch>();
359 m_knownClients.clear();
362 void CPVRManager::Init()
364 // initial check for enabled addons
365 // if at least one pvr addon is enabled, PVRManager start up
366 CServiceBroker::GetJobManager()->Submit([this] {
367 Clients()->Start();
368 return true;
372 void CPVRManager::Start()
374 std::unique_lock<CCriticalSection> initLock(m_startStopMutex);
376 // Prevent concurrent starts
377 if (IsInitialising())
378 return;
380 // Note: Stop() must not be called while holding pvr manager's mutex. Stop() calls
381 // StopThread() which can deadlock if the worker thread tries to acquire pvr manager's
382 // lock while StopThread() is waiting for the worker to exit. Thus, we introduce another
383 // lock here (m_startStopMutex), which only gets hold while starting/restarting pvr manager.
384 Stop(true);
386 if (!m_addons->HasCreatedClients())
387 return;
389 CLog::Log(LOGINFO, "PVR Manager: Starting");
390 SetState(ManagerState::STATE_STARTING);
392 /* create the pvrmanager thread, which will ensure that all data will be loaded */
393 Create();
394 SetPriority(ThreadPriority::BELOW_NORMAL);
397 void CPVRManager::Stop(bool bRestart /* = false */)
399 std::unique_lock<CCriticalSection> initLock(m_startStopMutex);
401 // Prevent concurrent stops
402 if (IsStopped())
403 return;
405 /* stop playback if needed */
406 if (!bRestart && m_playbackState->IsPlaying())
408 CLog::LogFC(LOGDEBUG, LOGPVR, "Stopping PVR playback");
409 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP);
412 CLog::Log(LOGINFO, "PVR Manager: Stopping");
413 SetState(ManagerState::STATE_STOPPING);
415 StopThread();
418 void CPVRManager::Unload()
420 // stop pvr manager thread and clear all pvr data
421 Stop();
422 Clear();
425 void CPVRManager::Deinit()
427 SetWakeupCommand();
428 Unload();
430 // release addons
431 m_addons.reset();
434 CPVRManager::ManagerState CPVRManager::GetState() const
436 std::unique_lock<CCriticalSection> lock(m_managerStateMutex);
437 return m_managerState;
440 void CPVRManager::SetState(CPVRManager::ManagerState state)
443 std::unique_lock<CCriticalSection> lock(m_managerStateMutex);
444 if (m_managerState == state)
445 return;
447 m_managerState = state;
450 PVREvent event;
451 switch (state)
453 case ManagerState::STATE_ERROR:
454 event = PVREvent::ManagerError;
455 break;
456 case ManagerState::STATE_STOPPED:
457 event = PVREvent::ManagerStopped;
458 break;
459 case ManagerState::STATE_STARTING:
460 event = PVREvent::ManagerStarting;
461 break;
462 case ManagerState::STATE_STOPPING:
463 event = PVREvent::ManagerStopped;
464 break;
465 case ManagerState::STATE_INTERRUPTED:
466 event = PVREvent::ManagerInterrupted;
467 break;
468 case ManagerState::STATE_STARTED:
469 event = PVREvent::ManagerStarted;
470 break;
471 default:
472 return;
475 PublishEvent(event);
478 void CPVRManager::PublishEvent(PVREvent event)
480 m_events.Publish(event);
483 void CPVRManager::Process()
485 m_addons->Continue();
486 m_database->Open();
488 if (!IsInitialising())
490 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
491 return;
494 UnloadComponents();
496 if (!IsInitialising())
498 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
499 return;
502 // Wait for at least one client to come up and load/update data
503 UpdateComponents(ManagerState::STATE_STARTING);
505 if (!IsInitialising())
507 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
508 return;
511 // Load EPGs from database.
512 m_epgContainer->Load();
514 // Reinit playbackstate
515 m_playbackState->ReInit();
517 m_guiInfo->Start();
518 m_epgContainer->Start();
519 m_timers->Start();
520 m_pendingUpdates->Start();
522 SetState(ManagerState::STATE_STARTED);
523 CLog::Log(LOGINFO, "PVR Manager: Started");
525 bool bRestart(false);
526 XbmcThreads::EndTime<> cachedImagesCleanupTimeout(30s); // first timeout after 30 secs
528 while (IsStarted() && m_addons->HasCreatedClients() && !bRestart)
530 // In case any new client connected, load from db and fetch data update from new client(s)
531 UpdateComponents(ManagerState::STATE_STARTED);
533 if (cachedImagesCleanupTimeout.IsTimePast())
535 // We don't know for sure what to delete if there are not (yet) connected clients
536 if (m_addons->HasIgnoredClients())
538 cachedImagesCleanupTimeout.Set(10s); // try again in 10 secs
540 else
542 // start a job to erase stale texture db entries and image files
543 TriggerCleanupCachedImages();
544 cachedImagesCleanupTimeout.Set(12h); // following timeouts after 12 hours
548 /* first startup */
549 if (m_bFirstStart)
552 std::unique_lock<CCriticalSection> lock(m_critSection);
553 m_bFirstStart = false;
556 /* start job to search for missing channel icons */
557 TriggerSearchMissingChannelIcons();
559 /* try to play channel on startup */
560 TriggerPlayChannelOnStartup();
563 if (m_addons->AnyClientSupportingRecordingsSize())
564 TriggerRecordingsSizeInProgressUpdate();
566 /* execute the next pending jobs if there are any */
569 m_pendingUpdates->ExecutePendingJobs();
571 catch (...)
573 CLog::LogF(
574 LOGERROR,
575 "An error occurred while trying to execute the last PVR update job, trying to recover");
576 bRestart = true;
579 if (IsStarted() && !bRestart)
580 m_pendingUpdates->WaitForJobs(1000);
583 m_addons->Stop();
584 m_pendingUpdates->Stop();
585 m_timers->Stop();
586 m_epgContainer->Stop();
587 m_guiInfo->Stop();
589 SetState(ManagerState::STATE_INTERRUPTED);
591 UnloadComponents();
592 m_database->Close();
594 ResetProperties();
596 CLog::Log(LOGINFO, "PVR Manager: Stopped");
597 SetState(ManagerState::STATE_STOPPED);
600 bool CPVRManager::SetWakeupCommand()
602 #if !defined(TARGET_DARWIN_EMBEDDED) && !defined(TARGET_WINDOWS_STORE)
603 if (!m_settings.GetBoolValue(CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED))
604 return false;
606 const std::string strWakeupCommand(
607 m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD));
608 if (!strWakeupCommand.empty() && m_timers)
610 const CDateTime nextEvent = m_timers->GetNextEventTime();
611 if (nextEvent.IsValid())
613 time_t iWakeupTime;
614 nextEvent.GetAsTime(iWakeupTime);
616 std::string strExecCommand = StringUtils::Format("{} {}", strWakeupCommand, iWakeupTime);
618 const int iReturn = system(strExecCommand.c_str());
619 if (iReturn != 0)
620 CLog::LogF(LOGERROR, "PVR Manager failed to execute wakeup command '{}': {} ({})",
621 strExecCommand, strerror(iReturn), iReturn);
623 return iReturn == 0;
626 #endif
627 return false;
630 void CPVRManager::OnSleep()
632 PublishEvent(PVREvent::SystemSleep);
634 SetWakeupCommand();
636 m_epgContainer->OnSystemSleep();
637 m_addons->OnSystemSleep();
640 void CPVRManager::OnWake()
642 m_addons->OnSystemWake();
643 m_epgContainer->OnSystemWake();
645 PublishEvent(PVREvent::SystemWake);
647 /* start job to search for missing channel icons */
648 TriggerSearchMissingChannelIcons();
650 /* try to play channel on startup */
651 TriggerPlayChannelOnStartup();
653 /* trigger PVR data updates */
654 TriggerChannelGroupsUpdate();
655 TriggerProvidersUpdate();
656 TriggerChannelsUpdate();
657 TriggerRecordingsUpdate();
658 TriggerTimersUpdate();
661 void CPVRManager::UpdateComponents(ManagerState stateToCheck)
663 XbmcThreads::EndTime<> progressTimeout(30s);
664 std::unique_ptr<CPVRGUIProgressHandler> progressHandler(
665 new CPVRGUIProgressHandler(g_localizeStrings.Get(19235))); // PVR manager is starting up
667 // Wait for at least one client to come up and load/update data
668 while (!UpdateComponents(stateToCheck, progressHandler) && m_addons->HasCreatedClients() &&
669 (stateToCheck == GetState()))
671 CThread::Sleep(1000ms);
673 if (progressTimeout.IsTimePast())
674 progressHandler.reset();
678 bool CPVRManager::UpdateComponents(ManagerState stateToCheck,
679 const std::unique_ptr<CPVRGUIProgressHandler>& progressHandler)
681 // find clients which appeared since last check and update them
682 const CPVRClientMap clientMap = m_addons->GetCreatedClients();
683 if (clientMap.empty())
685 CLog::LogFC(LOGDEBUG, LOGPVR, "All created PVR clients gone!");
686 m_knownClients.clear(); // start over
687 PublishEvent(PVREvent::ClientsInvalidated);
688 return false;
691 std::vector<std::shared_ptr<CPVRClient>> newClients;
692 for (const auto& entry : clientMap)
694 // skip not (yet) connected clients
695 if (entry.second->IgnoreClient())
697 CLog::LogFC(LOGDEBUG, LOGPVR, "Skipping not (yet) connected PVR client {}",
698 entry.second->GetID());
699 continue;
702 if (!IsKnownClient(entry.first))
704 m_knownClients.emplace_back(entry.second);
705 newClients.emplace_back(entry.second);
707 CLog::LogFC(LOGDEBUG, LOGPVR, "Adding new PVR client {} to list of known clients",
708 entry.second->GetID());
712 if (newClients.empty())
713 return !m_knownClients.empty();
715 // Load all channels and groups
716 if (progressHandler)
717 progressHandler->UpdateProgress(g_localizeStrings.Get(19236), 0); // Loading channels and groups
719 if (!m_providers->Update(newClients) || (stateToCheck != GetState()))
721 CLog::LogF(LOGERROR, "Failed to load PVR providers.");
722 m_knownClients.clear(); // start over
723 PublishEvent(PVREvent::ClientsInvalidated);
724 return false;
727 if (!m_channelGroups->Update(newClients) || (stateToCheck != GetState()))
729 CLog::LogF(LOGERROR, "Failed to load PVR channels / groups.");
730 m_knownClients.clear(); // start over
731 PublishEvent(PVREvent::ClientsInvalidated);
732 return false;
735 // Load all timers
736 if (progressHandler)
737 progressHandler->UpdateProgress(g_localizeStrings.Get(19237), 50); // Loading timers
739 if (!m_timers->Update(newClients) || (stateToCheck != GetState()))
741 CLog::LogF(LOGERROR, "Failed to load PVR timers.");
742 m_knownClients.clear(); // start over
743 PublishEvent(PVREvent::ClientsInvalidated);
744 return false;
747 // Load all recordings
748 if (progressHandler)
749 progressHandler->UpdateProgress(g_localizeStrings.Get(19238), 75); // Loading recordings
751 if (!m_recordings->Update(newClients) || (stateToCheck != GetState()))
753 CLog::LogF(LOGERROR, "Failed to load PVR recordings.");
754 m_knownClients.clear(); // start over
755 PublishEvent(PVREvent::ClientsInvalidated);
756 return false;
759 // reinit playbackstate as new client may provide new last opened group / last played channel
760 m_playbackState->ReInit();
762 PublishEvent(PVREvent::ClientsInvalidated);
763 return true;
766 void CPVRManager::UnloadComponents()
768 m_recordings->Unload();
769 m_timers->Unload();
770 m_channelGroups->Unload();
771 m_providers->Unload();
772 m_epgContainer->Unload();
775 bool CPVRManager::IsKnownClient(int clientID) const
777 return std::any_of(m_knownClients.cbegin(), m_knownClients.cend(),
778 [clientID](const auto& client) { return client->GetID() == clientID; });
781 void CPVRManager::TriggerPlayChannelOnStartup()
783 if (IsStarted())
785 CServiceBroker::GetJobManager()->Submit(
786 [this] { return Get<PVR::GUI::Playback>().PlayChannelOnStartup(); });
790 void CPVRManager::RestartParentalTimer()
792 if (m_parentalTimer)
793 m_parentalTimer->StartZero();
796 bool CPVRManager::IsParentalLocked(const std::shared_ptr<const CPVREpgInfoTag>& epgTag) const
798 return m_channelGroups && epgTag &&
799 IsCurrentlyParentalLocked(
800 m_channelGroups->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()),
801 epgTag->IsParentalLocked());
804 bool CPVRManager::IsParentalLocked(const std::shared_ptr<const CPVRChannel>& channel) const
806 return channel && IsCurrentlyParentalLocked(channel, channel->IsLocked());
809 bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr<const CPVRChannel>& channel,
810 bool bGenerallyLocked) const
812 bool bReturn = false;
814 if (!channel || !bGenerallyLocked)
815 return bReturn;
817 const std::shared_ptr<const CPVRChannel> currentChannel = m_playbackState->GetPlayingChannel();
819 if ( // if channel in question is currently playing it must be currently unlocked.
820 (!currentChannel || channel != currentChannel) &&
821 // parental control enabled
822 m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED))
824 float parentalDurationMs =
825 m_settings.GetIntValue(CSettings::SETTING_PVRPARENTAL_DURATION) * 1000.0f;
826 bReturn = m_parentalTimer && (!m_parentalTimer->IsRunning() ||
827 m_parentalTimer->GetElapsedMilliseconds() > parentalDurationMs);
830 return bReturn;
833 void CPVRManager::OnPlaybackStarted(const CFileItem& item)
835 m_playbackState->OnPlaybackStarted(item);
836 Get<PVR::GUI::Channels>().OnPlaybackStarted(item);
837 m_epgContainer->OnPlaybackStarted();
840 void CPVRManager::OnPlaybackStopped(const CFileItem& item)
842 // Playback ended due to user interaction
843 if (m_playbackState->OnPlaybackStopped(item))
844 PublishEvent(PVREvent::ChannelPlaybackStopped);
846 Get<PVR::GUI::Channels>().OnPlaybackStopped(item);
847 m_epgContainer->OnPlaybackStopped();
850 void CPVRManager::OnPlaybackEnded(const CFileItem& item)
852 // Playback ended, but not due to user interaction
853 if (m_playbackState->OnPlaybackEnded(item))
854 PublishEvent(PVREvent::ChannelPlaybackStopped);
856 Get<PVR::GUI::Channels>().OnPlaybackStopped(item);
857 m_epgContainer->OnPlaybackStopped();
860 void CPVRManager::LocalizationChanged()
862 std::unique_lock<CCriticalSection> lock(m_critSection);
863 if (IsStarted())
865 static_cast<CPVRChannelGroupAllChannels*>(m_channelGroups->GetGroupAllRadio().get())
866 ->CheckGroupName();
867 static_cast<CPVRChannelGroupAllChannels*>(m_channelGroups->GetGroupAllTV().get())
868 ->CheckGroupName();
872 void CPVRManager::TriggerRecordingsSizeInProgressUpdate()
874 m_pendingUpdates->Append("pvr-update-recordings-size",
875 [this]() { return Recordings()->UpdateInProgressSize(); });
878 void CPVRManager::TriggerRecordingsUpdate(int clientId)
880 m_pendingUpdates->Append("pvr-update-recordings-" + std::to_string(clientId), [this, clientId]() {
881 if (!IsKnownClient(clientId))
882 return;
884 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
885 if (client)
886 Recordings()->UpdateFromClients({client});
890 void CPVRManager::TriggerRecordingsUpdate()
892 m_pendingUpdates->Append("pvr-update-recordings",
893 [this]() { Recordings()->UpdateFromClients({}); });
896 void CPVRManager::TriggerTimersUpdate(int clientId)
898 m_pendingUpdates->Append("pvr-update-timers-" + std::to_string(clientId), [this, clientId]() {
899 if (!IsKnownClient(clientId))
900 return;
902 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
903 if (client)
904 Timers()->UpdateFromClients({client});
908 void CPVRManager::TriggerTimersUpdate()
910 m_pendingUpdates->Append("pvr-update-timers", [this]() { Timers()->UpdateFromClients({}); });
913 void CPVRManager::TriggerProvidersUpdate(int clientId)
915 m_pendingUpdates->Append("pvr-update-channel-providers-" + std::to_string(clientId),
916 [this, clientId]() {
917 if (!IsKnownClient(clientId))
918 return;
920 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
921 if (client)
922 Providers()->UpdateFromClients({client});
926 void CPVRManager::TriggerProvidersUpdate()
928 m_pendingUpdates->Append("pvr-update-channel-providers",
929 [this]() { Providers()->UpdateFromClients({}); });
932 void CPVRManager::TriggerChannelsUpdate(int clientId)
934 m_pendingUpdates->Append("pvr-update-channels-" + std::to_string(clientId), [this, clientId]() {
935 if (!IsKnownClient(clientId))
936 return;
938 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
939 if (client)
940 ChannelGroups()->UpdateFromClients({client}, true);
944 void CPVRManager::TriggerChannelsUpdate()
946 m_pendingUpdates->Append("pvr-update-channels",
947 [this]() { ChannelGroups()->UpdateFromClients({}, true); });
950 void CPVRManager::TriggerChannelGroupsUpdate(int clientId)
952 m_pendingUpdates->Append("pvr-update-channelgroups-" + std::to_string(clientId),
953 [this, clientId]() {
954 if (!IsKnownClient(clientId))
955 return;
957 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
958 if (client)
959 ChannelGroups()->UpdateFromClients({client}, false);
963 void CPVRManager::TriggerChannelGroupsUpdate()
965 m_pendingUpdates->Append("pvr-update-channelgroups",
966 [this]() { ChannelGroups()->UpdateFromClients({}, false); });
969 void CPVRManager::TriggerSearchMissingChannelIcons()
971 m_pendingUpdates->Append("pvr-search-missing-channel-icons", [this]() {
972 CPVRGUIChannelIconUpdater updater(
973 {ChannelGroups()->GetGroupAllTV(), ChannelGroups()->GetGroupAllRadio()}, true);
974 updater.SearchAndUpdateMissingChannelIcons();
975 return true;
979 void CPVRManager::TriggerSearchMissingChannelIcons(const std::shared_ptr<CPVRChannelGroup>& group)
981 m_pendingUpdates->Append("pvr-search-missing-channel-icons-" + std::to_string(group->GroupID()),
982 [group]() {
983 CPVRGUIChannelIconUpdater updater({group}, false);
984 updater.SearchAndUpdateMissingChannelIcons();
985 return true;
989 void CPVRManager::TriggerCleanupCachedImages()
991 m_pendingUpdates->Append("pvr-cleanup-cached-images", [this]() {
992 int iCleanedImages = 0;
993 CLog::Log(LOGINFO, "PVR Manager: Starting cleanup of cached images.");
994 iCleanedImages += Recordings()->CleanupCachedImages();
995 iCleanedImages += ChannelGroups()->CleanupCachedImages();
996 iCleanedImages += Providers()->CleanupCachedImages();
997 iCleanedImages += EpgContainer().CleanupCachedImages();
998 CLog::Log(LOGINFO, "PVR Manager: Cleaned up {} cached images.", iCleanedImages);
999 return true;
1003 void CPVRManager::ConnectionStateChange(CPVRClient* client,
1004 const std::string& connectString,
1005 PVR_CONNECTION_STATE state,
1006 const std::string& message)
1008 CServiceBroker::GetJobManager()->Submit([this, client, connectString, state, message] {
1009 Clients()->ConnectionStateChange(client, connectString, state, message);
1010 return true;