Merge pull request #26244 from Hitcher/media_flag_border_fix
[xbmc.git] / xbmc / pvr / PVRManager.cpp
blobf0d25dc654477c56dd171484a31bcdc0331b288a
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/PVRConstants.h" // PVR_CLIENT_INVALID_UID
18 #include "pvr/PVRDatabase.h"
19 #include "pvr/PVRPlaybackState.h"
20 #include "pvr/addons/PVRClient.h"
21 #include "pvr/addons/PVRClients.h"
22 #include "pvr/channels/PVRChannel.h"
23 #include "pvr/channels/PVRChannelGroup.h"
24 #include "pvr/channels/PVRChannelGroupAllChannels.h"
25 #include "pvr/channels/PVRChannelGroups.h"
26 #include "pvr/channels/PVRChannelGroupsContainer.h"
27 #include "pvr/channels/PVRChannelsPath.h"
28 #include "pvr/epg/EpgContainer.h"
29 #include "pvr/epg/EpgInfoTag.h"
30 #include "pvr/guilib/PVRGUIActionsChannels.h"
31 #include "pvr/guilib/PVRGUIActionsPlayback.h"
32 #include "pvr/guilib/PVRGUIChannelIconUpdater.h"
33 #include "pvr/guilib/PVRGUIProgressHandler.h"
34 #include "pvr/guilib/guiinfo/PVRGUIInfo.h"
35 #include "pvr/providers/PVRProvider.h"
36 #include "pvr/providers/PVRProviders.h"
37 #include "pvr/recordings/PVRRecording.h"
38 #include "pvr/recordings/PVRRecordings.h"
39 #include "pvr/timers/PVRTimerInfoTag.h"
40 #include "pvr/timers/PVRTimers.h"
41 #include "settings/Settings.h"
42 #include "utils/JobManager.h"
43 #include "utils/Stopwatch.h"
44 #include "utils/StringUtils.h"
45 #include "utils/URIUtils.h"
46 #include "utils/log.h"
48 #include <algorithm>
49 #include <memory>
50 #include <mutex>
51 #include <string>
52 #include <utility>
53 #include <vector>
55 using namespace PVR;
56 using namespace std::chrono_literals;
58 namespace
61 class CPVRJob
63 public:
64 virtual ~CPVRJob() = default;
66 virtual bool DoWork() = 0;
67 virtual const std::string GetType() const = 0;
69 protected:
72 template<typename F>
73 class CPVRLambdaJob : public CPVRJob
75 public:
76 CPVRLambdaJob() = delete;
77 CPVRLambdaJob(const std::string& type, F&& f) : m_type(type), m_f(std::forward<F>(f)) {}
79 bool DoWork() override
81 m_f();
82 return true;
85 const std::string GetType() const override { return m_type; }
87 private:
88 std::string m_type;
89 F m_f;
92 } // unnamed namespace
94 namespace PVR
97 class CPVRManagerJobQueue
99 public:
100 CPVRManagerJobQueue() : m_triggerEvent(false) {}
102 void Start();
103 void Stop();
104 void Clear();
106 template<typename F>
107 void Append(const std::string& type, F&& f)
109 AppendJob(new CPVRLambdaJob<F>(type, std::forward<F>(f)));
112 void ExecutePendingJobs();
114 bool WaitForJobs(unsigned int milliSeconds)
116 return m_triggerEvent.Wait(std::chrono::milliseconds(milliSeconds));
119 private:
120 void AppendJob(CPVRJob* job);
122 CCriticalSection m_critSection;
123 CEvent m_triggerEvent;
124 std::vector<CPVRJob*> m_pendingUpdates;
125 bool m_bStopped = true;
128 } // namespace PVR
130 void CPVRManagerJobQueue::Start()
132 std::unique_lock<CCriticalSection> lock(m_critSection);
133 m_bStopped = false;
134 m_triggerEvent.Set();
137 void CPVRManagerJobQueue::Stop()
139 std::unique_lock<CCriticalSection> lock(m_critSection);
140 m_bStopped = true;
141 m_triggerEvent.Reset();
144 void CPVRManagerJobQueue::Clear()
146 std::unique_lock<CCriticalSection> lock(m_critSection);
147 for (CPVRJob* updateJob : m_pendingUpdates)
148 delete updateJob;
150 m_pendingUpdates.clear();
151 m_triggerEvent.Set();
154 void CPVRManagerJobQueue::AppendJob(CPVRJob* job)
156 std::unique_lock<CCriticalSection> lock(m_critSection);
158 // check for another pending job of given type...
159 if (std::any_of(m_pendingUpdates.cbegin(), m_pendingUpdates.cend(),
160 [job](CPVRJob* updateJob) { return updateJob->GetType() == job->GetType(); }))
162 delete job;
163 return;
166 m_pendingUpdates.push_back(job);
167 m_triggerEvent.Set();
170 void CPVRManagerJobQueue::ExecutePendingJobs()
172 std::vector<CPVRJob*> pendingUpdates;
175 std::unique_lock<CCriticalSection> lock(m_critSection);
177 if (m_bStopped)
178 return;
180 pendingUpdates = std::move(m_pendingUpdates);
181 m_triggerEvent.Reset();
184 CPVRJob* job = nullptr;
185 while (!pendingUpdates.empty())
187 job = pendingUpdates.front();
188 pendingUpdates.erase(pendingUpdates.begin());
190 job->DoWork();
191 delete job;
195 CPVRManager::CPVRManager()
196 : CThread("PVRManager"),
197 m_providers(new CPVRProviders),
198 m_channelGroups(new CPVRChannelGroupsContainer),
199 m_recordings(new CPVRRecordings),
200 m_timers(new CPVRTimers),
201 m_addons(new CPVRClients),
202 m_guiInfo(new CPVRGUIInfo),
203 m_components(new CPVRComponentRegistration),
204 m_epgContainer(new CPVREpgContainer(m_events)),
205 m_pendingUpdates(new CPVRManagerJobQueue),
206 m_database(new CPVRDatabase),
207 m_parentalTimer(new CStopWatch),
208 m_playbackState(new CPVRPlaybackState),
209 m_settings({CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED,
210 CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD,
211 CSettings::SETTING_PVRPARENTAL_ENABLED, CSettings::SETTING_PVRPARENTAL_DURATION})
213 CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this, ANNOUNCEMENT::GUI);
214 m_actionListener.Init(*this);
216 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance created");
219 CPVRManager::~CPVRManager()
221 m_actionListener.Deinit(*this);
222 CServiceBroker::GetAnnouncementManager()->RemoveAnnouncer(this);
224 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance destroyed");
227 void CPVRManager::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
228 const std::string& sender,
229 const std::string& message,
230 const CVariant& data)
232 if (!IsStarted())
233 return;
235 if ((flag & (ANNOUNCEMENT::GUI)))
237 if (message == "OnScreensaverActivated")
238 m_addons->OnPowerSavingActivated();
239 else if (message == "OnScreensaverDeactivated")
240 m_addons->OnPowerSavingDeactivated();
244 std::shared_ptr<CPVRDatabase> CPVRManager::GetTVDatabase() const
246 std::unique_lock<CCriticalSection> lock(m_critSection);
247 if (!m_database || !m_database->IsOpen())
248 CLog::LogF(LOGERROR, "Failed to open the PVR database");
250 return m_database;
253 std::shared_ptr<CPVRProviders> CPVRManager::Providers() const
255 std::unique_lock<CCriticalSection> lock(m_critSection);
256 return m_providers;
259 std::shared_ptr<CPVRChannelGroupsContainer> CPVRManager::ChannelGroups() const
261 std::unique_lock<CCriticalSection> lock(m_critSection);
262 return m_channelGroups;
265 std::shared_ptr<CPVRRecordings> CPVRManager::Recordings() const
267 std::unique_lock<CCriticalSection> lock(m_critSection);
268 return m_recordings;
271 std::shared_ptr<CPVRTimers> CPVRManager::Timers() const
273 std::unique_lock<CCriticalSection> lock(m_critSection);
274 return m_timers;
277 std::shared_ptr<CPVRClients> CPVRManager::Clients() const
279 // note: m_addons is const (only set/reset in ctor/dtor). no need for a lock here.
280 return m_addons;
283 std::shared_ptr<CPVRClient> CPVRManager::GetClient(const CFileItem& item) const
285 int iClientID = PVR_CLIENT_INVALID_UID;
287 if (item.HasPVRChannelInfoTag())
288 iClientID = item.GetPVRChannelInfoTag()->ClientID();
289 else if (item.HasPVRRecordingInfoTag())
290 iClientID = item.GetPVRRecordingInfoTag()->ClientID();
291 else if (item.HasPVRTimerInfoTag())
292 iClientID = item.GetPVRTimerInfoTag()->ClientID();
293 else if (item.HasEPGInfoTag())
294 iClientID = item.GetEPGInfoTag()->ClientID();
295 else if (URIUtils::IsPVRChannel(item.GetPath()))
297 const std::shared_ptr<const CPVRChannel> channel = m_channelGroups->GetByPath(item.GetPath());
298 if (channel)
299 iClientID = channel->ClientID();
301 else if (URIUtils::IsPVRChannelGroup(item.GetPath()))
303 const CPVRChannelsPath path(item.GetPath());
304 iClientID = path.GetGroupClientID();
306 else if (URIUtils::IsPVRRecording(item.GetPath()))
308 const std::shared_ptr<const CPVRRecording> recording = m_recordings->GetByPath(item.GetPath());
309 if (recording)
310 iClientID = recording->ClientID();
312 return GetClient(iClientID);
315 std::shared_ptr<CPVRClient> CPVRManager::GetClient(int iClientId) const
317 return m_addons->GetCreatedClient(iClientId);
320 std::shared_ptr<CPVRPlaybackState> CPVRManager::PlaybackState() const
322 // note: m_playbackState is const (only set/reset in ctor/dtor). no need for a lock here.
323 return m_playbackState;
326 CPVREpgContainer& CPVRManager::EpgContainer()
328 // note: m_epgContainer is const (only set/reset in ctor/dtor). no need for a lock here.
329 return *m_epgContainer;
332 void CPVRManager::Clear()
334 m_playbackState->Clear();
335 m_pendingUpdates->Clear();
337 std::unique_lock<CCriticalSection> lock(m_critSection);
339 m_guiInfo.reset();
340 m_timers.reset();
341 m_recordings.reset();
342 m_providers.reset();
343 m_channelGroups.reset();
344 m_parentalTimer.reset();
345 m_database.reset();
348 void CPVRManager::ResetProperties()
350 std::unique_lock<CCriticalSection> lock(m_critSection);
351 Clear();
353 m_database = std::make_shared<CPVRDatabase>();
354 m_providers = std::make_shared<CPVRProviders>();
355 m_channelGroups = std::make_shared<CPVRChannelGroupsContainer>();
356 m_recordings = std::make_shared<CPVRRecordings>();
357 m_timers = std::make_shared<CPVRTimers>();
358 m_guiInfo = std::make_unique<CPVRGUIInfo>();
359 m_parentalTimer = std::make_unique<CStopWatch>();
360 m_knownClients.clear();
363 void CPVRManager::Init()
365 // initial check for enabled addons
366 // if at least one pvr addon is enabled, PVRManager start up
367 CServiceBroker::GetJobManager()->Submit([this] {
368 Clients()->Start();
369 return true;
373 void CPVRManager::Start()
375 std::unique_lock<CCriticalSection> initLock(m_startStopMutex);
377 // Prevent concurrent starts
378 if (IsInitialising())
379 return;
381 // Note: Stop() must not be called while holding pvr manager's mutex. Stop() calls
382 // StopThread() which can deadlock if the worker thread tries to acquire pvr manager's
383 // lock while StopThread() is waiting for the worker to exit. Thus, we introduce another
384 // lock here (m_startStopMutex), which only gets hold while starting/restarting pvr manager.
385 Stop(true);
387 if (!m_addons->HasCreatedClients())
388 return;
390 CLog::Log(LOGINFO, "PVR Manager: Starting");
391 SetState(ManagerState::STATE_STARTING);
393 /* create the pvrmanager thread, which will ensure that all data will be loaded */
394 Create();
395 SetPriority(ThreadPriority::BELOW_NORMAL);
398 void CPVRManager::Stop(bool bRestart /* = false */)
400 std::unique_lock<CCriticalSection> initLock(m_startStopMutex);
402 // Prevent concurrent stops
403 if (IsStopped())
404 return;
406 /* stop playback if needed */
407 if (!bRestart && m_playbackState->IsPlaying())
409 CLog::LogFC(LOGDEBUG, LOGPVR, "Stopping PVR playback");
410 CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP);
413 CLog::Log(LOGINFO, "PVR Manager: Stopping");
414 SetState(ManagerState::STATE_STOPPING);
416 StopThread();
419 void CPVRManager::Unload()
421 // stop pvr manager thread and clear all pvr data
422 Stop();
423 Clear();
426 void CPVRManager::Deinit()
428 SetWakeupCommand();
429 Unload();
431 // release addons
432 m_addons.reset();
435 CPVRManager::ManagerState CPVRManager::GetState() const
437 std::unique_lock<CCriticalSection> lock(m_managerStateMutex);
438 return m_managerState;
441 void CPVRManager::SetState(CPVRManager::ManagerState state)
444 std::unique_lock<CCriticalSection> lock(m_managerStateMutex);
445 if (m_managerState == state)
446 return;
448 m_managerState = state;
451 PVREvent event;
452 switch (state)
454 case ManagerState::STATE_ERROR:
455 event = PVREvent::ManagerError;
456 break;
457 case ManagerState::STATE_STOPPED:
458 event = PVREvent::ManagerStopped;
459 break;
460 case ManagerState::STATE_STARTING:
461 event = PVREvent::ManagerStarting;
462 break;
463 case ManagerState::STATE_STOPPING:
464 event = PVREvent::ManagerStopped;
465 break;
466 case ManagerState::STATE_INTERRUPTED:
467 event = PVREvent::ManagerInterrupted;
468 break;
469 case ManagerState::STATE_STARTED:
470 event = PVREvent::ManagerStarted;
471 break;
472 default:
473 return;
476 PublishEvent(event);
479 void CPVRManager::PublishEvent(PVREvent event)
481 m_events.Publish(event);
484 void CPVRManager::Process()
486 m_addons->Continue();
487 m_database->Open();
489 if (!IsInitialising())
491 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
492 return;
495 UnloadComponents();
497 if (!IsInitialising())
499 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
500 return;
503 // Wait for at least one client to come up and load/update data
504 UpdateComponents(ManagerState::STATE_STARTING);
506 if (!IsInitialising())
508 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
509 return;
512 // Load EPGs from database.
513 m_epgContainer->Load();
515 // Reinit playbackstate
516 m_playbackState->ReInit();
518 m_guiInfo->Start();
519 m_epgContainer->Start();
520 m_timers->Start();
521 m_pendingUpdates->Start();
523 SetState(ManagerState::STATE_STARTED);
524 CLog::Log(LOGINFO, "PVR Manager: Started");
526 bool bRestart(false);
527 XbmcThreads::EndTime<> cachedImagesCleanupTimeout(30s); // first timeout after 30 secs
529 while (IsStarted() && m_addons->HasCreatedClients() && !bRestart)
531 // In case any new client connected, load from db and fetch data update from new client(s)
532 UpdateComponents(ManagerState::STATE_STARTED);
534 if (cachedImagesCleanupTimeout.IsTimePast())
536 // We don't know for sure what to delete if there are not (yet) connected clients
537 if (m_addons->HasIgnoredClients())
539 cachedImagesCleanupTimeout.Set(10s); // try again in 10 secs
541 else
543 // start a job to erase stale texture db entries and image files
544 TriggerCleanupCachedImages();
545 cachedImagesCleanupTimeout.Set(12h); // following timeouts after 12 hours
549 /* first startup */
550 if (m_bFirstStart)
553 std::unique_lock<CCriticalSection> lock(m_critSection);
554 m_bFirstStart = false;
557 /* start job to search for missing channel icons */
558 TriggerSearchMissingChannelIcons();
560 /* try to play channel on startup */
561 TriggerPlayChannelOnStartup();
564 if (m_addons->AnyClientSupportingRecordingsSize())
565 TriggerRecordingsSizeInProgressUpdate();
567 /* execute the next pending jobs if there are any */
570 m_pendingUpdates->ExecutePendingJobs();
572 catch (...)
574 CLog::LogF(
575 LOGERROR,
576 "An error occurred while trying to execute the last PVR update job, trying to recover");
577 bRestart = true;
580 if (IsStarted() && !bRestart)
581 m_pendingUpdates->WaitForJobs(1000);
584 m_addons->Stop();
585 m_pendingUpdates->Stop();
586 m_timers->Stop();
587 m_epgContainer->Stop();
588 m_guiInfo->Stop();
590 SetState(ManagerState::STATE_INTERRUPTED);
592 UnloadComponents();
593 m_database->Close();
595 ResetProperties();
597 CLog::Log(LOGINFO, "PVR Manager: Stopped");
598 SetState(ManagerState::STATE_STOPPED);
601 bool CPVRManager::SetWakeupCommand()
603 #if !defined(TARGET_DARWIN_EMBEDDED) && !defined(TARGET_WINDOWS_STORE)
604 if (!m_settings.GetBoolValue(CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED))
605 return false;
607 const std::string strWakeupCommand(
608 m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD));
609 if (!strWakeupCommand.empty() && m_timers)
611 const CDateTime nextEvent = m_timers->GetNextEventTime();
612 if (nextEvent.IsValid())
614 time_t iWakeupTime;
615 nextEvent.GetAsTime(iWakeupTime);
617 std::string strExecCommand = StringUtils::Format("{} {}", strWakeupCommand, iWakeupTime);
619 const int iReturn = system(strExecCommand.c_str());
620 if (iReturn != 0)
621 CLog::LogF(LOGERROR, "PVR Manager failed to execute wakeup command '{}': {} ({})",
622 strExecCommand, strerror(iReturn), iReturn);
624 return iReturn == 0;
627 #endif
628 return false;
631 void CPVRManager::OnSleep()
633 PublishEvent(PVREvent::SystemSleep);
635 SetWakeupCommand();
637 m_epgContainer->OnSystemSleep();
638 m_addons->OnSystemSleep();
641 void CPVRManager::OnWake()
643 m_addons->OnSystemWake();
644 m_epgContainer->OnSystemWake();
646 PublishEvent(PVREvent::SystemWake);
648 /* start job to search for missing channel icons */
649 TriggerSearchMissingChannelIcons();
651 /* try to play channel on startup */
652 TriggerPlayChannelOnStartup();
654 /* trigger PVR data updates */
655 TriggerChannelGroupsUpdate();
656 TriggerProvidersUpdate();
657 TriggerChannelsUpdate();
658 TriggerRecordingsUpdate();
659 TriggerTimersUpdate();
662 void CPVRManager::UpdateComponents(ManagerState stateToCheck)
664 XbmcThreads::EndTime<> progressTimeout(30s);
665 std::unique_ptr<CPVRGUIProgressHandler> progressHandler(
666 new CPVRGUIProgressHandler(g_localizeStrings.Get(19235))); // PVR manager is starting up
668 // Wait for at least one client to come up and load/update data
669 while (!UpdateComponents(stateToCheck, progressHandler) && m_addons->HasCreatedClients() &&
670 (stateToCheck == GetState()))
672 CThread::Sleep(1000ms);
674 if (progressTimeout.IsTimePast())
675 progressHandler.reset();
679 bool CPVRManager::UpdateComponents(ManagerState stateToCheck,
680 const std::unique_ptr<CPVRGUIProgressHandler>& progressHandler)
682 // find clients which appeared since last check and update them
683 const CPVRClientMap clientMap = m_addons->GetCreatedClients();
684 if (clientMap.empty())
686 CLog::LogFC(LOGDEBUG, LOGPVR, "All created PVR clients gone!");
687 m_knownClients.clear(); // start over
688 PublishEvent(PVREvent::ClientsInvalidated);
689 return false;
692 std::vector<std::shared_ptr<CPVRClient>> newClients;
693 for (const auto& entry : clientMap)
695 // skip not (yet) connected clients
696 if (entry.second->IgnoreClient())
698 CLog::LogFC(LOGDEBUG, LOGPVR, "Skipping not (yet) connected PVR client {}",
699 entry.second->GetID());
700 continue;
703 if (!IsKnownClient(entry.first))
705 m_knownClients.emplace_back(entry.second);
706 newClients.emplace_back(entry.second);
708 CLog::LogFC(LOGDEBUG, LOGPVR, "Adding new PVR client {} to list of known clients",
709 entry.second->GetID());
713 if (newClients.empty())
714 return !m_knownClients.empty();
716 // Load all channels and groups
717 if (progressHandler)
718 progressHandler->UpdateProgress(g_localizeStrings.Get(19236), 0); // Loading channels and groups
720 if (!m_providers->Update(newClients))
722 CLog::LogF(LOGERROR, "Failed to load PVR providers.");
723 m_knownClients.clear(); // start over
724 PublishEvent(PVREvent::ClientsInvalidated);
725 return false;
728 if (stateToCheck != GetState())
729 return false;
731 if (!m_channelGroups->Update(newClients))
733 CLog::LogF(LOGERROR, "Failed to load PVR channels / groups.");
734 m_knownClients.clear(); // start over
735 PublishEvent(PVREvent::ClientsInvalidated);
736 return false;
739 // Load all timers
740 if (progressHandler)
741 progressHandler->UpdateProgress(g_localizeStrings.Get(19237), 50); // Loading timers
743 if (!m_timers->Update(newClients))
745 CLog::LogF(LOGERROR, "Failed to load PVR timers.");
746 m_knownClients.clear(); // start over
747 PublishEvent(PVREvent::ClientsInvalidated);
748 return false;
751 // Load all recordings
752 if (progressHandler)
753 progressHandler->UpdateProgress(g_localizeStrings.Get(19238), 75); // Loading recordings
755 if (!m_recordings->Update(newClients))
757 CLog::LogF(LOGERROR, "Failed to load PVR recordings.");
758 m_knownClients.clear(); // start over
759 PublishEvent(PVREvent::ClientsInvalidated);
760 return false;
763 // reinit playbackstate as new client may provide new last opened group / last played channel
764 m_playbackState->ReInit();
766 PublishEvent(PVREvent::ClientsInvalidated);
767 return true;
770 void CPVRManager::UnloadComponents()
772 m_recordings->Unload();
773 m_timers->Unload();
774 m_channelGroups->Unload();
775 m_providers->Unload();
776 m_epgContainer->Unload();
779 bool CPVRManager::IsKnownClient(int clientID) const
781 return std::any_of(m_knownClients.cbegin(), m_knownClients.cend(),
782 [clientID](const auto& client) { return client->GetID() == clientID; });
785 void CPVRManager::TriggerPlayChannelOnStartup()
787 if (IsStarted())
789 CServiceBroker::GetJobManager()->Submit(
790 [this] { return Get<PVR::GUI::Playback>().PlayChannelOnStartup(); });
794 void CPVRManager::RestartParentalTimer()
796 if (m_parentalTimer)
797 m_parentalTimer->StartZero();
800 bool CPVRManager::IsParentalLocked(const std::shared_ptr<const CPVREpgInfoTag>& epgTag) const
802 return m_channelGroups && epgTag &&
803 IsCurrentlyParentalLocked(
804 m_channelGroups->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()),
805 epgTag->IsParentalLocked());
808 bool CPVRManager::IsParentalLocked(const std::shared_ptr<const CPVRChannel>& channel) const
810 return channel && IsCurrentlyParentalLocked(channel, channel->IsLocked());
813 bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr<const CPVRChannel>& channel,
814 bool bGenerallyLocked) const
816 bool bReturn = false;
818 if (!channel || !bGenerallyLocked)
819 return bReturn;
821 const std::shared_ptr<const CPVRChannel> currentChannel = m_playbackState->GetPlayingChannel();
823 if ( // if channel in question is currently playing it must be currently unlocked.
824 (!currentChannel || channel != currentChannel) &&
825 // parental control enabled
826 m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED))
828 float parentalDurationMs =
829 m_settings.GetIntValue(CSettings::SETTING_PVRPARENTAL_DURATION) * 1000.0f;
830 bReturn = m_parentalTimer && (!m_parentalTimer->IsRunning() ||
831 m_parentalTimer->GetElapsedMilliseconds() > parentalDurationMs);
834 return bReturn;
837 void CPVRManager::OnPlaybackStarted(const CFileItem& item)
839 m_playbackState->OnPlaybackStarted(item);
840 Get<PVR::GUI::Channels>().OnPlaybackStarted(item);
841 m_epgContainer->OnPlaybackStarted();
844 void CPVRManager::OnPlaybackStopped(const CFileItem& item)
846 // Playback ended due to user interaction
847 if (m_playbackState->OnPlaybackStopped(item))
848 PublishEvent(PVREvent::ChannelPlaybackStopped);
850 Get<PVR::GUI::Channels>().OnPlaybackStopped(item);
851 m_epgContainer->OnPlaybackStopped();
854 void CPVRManager::OnPlaybackEnded(const CFileItem& item)
856 // Playback ended, but not due to user interaction
857 if (m_playbackState->OnPlaybackEnded(item))
858 PublishEvent(PVREvent::ChannelPlaybackStopped);
860 Get<PVR::GUI::Channels>().OnPlaybackStopped(item);
861 m_epgContainer->OnPlaybackStopped();
864 void CPVRManager::LocalizationChanged()
866 std::unique_lock<CCriticalSection> lock(m_critSection);
867 if (IsStarted())
869 static_cast<CPVRChannelGroupAllChannels*>(m_channelGroups->GetGroupAllRadio().get())
870 ->CheckGroupName();
871 static_cast<CPVRChannelGroupAllChannels*>(m_channelGroups->GetGroupAllTV().get())
872 ->CheckGroupName();
876 void CPVRManager::TriggerRecordingsSizeInProgressUpdate()
878 m_pendingUpdates->Append("pvr-update-recordings-size",
879 [this]() { return Recordings()->UpdateInProgressSize(); });
882 void CPVRManager::TriggerRecordingsUpdate(int clientId)
884 m_pendingUpdates->Append("pvr-update-recordings-" + std::to_string(clientId), [this, clientId]() {
885 if (!IsKnownClient(clientId))
886 return;
888 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
889 if (client)
890 Recordings()->UpdateFromClients({client});
894 void CPVRManager::TriggerRecordingsUpdate()
896 m_pendingUpdates->Append("pvr-update-recordings",
897 [this]() { Recordings()->UpdateFromClients({}); });
900 void CPVRManager::TriggerTimersUpdate(int clientId)
902 m_pendingUpdates->Append("pvr-update-timers-" + std::to_string(clientId), [this, clientId]() {
903 if (!IsKnownClient(clientId))
904 return;
906 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
907 if (client)
908 Timers()->UpdateFromClients({client});
912 void CPVRManager::TriggerTimersUpdate()
914 m_pendingUpdates->Append("pvr-update-timers", [this]() { Timers()->UpdateFromClients({}); });
917 void CPVRManager::TriggerProvidersUpdate(int clientId)
919 m_pendingUpdates->Append("pvr-update-channel-providers-" + std::to_string(clientId),
920 [this, clientId]() {
921 if (!IsKnownClient(clientId))
922 return;
924 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
925 if (client)
926 Providers()->UpdateFromClients({client});
930 void CPVRManager::TriggerProvidersUpdate()
932 m_pendingUpdates->Append("pvr-update-channel-providers",
933 [this]() { Providers()->UpdateFromClients({}); });
936 void CPVRManager::TriggerChannelsUpdate(int clientId)
938 m_pendingUpdates->Append("pvr-update-channels-" + std::to_string(clientId), [this, clientId]() {
939 if (!IsKnownClient(clientId))
940 return;
942 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
943 if (client)
944 ChannelGroups()->UpdateFromClients({client}, true);
948 void CPVRManager::TriggerChannelsUpdate()
950 m_pendingUpdates->Append("pvr-update-channels",
951 [this]() { ChannelGroups()->UpdateFromClients({}, true); });
954 void CPVRManager::TriggerChannelGroupsUpdate(int clientId)
956 m_pendingUpdates->Append("pvr-update-channelgroups-" + std::to_string(clientId),
957 [this, clientId]() {
958 if (!IsKnownClient(clientId))
959 return;
961 const std::shared_ptr<CPVRClient> client = GetClient(clientId);
962 if (client)
963 ChannelGroups()->UpdateFromClients({client}, false);
967 void CPVRManager::TriggerChannelGroupsUpdate()
969 m_pendingUpdates->Append("pvr-update-channelgroups",
970 [this]() { ChannelGroups()->UpdateFromClients({}, false); });
973 void CPVRManager::TriggerSearchMissingChannelIcons()
975 m_pendingUpdates->Append("pvr-search-missing-channel-icons", [this]() {
976 CPVRGUIChannelIconUpdater updater(
977 {ChannelGroups()->GetGroupAllTV(), ChannelGroups()->GetGroupAllRadio()}, true);
978 updater.SearchAndUpdateMissingChannelIcons();
979 return true;
983 void CPVRManager::TriggerSearchMissingChannelIcons(const std::shared_ptr<CPVRChannelGroup>& group)
985 m_pendingUpdates->Append("pvr-search-missing-channel-icons-" + std::to_string(group->GroupID()),
986 [group]() {
987 CPVRGUIChannelIconUpdater updater({group}, false);
988 updater.SearchAndUpdateMissingChannelIcons();
989 return true;
993 void CPVRManager::TriggerCleanupCachedImages()
995 m_pendingUpdates->Append("pvr-cleanup-cached-images", [this]() {
996 int iCleanedImages = 0;
997 CLog::Log(LOGINFO, "PVR Manager: Starting cleanup of cached images.");
998 iCleanedImages += Recordings()->CleanupCachedImages();
999 iCleanedImages += ChannelGroups()->CleanupCachedImages();
1000 iCleanedImages += Providers()->CleanupCachedImages();
1001 iCleanedImages += EpgContainer().CleanupCachedImages();
1002 CLog::Log(LOGINFO, "PVR Manager: Cleaned up {} cached images.", iCleanedImages);
1003 return true;
1007 void CPVRManager::ConnectionStateChange(CPVRClient* client,
1008 const std::string& connectString,
1009 PVR_CONNECTION_STATE state,
1010 const std::string& message)
1012 CServiceBroker::GetJobManager()->Submit([this, client, connectString, state, message] {
1013 Clients()->ConnectionStateChange(client, connectString, state, message);
1014 return true;