1 /*
2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "PVRManager.h"
10
11 #include "ServiceBroker.h"
12 #include "guilib/LocalizeStrings.h"
13 #include "interfaces/AnnouncementManager.h"
14 #include "messaging/ApplicationMessenger.h"
15 #include "pvr/PVRDatabase.h"
16 #include "pvr/PVRPlaybackState.h"
17 #include "pvr/addons/PVRClient.h"
18 #include "pvr/addons/PVRClients.h"
19 #include "pvr/channels/PVRChannel.h"
20 #include "pvr/channels/PVRChannelGroup.h"
21 #include "pvr/channels/PVRChannelGroupInternal.h"
22 #include "pvr/channels/PVRChannelGroups.h"
23 #include "pvr/channels/PVRChannelGroupsContainer.h"
24 #include "pvr/epg/EpgInfoTag.h"
25 #include "pvr/guilib/PVRGUIActions.h"
26 #include "pvr/guilib/PVRGUIChannelIconUpdater.h"
27 #include "pvr/guilib/PVRGUIProgressHandler.h"
28 #include "pvr/guilib/guiinfo/PVRGUIInfo.h"
29 #include "pvr/recordings/PVRRecording.h"
30 #include "pvr/recordings/PVRRecordings.h"
31 #include "pvr/timers/PVRTimerInfoTag.h"
32 #include "pvr/timers/PVRTimers.h"
33 #include "settings/Settings.h"
34 #include "utils/JobManager.h"
35 #include "utils/Stopwatch.h"
36 #include "utils/StringUtils.h"
37 #include "utils/URIUtils.h"
38 #include "utils/log.h"
39
40 #include <memory>
41 #include <string>
42 #include <utility>
43 #include <vector>
44
45 using namespace PVR;
46 using namespace KODI::MESSAGING;
47
48 namespace PVR
49 {
50 template<typename F>
51 class CPVRLambdaJob : public CJob
52 {
53 public:
54 CPVRLambdaJob() = delete;
CPVRLambdaJob(const std::string & type,F && f)55 CPVRLambdaJob(const std::string& type, F&& f) : m_type(type), m_f(std::forward<F>(f)) {}
56
DoWork()57 bool DoWork() override
58 {
59 m_f();
60 return true;
61 }
62
GetType() const63 const char* GetType() const override
64 {
65 return m_type.c_str();
66 }
67
68 private:
69 std::string m_type;
70 F m_f;
71 };
72
73 class CPVRManagerJobQueue
74 {
75 public:
CPVRManagerJobQueue()76 CPVRManagerJobQueue() : m_triggerEvent(false) {}
77
78 void Start();
79 void Stop();
80 void Clear();
81
82 template<typename F>
Append(const std::string & type,F && f)83 void Append(const std::string& type, F&& f)
84 {
85 AppendJob(new CPVRLambdaJob<F>(type, std::forward<F>(f)));
86 }
87
88 void ExecutePendingJobs();
89
WaitForJobs(unsigned int milliSeconds)90 bool WaitForJobs(unsigned int milliSeconds)
91 {
92 return m_triggerEvent.WaitMSec(milliSeconds);
93 }
94
95
96 private:
97 void AppendJob(CJob* job);
98
99 CCriticalSection m_critSection;
100 CEvent m_triggerEvent;
101 std::vector<CJob*> m_pendingUpdates;
102 bool m_bStopped = true;
103 };
104 } // namespace PVR
105
Start()106 void CPVRManagerJobQueue::Start()
107 {
108 CSingleLock lock(m_critSection);
109 m_bStopped = false;
110 m_triggerEvent.Set();
111 }
112
Stop()113 void CPVRManagerJobQueue::Stop()
114 {
115 CSingleLock lock(m_critSection);
116 m_bStopped = true;
117 m_triggerEvent.Reset();
118 }
119
Clear()120 void CPVRManagerJobQueue::Clear()
121 {
122 CSingleLock lock(m_critSection);
123 for (CJob* updateJob : m_pendingUpdates)
124 delete updateJob;
125
126 m_pendingUpdates.clear();
127 m_triggerEvent.Set();
128 }
129
AppendJob(CJob * job)130 void CPVRManagerJobQueue::AppendJob(CJob* job)
131 {
132 CSingleLock lock(m_critSection);
133
134 // check for another pending job of given type...
135 for (CJob* updateJob : m_pendingUpdates)
136 {
137 if (!strcmp(updateJob->GetType(), job->GetType()))
138 {
139 delete job;
140 return;
141 }
142 }
143
144 m_pendingUpdates.push_back(job);
145 m_triggerEvent.Set();
146 }
147
ExecutePendingJobs()148 void CPVRManagerJobQueue::ExecutePendingJobs()
149 {
150 std::vector<CJob*> pendingUpdates;
151
152 {
153 CSingleLock lock(m_critSection);
154
155 if (m_bStopped)
156 return;
157
158 pendingUpdates = std::move(m_pendingUpdates);
159 m_triggerEvent.Reset();
160 }
161
162 CJob* job = nullptr;
163 while (!pendingUpdates.empty())
164 {
165 job = pendingUpdates.front();
166 pendingUpdates.erase(pendingUpdates.begin());
167
168 job->DoWork();
169 delete job;
170 }
171 }
172
CPVRManager()173 CPVRManager::CPVRManager() :
174 CThread("PVRManager"),
175 m_channelGroups(new CPVRChannelGroupsContainer),
176 m_recordings(new CPVRRecordings),
177 m_timers(new CPVRTimers),
178 m_addons(new CPVRClients),
179 m_guiInfo(new CPVRGUIInfo),
180 m_guiActions(new CPVRGUIActions),
181 m_pendingUpdates(new CPVRManagerJobQueue),
182 m_database(new CPVRDatabase),
183 m_parentalTimer(new CStopWatch),
184 m_playbackState(new CPVRPlaybackState),
185 m_settings({
186 CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED,
187 CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD,
188 CSettings::SETTING_PVRPARENTAL_ENABLED,
189 CSettings::SETTING_PVRPARENTAL_DURATION
190 })
191 {
192 CServiceBroker::GetAnnouncementManager()->AddAnnouncer(this);
193 m_actionListener.Init(*this);
194
195 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance created");
196 }
197
~CPVRManager()198 CPVRManager::~CPVRManager()
199 {
200 m_actionListener.Deinit(*this);
201 CServiceBroker::GetAnnouncementManager()->RemoveAnnouncer(this);
202
203 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager instance destroyed");
204 }
205
Announce(ANNOUNCEMENT::AnnouncementFlag flag,const std::string & sender,const std::string & message,const CVariant & data)206 void CPVRManager::Announce(ANNOUNCEMENT::AnnouncementFlag flag,
207 const std::string& sender,
208 const std::string& message,
209 const CVariant& data)
210 {
211 if (!IsStarted())
212 return;
213
214 if ((flag & (ANNOUNCEMENT::GUI)))
215 {
216 if (message == "OnScreensaverActivated")
217 m_addons->OnPowerSavingActivated();
218 else if (message == "OnScreensaverDeactivated")
219 m_addons->OnPowerSavingDeactivated();
220 }
221 }
222
GetTVDatabase() const223 std::shared_ptr<CPVRDatabase> CPVRManager::GetTVDatabase() const
224 {
225 CSingleLock lock(m_critSection);
226 if (!m_database || !m_database->IsOpen())
227 CLog::LogF(LOGERROR, "Failed to open the PVR database");
228
229 return m_database;
230 }
231
ChannelGroups() const232 std::shared_ptr<CPVRChannelGroupsContainer> CPVRManager::ChannelGroups() const
233 {
234 CSingleLock lock(m_critSection);
235 return m_channelGroups;
236 }
237
Recordings() const238 std::shared_ptr<CPVRRecordings> CPVRManager::Recordings() const
239 {
240 CSingleLock lock(m_critSection);
241 return m_recordings;
242 }
243
Timers() const244 std::shared_ptr<CPVRTimers> CPVRManager::Timers() const
245 {
246 CSingleLock lock(m_critSection);
247 return m_timers;
248 }
249
Clients() const250 std::shared_ptr<CPVRClients> CPVRManager::Clients() const
251 {
252 // note: m_addons is const (only set/reset in ctor/dtor). no need for a lock here.
253 return m_addons;
254 }
255
GetClient(const CFileItem & item) const256 std::shared_ptr<CPVRClient> CPVRManager::GetClient(const CFileItem& item) const
257 {
258 int iClientID = PVR_INVALID_CLIENT_ID;
259
260 if (item.HasPVRChannelInfoTag())
261 iClientID = item.GetPVRChannelInfoTag()->ClientID();
262 else if (item.HasPVRRecordingInfoTag())
263 iClientID = item.GetPVRRecordingInfoTag()->m_iClientId;
264 else if (item.HasPVRTimerInfoTag())
265 iClientID = item.GetPVRTimerInfoTag()->m_iClientId;
266 else if (item.HasEPGInfoTag())
267 iClientID = item.GetEPGInfoTag()->ClientID();
268 else if (URIUtils::IsPVRChannel(item.GetPath()))
269 {
270 const std::shared_ptr<CPVRChannel> channel = m_channelGroups->GetByPath(item.GetPath());
271 if (channel)
272 iClientID = channel->ClientID();
273 }
274 else if (URIUtils::IsPVRRecording(item.GetPath()))
275 {
276 const std::shared_ptr<CPVRRecording> recording = m_recordings->GetByPath(item.GetPath());
277 if (recording)
278 iClientID = recording->ClientID();
279 }
280 return GetClient(iClientID);
281 }
282
GetClient(int iClientId) const283 std::shared_ptr<CPVRClient> CPVRManager::GetClient(int iClientId) const
284 {
285 std::shared_ptr<CPVRClient> client;
286 if (iClientId != PVR_INVALID_CLIENT_ID)
287 m_addons->GetCreatedClient(iClientId, client);
288
289 return client;
290 }
291
GUIActions() const292 std::shared_ptr<CPVRGUIActions> CPVRManager::GUIActions() const
293 {
294 // note: m_guiActions is const (only set/reset in ctor/dtor). no need for a lock here.
295 return m_guiActions;
296 }
297
PlaybackState() const298 std::shared_ptr<CPVRPlaybackState> CPVRManager::PlaybackState() const
299 {
300 // note: m_playbackState is const (only set/reset in ctor/dtor). no need for a lock here.
301 return m_playbackState;
302 }
303
EpgContainer()304 CPVREpgContainer& CPVRManager::EpgContainer()
305 {
306 // note: m_epgContainer is const (only set/reset in ctor/dtor). no need for a lock here.
307 return m_epgContainer;
308 }
309
Clear()310 void CPVRManager::Clear()
311 {
312 m_playbackState->Clear();
313 m_pendingUpdates->Clear();
314
315 CSingleLock lock(m_critSection);
316
317 m_guiInfo.reset();
318 m_timers.reset();
319 m_recordings.reset();
320 m_channelGroups.reset();
321 m_parentalTimer.reset();
322 m_database.reset();
323
324 m_bEpgsCreated = false;
325 }
326
ResetProperties()327 void CPVRManager::ResetProperties()
328 {
329 CSingleLock lock(m_critSection);
330 Clear();
331
332 m_database.reset(new CPVRDatabase);
333 m_channelGroups.reset(new CPVRChannelGroupsContainer);
334 m_recordings.reset(new CPVRRecordings);
335 m_timers.reset(new CPVRTimers);
336 m_guiInfo.reset(new CPVRGUIInfo);
337 m_parentalTimer.reset(new CStopWatch);
338 }
339
Init()340 void CPVRManager::Init()
341 {
342 // initial check for enabled addons
343 // if at least one pvr addon is enabled, PVRManager start up
344 CJobManager::GetInstance().Submit([this] {
345 Clients()->Start();
346 return true;
347 });
348 }
349
Start()350 void CPVRManager::Start()
351 {
352 CSingleLock initLock(m_startStopMutex);
353
354 // Prevent concurrent starts
355 if (IsInitialising())
356 return;
357
358 // Note: Stop() must not be called while holding pvr manager's mutex. Stop() calls
359 // StopThread() which can deadlock if the worker thread tries to acquire pvr manager's
360 // lock while StopThread() is waiting for the worker to exit. Thus, we introduce another
361 // lock here (m_startStopMutex), which only gets hold while starting/restarting pvr manager.
362 Stop(true);
363
364 if (!m_addons->HasCreatedClients())
365 return;
366
367 CLog::Log(LOGINFO, "PVR Manager: Starting");
368 SetState(ManagerStateStarting);
369
370 /* create the pvrmanager thread, which will ensure that all data will be loaded */
371 Create();
372 SetPriority(-1);
373 }
374
Stop(bool bRestart)375 void CPVRManager::Stop(bool bRestart /* = false */)
376 {
377 CSingleLock initLock(m_startStopMutex);
378
379 // Prevent concurrent stops
380 if (IsStopped())
381 return;
382
383 /* stop playback if needed */
384 if (!bRestart && m_playbackState->IsPlaying())
385 {
386 CLog::LogFC(LOGDEBUG, LOGPVR, "Stopping PVR playback");
387 CApplicationMessenger::GetInstance().SendMsg(TMSG_MEDIA_STOP);
388 }
389
390 CLog::Log(LOGINFO, "PVR Manager: Stopping");
391 SetState(ManagerStateStopping);
392
393 m_addons->Stop();
394 m_pendingUpdates->Stop();
395 m_timers->Stop();
396 m_epgContainer.Stop();
397 m_guiInfo->Stop();
398
399 StopThread();
400
401 SetState(ManagerStateInterrupted);
402
403 UnloadComponents();
404 m_database->Close();
405
406 ResetProperties();
407
408 CLog::Log(LOGINFO, "PVR Manager: Stopped");
409 SetState(ManagerStateStopped);
410 }
411
Unload()412 void CPVRManager::Unload()
413 {
414 // stop pvr manager thread and clear all pvr data
415 Stop();
416 Clear();
417 }
418
Deinit()419 void CPVRManager::Deinit()
420 {
421 SetWakeupCommand();
422 Unload();
423
424 // release addons
425 m_addons.reset();
426 }
427
GetState() const428 CPVRManager::ManagerState CPVRManager::GetState() const
429 {
430 CSingleLock lock(m_managerStateMutex);
431 return m_managerState;
432 }
433
SetState(CPVRManager::ManagerState state)434 void CPVRManager::SetState(CPVRManager::ManagerState state)
435 {
436 {
437 CSingleLock lock(m_managerStateMutex);
438 if (m_managerState == state)
439 return;
440
441 m_managerState = state;
442 }
443
444 PVREvent event;
445 switch (state)
446 {
447 case ManagerStateError:
448 event = PVREvent::ManagerError;
449 break;
450 case ManagerStateStopped:
451 event = PVREvent::ManagerStopped;
452 break;
453 case ManagerStateStarting:
454 event = PVREvent::ManagerStarting;
455 break;
456 case ManagerStateStopping:
457 event = PVREvent::ManagerStopped;
458 break;
459 case ManagerStateInterrupted:
460 event = PVREvent::ManagerInterrupted;
461 break;
462 case ManagerStateStarted:
463 event = PVREvent::ManagerStarted;
464 break;
465 default:
466 return;
467 }
468
469 PublishEvent(event);
470 }
471
PublishEvent(PVREvent event)472 void CPVRManager::PublishEvent(PVREvent event)
473 {
474 m_events.Publish(event);
475 }
476
Process()477 void CPVRManager::Process()
478 {
479 m_addons->Continue();
480 m_database->Open();
481
482 /* load the pvr data from the db and clients if it's not already loaded */
483 XbmcThreads::EndTime progressTimeout(30000); // 30 secs
484 CPVRGUIProgressHandler* progressHandler = new CPVRGUIProgressHandler(g_localizeStrings.Get(19235)); // PVR manager is starting up
485 while (!LoadComponents(progressHandler) && IsInitialising())
486 {
487 CLog::Log(LOGWARNING, "PVR Manager failed to load data, retrying");
488 CThread::Sleep(1000);
489
490 if (progressHandler && progressTimeout.IsTimePast())
491 {
492 progressHandler->DestroyProgress();
493 progressHandler = nullptr; // no delete, instance is deleting itself
494 }
495 }
496
497 if (progressHandler)
498 {
499 progressHandler->DestroyProgress();
500 progressHandler = nullptr; // no delete, instance is deleting itself
501 }
502
503 if (!IsInitialising())
504 {
505 CLog::Log(LOGINFO, "PVR Manager: Start aborted");
506 return;
507 }
508
509 // Load EPGs from database.
510 m_epgContainer.Load();
511
512 // Reinit playbackstate
513 m_playbackState->ReInit();
514
515 m_guiInfo->Start();
516 m_epgContainer.Start();
517 m_timers->Start();
518 m_pendingUpdates->Start();
519
520 SetState(ManagerStateStarted);
521 CLog::Log(LOGINFO, "PVR Manager: Started");
522
523 /* main loop */
524 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager entering main loop");
525
526 bool bRestart(false);
527 while (IsStarted() && m_addons->HasCreatedClients() && !bRestart)
528 {
529 /* first startup */
530 if (m_bFirstStart)
531 {
532 {
533 CSingleLock lock(m_critSection);
534 m_bFirstStart = false;
535 }
536
537 /* start job to search for missing channel icons */
538 TriggerSearchMissingChannelIcons();
539
540 /* try to play channel on startup */
541 TriggerPlayChannelOnStartup();
542 }
543
544 if (m_addons->AnyClientSupportingRecordingsSize())
545 TriggerRecordingsSizeInProgressUpdate();
546
547 /* execute the next pending jobs if there are any */
548 try
549 {
550 m_pendingUpdates->ExecutePendingJobs();
551 }
552 catch (...)
553 {
554 CLog::LogF(LOGERROR, "An error occurred while trying to execute the last PVR update job, trying to recover");
555 bRestart = true;
556 }
557
558 if (IsStarted() && !bRestart)
559 m_pendingUpdates->WaitForJobs(1000);
560 }
561
562 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager leaving main loop");
563 }
564
SetWakeupCommand()565 bool CPVRManager::SetWakeupCommand()
566 {
567 #if !defined(TARGET_DARWIN_EMBEDDED) && !defined(TARGET_WINDOWS_STORE)
568 if (!m_settings.GetBoolValue(CSettings::SETTING_PVRPOWERMANAGEMENT_ENABLED))
569 return false;
570
571 const std::string strWakeupCommand(m_settings.GetStringValue(CSettings::SETTING_PVRPOWERMANAGEMENT_SETWAKEUPCMD));
572 if (!strWakeupCommand.empty() && m_timers)
573 {
574 time_t iWakeupTime;
575 const CDateTime nextEvent = m_timers->GetNextEventTime();
576 if (nextEvent.IsValid())
577 {
578 nextEvent.GetAsTime(iWakeupTime);
579
580 std::string strExecCommand = StringUtils::Format("%s %ld", strWakeupCommand.c_str(), iWakeupTime);
581
582 const int iReturn = system(strExecCommand.c_str());
583 if (iReturn != 0)
584 CLog::LogF(LOGERROR, "PVR Manager failed to execute wakeup command '{}': {} ({})",
585 strExecCommand, strerror(iReturn), iReturn);
586
587 return iReturn == 0;
588 }
589 }
590 #endif
591 return false;
592 }
593
OnSleep()594 void CPVRManager::OnSleep()
595 {
596 PublishEvent(PVREvent::SystemSleep);
597
598 SetWakeupCommand();
599
600 m_epgContainer.OnSystemSleep();
601
602 m_addons->OnSystemSleep();
603 }
604
OnWake()605 void CPVRManager::OnWake()
606 {
607 m_addons->OnSystemWake();
608
609 m_epgContainer.OnSystemWake();
610
611 PublishEvent(PVREvent::SystemWake);
612
613 /* start job to search for missing channel icons */
614 TriggerSearchMissingChannelIcons();
615
616 /* try to play channel on startup */
617 TriggerPlayChannelOnStartup();
618
619 /* trigger PVR data updates */
620 TriggerChannelGroupsUpdate();
621 TriggerChannelsUpdate();
622 TriggerRecordingsUpdate();
623 TriggerEpgsCreate();
624 TriggerTimersUpdate();
625 }
626
LoadComponents(CPVRGUIProgressHandler * progressHandler)627 bool CPVRManager::LoadComponents(CPVRGUIProgressHandler* progressHandler)
628 {
629 /* load at least one client */
630 while (IsInitialising() && m_addons && !m_addons->HasCreatedClients())
631 CThread::Sleep(50);
632
633 if (!IsInitialising() || !m_addons->HasCreatedClients())
634 return false;
635
636 CLog::LogFC(LOGDEBUG, LOGPVR, "PVR Manager found active clients. Continuing startup");
637
638 /* load all channels and groups */
639 if (progressHandler)
640 progressHandler->UpdateProgress(g_localizeStrings.Get(19236), 0); // Loading channels from clients
641
642 if (!m_channelGroups->Load() || !IsInitialising())
643 return false;
644
645 PublishEvent(PVREvent::ChannelGroupsLoaded);
646
647 /* get timers from the backends */
648 if (progressHandler)
649 progressHandler->UpdateProgress(g_localizeStrings.Get(19237), 50); // Loading timers from clients
650
651 m_timers->Load();
652
653 /* get recordings from the backend */
654 if (progressHandler)
655 progressHandler->UpdateProgress(g_localizeStrings.Get(19238), 75); // Loading recordings from clients
656
657 m_recordings->Load();
658
659 if (!IsInitialising())
660 return false;
661
662 /* start the other pvr related update threads */
663 if (progressHandler)
664 progressHandler->UpdateProgress(g_localizeStrings.Get(19239), 85); // Starting background threads
665
666 return true;
667 }
668
UnloadComponents()669 void CPVRManager::UnloadComponents()
670 {
671 m_recordings->Unload();
672 m_timers->Unload();
673 m_channelGroups->Unload();
674 m_epgContainer.Unload();
675 }
676
TriggerPlayChannelOnStartup()677 void CPVRManager::TriggerPlayChannelOnStartup()
678 {
679 if (IsStarted())
680 {
681 CJobManager::GetInstance().Submit([this] {
682 return GUIActions()->PlayChannelOnStartup();
683 });
684 }
685 }
686
RestartParentalTimer()687 void CPVRManager::RestartParentalTimer()
688 {
689 if (m_parentalTimer)
690 m_parentalTimer->StartZero();
691 }
692
IsParentalLocked(const std::shared_ptr<CPVREpgInfoTag> & epgTag) const693 bool CPVRManager::IsParentalLocked(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
694 {
695 return m_channelGroups &&
696 epgTag &&
697 IsCurrentlyParentalLocked(m_channelGroups->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()),
698 epgTag->IsParentalLocked());
699 }
700
IsParentalLocked(const std::shared_ptr<CPVRChannel> & channel) const701 bool CPVRManager::IsParentalLocked(const std::shared_ptr<CPVRChannel>& channel) const
702 {
703 return channel &&
704 IsCurrentlyParentalLocked(channel, channel->IsLocked());
705 }
706
IsCurrentlyParentalLocked(const std::shared_ptr<CPVRChannel> & channel,bool bGenerallyLocked) const707 bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr<CPVRChannel>& channel, bool bGenerallyLocked) const
708 {
709 bool bReturn = false;
710
711 if (!channel || !bGenerallyLocked)
712 return bReturn;
713
714 const std::shared_ptr<CPVRChannel> currentChannel = m_playbackState->GetPlayingChannel();
715
716 if (// if channel in question is currently playing it must be currently unlocked.
717 (!currentChannel || channel != currentChannel) &&
718 // parental control enabled
719 m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED))
720 {
721 float parentalDurationMs = m_settings.GetIntValue(CSettings::SETTING_PVRPARENTAL_DURATION) * 1000.0f;
722 bReturn = m_parentalTimer &&
723 (!m_parentalTimer->IsRunning() ||
724 m_parentalTimer->GetElapsedMilliseconds() > parentalDurationMs);
725 }
726
727 return bReturn;
728 }
729
OnPlaybackStarted(const CFileItemPtr & item)730 void CPVRManager::OnPlaybackStarted(const CFileItemPtr& item)
731 {
732 m_playbackState->OnPlaybackStarted(item);
733 m_guiActions->OnPlaybackStarted(item);
734 m_epgContainer.OnPlaybackStarted();
735 }
736
OnPlaybackStopped(const CFileItemPtr & item)737 void CPVRManager::OnPlaybackStopped(const CFileItemPtr& item)
738 {
739 // Playback ended due to user interaction
740 if (m_playbackState->OnPlaybackStopped(item))
741 PublishEvent(PVREvent::ChannelPlaybackStopped);
742
743 m_guiActions->OnPlaybackStopped(item);
744 m_epgContainer.OnPlaybackStopped();
745 }
746
OnPlaybackEnded(const CFileItemPtr & item)747 void CPVRManager::OnPlaybackEnded(const CFileItemPtr& item)
748 {
749 // Playback ended, but not due to user interaction
750 OnPlaybackStopped(item);
751 }
752
LocalizationChanged()753 void CPVRManager::LocalizationChanged()
754 {
755 CSingleLock lock(m_critSection);
756 if (IsStarted())
757 {
758 static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllRadio().get())->CheckGroupName();
759 static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllTV().get())->CheckGroupName();
760 }
761 }
762
EpgsCreated() const763 bool CPVRManager::EpgsCreated() const
764 {
765 CSingleLock lock(m_critSection);
766 return m_bEpgsCreated;
767 }
768
TriggerEpgsCreate()769 void CPVRManager::TriggerEpgsCreate()
770 {
771 m_pendingUpdates->Append("pvr-create-epgs", [this]() {
772 return CreateChannelEpgs();
773 });
774 }
775
TriggerRecordingsUpdate()776 void CPVRManager::TriggerRecordingsUpdate()
777 {
778 m_pendingUpdates->Append("pvr-update-recordings", [this]() {
779 return Recordings()->Update();
780 });
781 }
782
TriggerRecordingsSizeInProgressUpdate()783 void CPVRManager::TriggerRecordingsSizeInProgressUpdate()
784 {
785 m_pendingUpdates->Append("pvr-update-recordings-size", [this]() {
786 return Recordings()->UpdateInProgressSize();
787 });
788 }
789
TriggerTimersUpdate()790 void CPVRManager::TriggerTimersUpdate()
791 {
792 m_pendingUpdates->Append("pvr-update-timers", [this]() {
793 return Timers()->Update();
794 });
795 }
796
TriggerChannelsUpdate()797 void CPVRManager::TriggerChannelsUpdate()
798 {
799 m_pendingUpdates->Append("pvr-update-channels", [this]() {
800 return ChannelGroups()->Update(true);
801 });
802 }
803
TriggerChannelGroupsUpdate()804 void CPVRManager::TriggerChannelGroupsUpdate()
805 {
806 m_pendingUpdates->Append("pvr-update-channelgroups", [this]() {
807 return ChannelGroups()->Update(false);
808 });
809 }
810
TriggerSearchMissingChannelIcons()811 void CPVRManager::TriggerSearchMissingChannelIcons()
812 {
813 m_pendingUpdates->Append("pvr-search-missing-channel-icons", [this]() {
814 CPVRGUIChannelIconUpdater updater(
815 {ChannelGroups()->GetGroupAllTV(), ChannelGroups()->GetGroupAllRadio()}, true);
816 updater.SearchAndUpdateMissingChannelIcons();
817 return true;
818 });
819 }
820
TriggerSearchMissingChannelIcons(const std::shared_ptr<CPVRChannelGroup> & group)821 void CPVRManager::TriggerSearchMissingChannelIcons(const std::shared_ptr<CPVRChannelGroup>& group)
822 {
823 m_pendingUpdates->Append("pvr-search-missing-channel-icons-" + std::to_string(group->GroupID()),
824 [group]() {
825 CPVRGUIChannelIconUpdater updater({group}, false);
826 updater.SearchAndUpdateMissingChannelIcons();
827 return true;
828 });
829 }
830
ConnectionStateChange(CPVRClient * client,const std::string & connectString,PVR_CONNECTION_STATE state,const std::string & message)831 void CPVRManager::ConnectionStateChange(CPVRClient* client,
832 const std::string& connectString,
833 PVR_CONNECTION_STATE state,
834 const std::string& message)
835 {
836 CJobManager::GetInstance().Submit([this, client, connectString, state, message] {
837 Clients()->ConnectionStateChange(client, connectString, state, message);
838
839 if (state == PVR_CONNECTION_STATE_CONNECTED)
840 Start(); // start over
841
842 return true;
843 });
844 }
845
CreateChannelEpgs()846 bool CPVRManager::CreateChannelEpgs()
847 {
848 if (EpgsCreated())
849 return true;
850
851 bool bEpgsCreated = m_channelGroups->CreateChannelEpgs();
852
853 CSingleLock lock(m_critSection);
854 m_bEpgsCreated = bEpgsCreated;
855 return m_bEpgsCreated;
856 }
857