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/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"
55 using namespace std::chrono_literals
;
63 virtual ~CPVRJob() = default;
65 virtual bool DoWork() = 0;
66 virtual const std::string
GetType() const = 0;
72 class CPVRLambdaJob
: public CPVRJob
75 CPVRLambdaJob() = delete;
76 CPVRLambdaJob(const std::string
& type
, F
&& f
) : m_type(type
), m_f(std::forward
<F
>(f
)) {}
78 bool DoWork() override
84 const std::string
GetType() const override
{ return m_type
; }
91 } // unnamed namespace
96 class CPVRManagerJobQueue
99 CPVRManagerJobQueue() : m_triggerEvent(false) {}
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
));
119 void AppendJob(CPVRJob
* job
);
121 CCriticalSection m_critSection
;
122 CEvent m_triggerEvent
;
123 std::vector
<CPVRJob
*> m_pendingUpdates
;
124 bool m_bStopped
= true;
129 void CPVRManagerJobQueue::Start()
131 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
133 m_triggerEvent
.Set();
136 void CPVRManagerJobQueue::Stop()
138 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
140 m_triggerEvent
.Reset();
143 void CPVRManagerJobQueue::Clear()
145 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
146 for (CPVRJob
* updateJob
: m_pendingUpdates
)
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(); }))
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
);
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());
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
)
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");
252 std::shared_ptr
<CPVRProviders
> CPVRManager::Providers() const
254 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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
);
270 std::shared_ptr
<CPVRTimers
> CPVRManager::Timers() const
272 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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.
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());
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());
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
);
340 m_recordings
.reset();
342 m_channelGroups
.reset();
343 m_parentalTimer
.reset();
347 void CPVRManager::ResetProperties()
349 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
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] {
372 void CPVRManager::Start()
374 std::unique_lock
<CCriticalSection
> initLock(m_startStopMutex
);
376 // Prevent concurrent starts
377 if (IsInitialising())
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.
386 if (!m_addons
->HasCreatedClients())
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 */
394 SetPriority(ThreadPriority::BELOW_NORMAL
);
397 void CPVRManager::Stop(bool bRestart
/* = false */)
399 std::unique_lock
<CCriticalSection
> initLock(m_startStopMutex
);
401 // Prevent concurrent stops
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
);
418 void CPVRManager::Unload()
420 // stop pvr manager thread and clear all pvr data
425 void CPVRManager::Deinit()
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
)
447 m_managerState
= state
;
453 case ManagerState::STATE_ERROR
:
454 event
= PVREvent::ManagerError
;
456 case ManagerState::STATE_STOPPED
:
457 event
= PVREvent::ManagerStopped
;
459 case ManagerState::STATE_STARTING
:
460 event
= PVREvent::ManagerStarting
;
462 case ManagerState::STATE_STOPPING
:
463 event
= PVREvent::ManagerStopped
;
465 case ManagerState::STATE_INTERRUPTED
:
466 event
= PVREvent::ManagerInterrupted
;
468 case ManagerState::STATE_STARTED
:
469 event
= PVREvent::ManagerStarted
;
478 void CPVRManager::PublishEvent(PVREvent event
)
480 m_events
.Publish(event
);
483 void CPVRManager::Process()
485 m_addons
->Continue();
488 if (!IsInitialising())
490 CLog::Log(LOGINFO
, "PVR Manager: Start aborted");
496 if (!IsInitialising())
498 CLog::Log(LOGINFO
, "PVR Manager: Start aborted");
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");
511 // Load EPGs from database.
512 m_epgContainer
->Load();
514 // Reinit playbackstate
515 m_playbackState
->ReInit();
518 m_epgContainer
->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
542 // start a job to erase stale texture db entries and image files
543 TriggerCleanupCachedImages();
544 cachedImagesCleanupTimeout
.Set(12h
); // following timeouts after 12 hours
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();
575 "An error occurred while trying to execute the last PVR update job, trying to recover");
579 if (IsStarted() && !bRestart
)
580 m_pendingUpdates
->WaitForJobs(1000);
584 m_pendingUpdates
->Stop();
586 m_epgContainer
->Stop();
589 SetState(ManagerState::STATE_INTERRUPTED
);
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
))
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())
614 nextEvent
.GetAsTime(iWakeupTime
);
616 std::string strExecCommand
= StringUtils::Format("{} {}", strWakeupCommand
, iWakeupTime
);
618 const int iReturn
= system(strExecCommand
.c_str());
620 CLog::LogF(LOGERROR
, "PVR Manager failed to execute wakeup command '{}': {} ({})",
621 strExecCommand
, strerror(iReturn
), iReturn
);
630 void CPVRManager::OnSleep()
632 PublishEvent(PVREvent::SystemSleep
);
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
);
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());
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
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
);
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
);
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
);
747 // Load all recordings
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
);
759 // reinit playbackstate as new client may provide new last opened group / last played channel
760 m_playbackState
->ReInit();
762 PublishEvent(PVREvent::ClientsInvalidated
);
766 void CPVRManager::UnloadComponents()
768 m_recordings
->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()
785 CServiceBroker::GetJobManager()->Submit(
786 [this] { return Get
<PVR::GUI::Playback
>().PlayChannelOnStartup(); });
790 void CPVRManager::RestartParentalTimer()
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
)
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
);
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
);
865 static_cast<CPVRChannelGroupAllChannels
*>(m_channelGroups
->GetGroupAllRadio().get())
867 static_cast<CPVRChannelGroupAllChannels
*>(m_channelGroups
->GetGroupAllTV().get())
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
))
884 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
))
902 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
),
917 if (!IsKnownClient(clientId
))
920 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
))
938 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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
),
954 if (!IsKnownClient(clientId
))
957 const std::shared_ptr
<CPVRClient
> client
= GetClient(clientId
);
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();
979 void CPVRManager::TriggerSearchMissingChannelIcons(const std::shared_ptr
<CPVRChannelGroup
>& group
)
981 m_pendingUpdates
->Append("pvr-search-missing-channel-icons-" + std::to_string(group
->GroupID()),
983 CPVRGUIChannelIconUpdater
updater({group
}, false);
984 updater
.SearchAndUpdateMissingChannelIcons();
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
);
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
);