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.
9 #include "PVRManager.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"
56 using namespace std::chrono_literals
;
64 virtual ~CPVRJob() = default;
66 virtual bool DoWork() = 0;
67 virtual const std::string
GetType() const = 0;
73 class CPVRLambdaJob
: public CPVRJob
76 CPVRLambdaJob() = delete;
77 CPVRLambdaJob(const std::string
& type
, F
&& f
) : m_type(type
), m_f(std::forward
<F
>(f
)) {}
79 bool DoWork() override
85 const std::string
GetType() const override
{ return m_type
; }
92 } // unnamed namespace
97 class CPVRManagerJobQueue
100 CPVRManagerJobQueue() : m_triggerEvent(false) {}
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
));
120 void AppendJob(CPVRJob
* job
);
122 CCriticalSection m_critSection
;
123 CEvent m_triggerEvent
;
124 std::vector
<CPVRJob
*> m_pendingUpdates
;
125 bool m_bStopped
= true;
130 void CPVRManagerJobQueue::Start()
132 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
134 m_triggerEvent
.Set();
137 void CPVRManagerJobQueue::Stop()
139 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
141 m_triggerEvent
.Reset();
144 void CPVRManagerJobQueue::Clear()
146 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
147 for (CPVRJob
* updateJob
: m_pendingUpdates
)
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(); }))
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
);
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());
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
)
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");
253 std::shared_ptr
<CPVRProviders
> CPVRManager::Providers() const
255 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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
);
271 std::shared_ptr
<CPVRTimers
> CPVRManager::Timers() const
273 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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.
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());
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());
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
);
341 m_recordings
.reset();
343 m_channelGroups
.reset();
344 m_parentalTimer
.reset();
348 void CPVRManager::ResetProperties()
350 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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] {
373 void CPVRManager::Start()
375 std::unique_lock
<CCriticalSection
> initLock(m_startStopMutex
);
377 // Prevent concurrent starts
378 if (IsInitialising())
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.
387 if (!m_addons
->HasCreatedClients())
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 */
395 SetPriority(ThreadPriority::BELOW_NORMAL
);
398 void CPVRManager::Stop(bool bRestart
/* = false */)
400 std::unique_lock
<CCriticalSection
> initLock(m_startStopMutex
);
402 // Prevent concurrent stops
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
);
419 void CPVRManager::Unload()
421 // stop pvr manager thread and clear all pvr data
426 void CPVRManager::Deinit()
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
)
448 m_managerState
= state
;
454 case ManagerState::STATE_ERROR
:
455 event
= PVREvent::ManagerError
;
457 case ManagerState::STATE_STOPPED
:
458 event
= PVREvent::ManagerStopped
;
460 case ManagerState::STATE_STARTING
:
461 event
= PVREvent::ManagerStarting
;
463 case ManagerState::STATE_STOPPING
:
464 event
= PVREvent::ManagerStopped
;
466 case ManagerState::STATE_INTERRUPTED
:
467 event
= PVREvent::ManagerInterrupted
;
469 case ManagerState::STATE_STARTED
:
470 event
= PVREvent::ManagerStarted
;
479 void CPVRManager::PublishEvent(PVREvent event
)
481 m_events
.Publish(event
);
484 void CPVRManager::Process()
486 m_addons
->Continue();
489 if (!IsInitialising())
491 CLog::Log(LOGINFO
, "PVR Manager: Start aborted");
497 if (!IsInitialising())
499 CLog::Log(LOGINFO
, "PVR Manager: Start aborted");
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");
512 // Load EPGs from database.
513 m_epgContainer
->Load();
515 // Reinit playbackstate
516 m_playbackState
->ReInit();
519 m_epgContainer
->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
543 // start a job to erase stale texture db entries and image files
544 TriggerCleanupCachedImages();
545 cachedImagesCleanupTimeout
.Set(12h
); // following timeouts after 12 hours
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();
576 "An error occurred while trying to execute the last PVR update job, trying to recover");
580 if (IsStarted() && !bRestart
)
581 m_pendingUpdates
->WaitForJobs(1000);
585 m_pendingUpdates
->Stop();
587 m_epgContainer
->Stop();
590 SetState(ManagerState::STATE_INTERRUPTED
);
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
))
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())
615 nextEvent
.GetAsTime(iWakeupTime
);
617 std::string strExecCommand
= StringUtils::Format("{} {}", strWakeupCommand
, iWakeupTime
);
619 const int iReturn
= system(strExecCommand
.c_str());
621 CLog::LogF(LOGERROR
, "PVR Manager failed to execute wakeup command '{}': {} ({})",
622 strExecCommand
, strerror(iReturn
), iReturn
);
631 void CPVRManager::OnSleep()
633 PublishEvent(PVREvent::SystemSleep
);
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
);
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());
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
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
);
728 if (stateToCheck
!= GetState())
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
);
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
);
751 // Load all recordings
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
);
763 // reinit playbackstate as new client may provide new last opened group / last played channel
764 m_playbackState
->ReInit();
766 PublishEvent(PVREvent::ClientsInvalidated
);
770 void CPVRManager::UnloadComponents()
772 m_recordings
->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()
789 CServiceBroker::GetJobManager()->Submit(
790 [this] { return Get
<PVR::GUI::Playback
>().PlayChannelOnStartup(); });
794 void CPVRManager::RestartParentalTimer()
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
)
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
);
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
);
869 static_cast<CPVRChannelGroupAllChannels
*>(m_channelGroups
->GetGroupAllRadio().get())
871 static_cast<CPVRChannelGroupAllChannels
*>(m_channelGroups
->GetGroupAllTV().get())
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
))
888 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
))
906 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
),
921 if (!IsKnownClient(clientId
))
924 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
))
942 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
),
958 if (!IsKnownClient(clientId
))
961 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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();
983 void CPVRManager::TriggerSearchMissingChannelIcons(const std::shared_ptr
<CPVRChannelGroup
>& group
)
985 m_pendingUpdates
->Append("pvr-search-missing-channel-icons-" + std::to_string(group
->GroupID()),
987 CPVRGUIChannelIconUpdater
updater({group
}, false);
988 updater
.SearchAndUpdateMissingChannelIcons();
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
);
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
);