Remove LiveTV menu.
[vuplus_xbmc] / xbmc / pvr / PVRManager.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "Application.h"
22 #include "ApplicationMessenger.h"
23 #include "GUIInfoManager.h"
24 #include "dialogs/GUIDialogOK.h"
25 #include "dialogs/GUIDialogNumeric.h"
26 #include "dialogs/GUIDialogProgress.h"
27 #include "dialogs/GUIDialogExtendedProgressBar.h"
28 #include "dialogs/GUIDialogKaiToast.h"
29 #include "dialogs/GUIDialogYesNo.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "guilib/LocalizeStrings.h"
32 #include "music/tags/MusicInfoTag.h"
33 #include "settings/AdvancedSettings.h"
34 #include "settings/MediaSettings.h"
35 #include "settings/lib/Setting.h"
36 #include "settings/Settings.h"
37 #include "threads/SingleLock.h"
38 #include "windows/GUIWindowPVR.h"
39 #include "utils/log.h"
40 #include "utils/Stopwatch.h"
41 #include "utils/StringUtils.h"
42 #include "threads/Atomics.h"
43 #include "windows/GUIWindowPVRCommon.h"
44 #include "utils/JobManager.h"
45 #include "interfaces/AnnouncementManager.h"
46
47 #include "PVRManager.h"
48 #include "PVRDatabase.h"
49 #include "PVRGUIInfo.h"
50 #include "addons/PVRClients.h"
51 #include "channels/PVRChannel.h"
52 #include "channels/PVRChannelGroupsContainer.h"
53 #include "channels/PVRChannelGroupInternal.h"
54 #include "epg/EpgContainer.h"
55 #include "recordings/PVRRecordings.h"
56 #include "timers/PVRTimers.h"
57 #include "interfaces/AnnouncementManager.h"
58 #include "addons/AddonInstaller.h"
59 #include "guilib/Key.h"
60 #include "dialogs/GUIDialogPVRChannelManager.h"
61
62 using namespace std;
63 using namespace MUSIC_INFO;
64 using namespace PVR;
65 using namespace EPG;
66 using namespace ANNOUNCEMENT;
67
68 CPVRManager::CPVRManager(void) :
69     CThread("PVRManager"),
70     m_channelGroups(NULL),
71     m_recordings(NULL),
72     m_timers(NULL),
73     m_addons(NULL),
74     m_guiInfo(NULL),
75     m_triggerEvent(true),
76     m_currentFile(NULL),
77     m_database(NULL),
78     m_bFirstStart(true),
79     m_bEpgsCreated(false),
80     m_progressHandle(NULL),
81     m_managerState(ManagerStateStopped),
82     m_bOpenPVRWindow(false)
83 {
84   CAnnouncementManager::AddAnnouncer(this);
85   ResetProperties();
86 }
87
88 CPVRManager::~CPVRManager(void)
89 {
90   CAnnouncementManager::RemoveAnnouncer(this);
91   Stop();
92   CLog::Log(LOGDEBUG,"PVRManager - destroyed");
93 }
94
95 void CPVRManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
96 {
97   if (!IsStarted() || (flag & (System)) == 0)
98    return;
99
100   if (strcmp(message, "OnWake") == 0)
101     ContinueLastChannel();
102 }
103
104 CPVRManager &CPVRManager::Get(void)
105 {
106   static CPVRManager pvrManagerInstance;
107   return pvrManagerInstance;
108 }
109
110 void CPVRManager::OnSettingChanged(const CSetting *setting)
111 {
112   if (setting == NULL)
113     return;
114
115   const std::string &settingId = setting->GetId();
116   if (settingId == "pvrmanager.enabled")
117   {
118     if (((CSettingBool*)setting)->GetValue())
119       CApplicationMessenger::Get().ExecBuiltIn("XBMC.StartPVRManager", false);
120     else
121       CApplicationMessenger::Get().ExecBuiltIn("XBMC.StopPVRManager", false);
122   }
123   else if (settingId == "pvrparental.enabled")
124   {
125     if (((CSettingBool*)setting)->GetValue() && CSettings::Get().GetString("pvrparental.pin").empty())
126     {
127       CStdString newPassword = "";
128       // password set... save it
129       if (CGUIDialogNumeric::ShowAndVerifyNewPassword(newPassword))
130         CSettings::Get().SetString("pvrparental.pin", newPassword);
131       // password not set... disable parental
132       else
133         ((CSettingBool*)setting)->SetValue(false);
134     }
135   }
136 }
137
138 void CPVRManager::OnSettingAction(const CSetting *setting)
139 {
140   if (setting == NULL)
141     return;
142
143   const std::string &settingId = setting->GetId();
144   if (settingId == "pvrmenu.searchicons")
145   {
146     if (IsStarted())
147       SearchMissingChannelIcons();
148   }
149   else if (settingId == "pvrmanager.resetdb")
150   {
151     if (CheckParentalPIN(g_localizeStrings.Get(19262).c_str()) &&
152         CGUIDialogYesNo::ShowAndGetInput(19098, 19186, 750, 0))
153     {
154       CDateTime::ResetTimezoneBias();
155       ResetDatabase(false);
156     }
157   }
158   else if (settingId == "epg.resetepg")
159   {
160     if (CGUIDialogYesNo::ShowAndGetInput(19098, 19188, 750, 0))
161     {
162       CDateTime::ResetTimezoneBias();
163       ResetDatabase(true);
164     }
165   }
166   else if (settingId == "pvrmanager.channelscan")
167   {
168     if (IsStarted())
169       StartChannelScan();
170   }
171   else if (settingId == "pvrmanager.channelmanager")
172   {
173     if (IsStarted())
174     {
175       CGUIDialogPVRChannelManager *dialog = (CGUIDialogPVRChannelManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
176       if (dialog)
177         dialog->DoModal();
178     }
179   }
180   else if (settingId == "pvrclient.menuhook")
181   {
182     if (IsStarted())
183       Clients()->ProcessMenuHooks(-1, PVR_MENUHOOK_SETTING, NULL);
184   }
185 }
186
187 bool CPVRManager::IsPVRWindowActive(void) const
188 {
189   return g_windowManager.IsWindowActive(WINDOW_PVR) ||
190       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_CHANNEL_MANAGER) ||
191       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_OSD_CHANNELS) ||
192       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_GROUP_MANAGER) ||
193       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_GUIDE_INFO) ||
194       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_OSD_CUTTER) ||
195       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_OSD_DIRECTOR) ||
196       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_OSD_GUIDE) ||
197       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_GUIDE_SEARCH) ||
198       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_RECORDING_INFO) ||
199       g_windowManager.IsWindowActive(WINDOW_DIALOG_PVR_TIMER_SETTING);
200 }
201
202 bool CPVRManager::InstallAddonAllowed(const std::string& strAddonId) const
203 {
204   return !IsStarted() ||
205       !m_addons->IsInUse(strAddonId) ||
206       (!IsPVRWindowActive() && !IsPlaying());
207 }
208
209 void CPVRManager::MarkAsOutdated(const std::string& strAddonId, const std::string& strReferer)
210 {
211   if (IsStarted() && CSettings::Get().GetBool("general.addonautoupdate"))
212   {
213     CSingleLock lock(m_critSection);
214     m_outdatedAddons.insert(make_pair(strAddonId, strReferer));
215   }
216 }
217
218 bool CPVRManager::UpgradeOutdatedAddons(void)
219 {
220   CSingleLock lock(m_critSection);
221   if (m_outdatedAddons.empty())
222     return true;
223
224   // there's add-ons that couldn't be updated
225   for (map<string, string>::iterator it = m_outdatedAddons.begin(); it != m_outdatedAddons.end(); it++)
226   {
227     if (!InstallAddonAllowed(it->first))
228     {
229       // we can't upgrade right now
230       return true;
231     }
232   }
233
234   // all outdated add-ons can be upgraded now
235   CLog::Log(LOGINFO, "PVR - upgrading outdated add-ons");
236
237   map<string, string> outdatedAddons = m_outdatedAddons;
238   // stop threads and unload
239   SetState(ManagerStateInterrupted);
240   g_EpgContainer.Stop();
241   m_guiInfo->Stop();
242   m_addons->Stop();
243   Cleanup();
244
245   // upgrade all add-ons
246   for (map<string, string>::iterator it = outdatedAddons.begin(); it != outdatedAddons.end(); it++)
247   {
248     CLog::Log(LOGINFO, "PVR - updating add-on '%s'", it->first.c_str());
249     CAddonInstaller::Get().Install(it->first, true, it->second, false);
250   }
251
252   // reload
253   CLog::Log(LOGINFO, "PVRManager - %s - restarting the PVR manager", __FUNCTION__);
254   SetState(ManagerStateStarting);
255   ResetProperties();
256
257   while (!Load() && IsInitialising())
258   {
259     CLog::Log(LOGERROR, "PVRManager - %s - failed to load PVR data, retrying", __FUNCTION__);
260     if (m_guiInfo) m_guiInfo->Stop();
261     if (m_addons) m_addons->Stop();
262     Cleanup();
263     Sleep(1000);
264   }
265
266   if (IsInitialising())
267   {
268     SetState(ManagerStateStarted);
269     g_EpgContainer.Start();
270
271     CLog::Log(LOGDEBUG, "PVRManager - %s - restarted", __FUNCTION__);
272     return true;
273   }
274
275   return false;
276 }
277
278 void CPVRManager::Cleanup(void)
279 {
280   CSingleLock lock(m_critSection);
281
282   SAFE_DELETE(m_addons);
283   SAFE_DELETE(m_guiInfo);
284   SAFE_DELETE(m_timers);
285   SAFE_DELETE(m_recordings);
286   SAFE_DELETE(m_channelGroups);
287   SAFE_DELETE(m_parentalTimer);
288   SAFE_DELETE(m_database);
289   m_triggerEvent.Set();
290
291   m_currentFile           = NULL;
292   m_bIsSwitchingChannels  = false;
293   m_outdatedAddons.clear();
294   m_bOpenPVRWindow = false;
295   m_bEpgsCreated = false;
296
297   for (unsigned int iJobPtr = 0; iJobPtr < m_pendingUpdates.size(); iJobPtr++)
298     delete m_pendingUpdates.at(iJobPtr);
299   m_pendingUpdates.clear();
300
301   HideProgressDialog();
302
303   SetState(ManagerStateStopped);
304 }
305
306 void CPVRManager::ResetProperties(void)
307 {
308   CSingleLock lock(m_critSection);
309   Cleanup();
310
311   if (!g_application.m_bStop)
312   {
313     m_addons        = new CPVRClients;
314     m_channelGroups = new CPVRChannelGroupsContainer;
315     m_recordings    = new CPVRRecordings;
316     m_timers        = new CPVRTimers;
317     m_guiInfo       = new CPVRGUIInfo;
318     m_parentalTimer = new CStopWatch;
319   }
320 }
321
322 class CPVRManagerStartJob : public CJob
323 {
324 public:
325   CPVRManagerStartJob(bool bOpenPVRWindow = false) :
326     m_bOpenPVRWindow(bOpenPVRWindow) {}
327   ~CPVRManagerStartJob(void) {}
328
329   bool DoWork(void)
330   {
331     g_PVRManager.Start(false, m_bOpenPVRWindow);
332     return true;
333   }
334 private:
335   bool m_bOpenPVRWindow;
336 };
337
338 void CPVRManager::Start(bool bAsync /* = false */, bool bOpenPVRWindow /* = false */)
339 {
340   if (bAsync)
341   {
342     CPVRManagerStartJob *job = new CPVRManagerStartJob(bOpenPVRWindow);
343     CJobManager::GetInstance().AddJob(job, NULL);
344     return;
345   }
346
347   CSingleLock lock(m_critSection);
348
349   /* first stop and remove any clients */
350   Stop();
351
352   /* don't start if Settings->Video->TV->Enable isn't checked */
353   if (!CSettings::Get().GetBool("pvrmanager.enabled"))
354     return;
355
356   ResetProperties();
357   SetState(ManagerStateStarting);
358   m_bOpenPVRWindow = bOpenPVRWindow;
359
360   /* create and open database */
361   if (!m_database)
362     m_database = new CPVRDatabase;
363   m_database->Open();
364
365   /* create the supervisor thread to do all background activities */
366   StartUpdateThreads();
367 }
368
369 void CPVRManager::Stop(void)
370 {
371   /* check whether the pvrmanager is loaded */
372   if (IsStopping() || IsStopped())
373     return;
374
375   SetState(ManagerStateStopping);
376
377   /* stop the EPG updater, since it might be using the pvr add-ons */
378   g_EpgContainer.Stop();
379
380   CLog::Log(LOGNOTICE, "PVRManager - stopping");
381
382   /* stop playback if needed */
383   if (IsPlaying())
384   {
385     CLog::Log(LOGNOTICE,"PVRManager - %s - stopping PVR playback", __FUNCTION__);
386     CApplicationMessenger::Get().MediaStop();
387   }
388
389   /* stop all update threads */
390   StopUpdateThreads();
391
392   /* executes the set wakeup command */
393   SetWakeupCommand();
394
395   /* close database */
396   if (m_database->IsOpen())
397     m_database->Close();
398
399   /* unload all data */
400   Cleanup();
401 }
402
403 ManagerState CPVRManager::GetState(void) const
404 {
405   CSingleLock lock(m_managerStateMutex);
406   return m_managerState;
407 }
408
409 void CPVRManager::SetState(ManagerState state) 
410 {
411   {
412     CSingleLock lock(m_managerStateMutex);
413     m_managerState = state;
414     SetChanged();
415   }
416
417   NotifyObservers(ObservableMessageManagerStateChanged);
418 }
419
420 void CPVRManager::Process(void)
421 {
422   g_EpgContainer.Stop();
423
424   /* load the pvr data from the db and clients if it's not already loaded */
425   while (!Load() && IsInitialising())
426   {
427     CLog::Log(LOGERROR, "PVRManager - %s - failed to load PVR data, retrying", __FUNCTION__);
428     if (m_guiInfo) m_guiInfo->Stop();
429     if (m_addons) m_addons->Stop();
430     Cleanup();
431     Sleep(1000);
432   }
433
434   if (IsInitialising())
435     SetState(ManagerStateStarted);
436   else
437     return;
438
439   /* main loop */
440   CLog::Log(LOGDEBUG, "PVRManager - %s - entering main loop", __FUNCTION__);
441   g_EpgContainer.Start();
442
443   if (m_bOpenPVRWindow)
444   {
445     m_bOpenPVRWindow = false;
446     CApplicationMessenger::Get().ExecBuiltIn("XBMC.ActivateWindowAndFocus(MyPVR, 32,0, 11,0)");
447   }
448
449   bool bRestart(false);
450   while (IsStarted() && m_addons && m_addons->HasConnectedClients() && !bRestart)
451   {
452     /* continue last watched channel after first startup */
453     if (m_bFirstStart)
454     {
455       {
456         CSingleLock lock(m_critSection);
457         m_bFirstStart = false;
458       }
459       ContinueLastChannel();
460     }
461     /* execute the next pending jobs if there are any */
462     try
463     {
464       ExecutePendingJobs();
465     }
466     catch (...)
467     {
468       CLog::Log(LOGERROR, "PVRManager - %s - an error occured while trying to execute the last update job, trying to recover", __FUNCTION__);
469       bRestart = true;
470     }
471
472     if (!UpgradeOutdatedAddons())
473     {
474       // failed to load after upgrading
475       CLog::Log(LOGERROR, "PVRManager - %s - could not load pvr data after upgrading. stopping the pvrmanager", __FUNCTION__);
476     }
477     else if (IsStarted() && !bRestart)
478       m_triggerEvent.WaitMSec(1000);
479   }
480
481   if (IsStarted())
482   {
483     CLog::Log(LOGNOTICE, "PVRManager - %s - no add-ons enabled anymore. restarting the pvrmanager", __FUNCTION__);
484     CApplicationMessenger::Get().ExecBuiltIn("StartPVRManager", false);
485   }
486   else
487   {
488     if (g_windowManager.GetActiveWindow() == WINDOW_PVR)
489       g_windowManager.ActivateWindow(WINDOW_HOME);
490   }
491 }
492
493 bool CPVRManager::SetWakeupCommand(void)
494 {
495   if (!CSettings::Get().GetBool("pvrpowermanagement.enabled"))
496     return false;
497
498   const CStdString strWakeupCommand = CSettings::Get().GetString("pvrpowermanagement.setwakeupcmd");
499   if (!strWakeupCommand.empty() && m_timers)
500   {
501     time_t iWakeupTime;
502     const CDateTime nextEvent = m_timers->GetNextEventTime();
503     if (nextEvent.IsValid())
504     {
505       nextEvent.GetAsTime(iWakeupTime);
506         
507       CStdString strExecCommand = StringUtils::Format("%s %d", strWakeupCommand.c_str(), iWakeupTime);
508         
509       const int iReturn = system(strExecCommand.c_str());
510       if (iReturn != 0)
511         CLog::Log(LOGERROR, "%s - failed to execute wakeup command '%s': %s (%d)", __FUNCTION__, strExecCommand.c_str(), strerror(iReturn), iReturn);
512         
513       return iReturn == 0;
514     }
515   }
516
517   return false;
518 }
519
520 bool CPVRManager::StartUpdateThreads(void)
521 {
522   StopUpdateThreads();
523   CLog::Log(LOGNOTICE, "PVRManager - starting up");
524
525   /* create the pvrmanager thread, which will ensure that all data will be loaded */
526   SetState(ManagerStateStarting);
527   Create();
528   SetPriority(-1);
529
530   return true;
531 }
532
533 void CPVRManager::StopUpdateThreads(void)
534 {
535   SetState(ManagerStateInterrupted);
536
537   StopThread();
538   if (m_guiInfo)
539     m_guiInfo->Stop();
540   if (m_addons)
541     m_addons->Stop();
542 }
543
544 bool CPVRManager::Load(void)
545 {
546   /* start the add-on update thread */
547   if (m_addons)
548     m_addons->Start();
549
550   /* load at least one client */
551   while (IsInitialising() && m_addons && !m_addons->HasConnectedClients())
552     Sleep(50);
553
554   if (!IsInitialising() || !m_addons || !m_addons->HasConnectedClients())
555     return false;
556
557   CLog::Log(LOGDEBUG, "PVRManager - %s - active clients found. continue to start", __FUNCTION__);
558
559   CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
560   if (pWindow)
561     pWindow->Reset();
562
563   /* load all channels and groups */
564   ShowProgressDialog(g_localizeStrings.Get(19236), 0); // Loading channels from clients
565   if (!m_channelGroups->Load() || !IsInitialising())
566     return false;
567
568   /* get timers from the backends */
569   ShowProgressDialog(g_localizeStrings.Get(19237), 50); // Loading timers from clients
570   m_timers->Load();
571
572   /* get recordings from the backend */
573   ShowProgressDialog(g_localizeStrings.Get(19238), 75); // Loading recordings from clients
574   m_recordings->Load();
575
576   if (!IsInitialising())
577     return false;
578
579   /* start the other pvr related update threads */
580   ShowProgressDialog(g_localizeStrings.Get(19239), 85); // Starting background threads
581   m_guiInfo->Start();
582
583   /* close the progess dialog */
584   HideProgressDialog();
585
586   return true;
587 }
588
589 void CPVRManager::ShowProgressDialog(const CStdString &strText, int iProgress)
590 {
591   if (!m_progressHandle)
592   {
593     CGUIDialogExtendedProgressBar *loadingProgressDialog = (CGUIDialogExtendedProgressBar *)g_windowManager.GetWindow(WINDOW_DIALOG_EXT_PROGRESS);
594     m_progressHandle = loadingProgressDialog->GetHandle(g_localizeStrings.Get(19235)); // PVR manager is starting up
595   }
596
597   m_progressHandle->SetPercentage((float)iProgress);
598   m_progressHandle->SetText(strText);
599 }
600
601 void CPVRManager::HideProgressDialog(void)
602 {
603   if (m_progressHandle)
604   {
605     m_progressHandle->MarkFinished();
606     m_progressHandle = NULL;
607   }
608 }
609
610 bool CPVRManager::ChannelSwitch(unsigned int iChannelNumber)
611 {
612   CSingleLock lock(m_critSection);
613
614   CPVRChannelGroupPtr playingGroup = GetPlayingGroup(m_addons->IsPlayingRadio());
615   if (!playingGroup)
616   {
617     CLog::Log(LOGERROR, "PVRManager - %s - cannot get the selected group", __FUNCTION__);
618     return false;
619   }
620
621   CFileItemPtr channel = playingGroup->GetByChannelNumber(iChannelNumber);
622   if (!channel || !channel->HasPVRChannelInfoTag())
623   {
624     CLog::Log(LOGERROR, "PVRManager - %s - cannot find channel %d", __FUNCTION__, iChannelNumber);
625     return false;
626   }
627
628   return PerformChannelSwitch(*channel->GetPVRChannelInfoTag(), false);
629 }
630
631 bool CPVRManager::ChannelUpDown(unsigned int *iNewChannelNumber, bool bPreview, bool bUp)
632 {
633   bool bReturn = false;
634   if (IsPlayingTV() || IsPlayingRadio())
635   {
636     CFileItem currentFile(g_application.CurrentFileItem());
637     CPVRChannel *currentChannel = currentFile.GetPVRChannelInfoTag();
638     CPVRChannelGroupPtr group = GetPlayingGroup(currentChannel->IsRadio());
639     if (group)
640     {
641       CFileItemPtr newChannel = bUp ?
642           group->GetByChannelUp(*currentChannel) :
643           group->GetByChannelDown(*currentChannel);
644
645       if (newChannel && newChannel->HasPVRChannelInfoTag() &&
646           PerformChannelSwitch(*newChannel->GetPVRChannelInfoTag(), bPreview))
647       {
648         *iNewChannelNumber = newChannel->GetPVRChannelInfoTag()->ChannelNumber();
649         bReturn = true;
650       }
651     }
652   }
653
654   return bReturn;
655 }
656
657 bool CPVRManager::ContinueLastChannel(void)
658 {
659   if (CSettings::Get().GetInt("pvrplayback.startlast") == START_LAST_CHANNEL_OFF)
660     return false;
661
662   CFileItemPtr channel = m_channelGroups->GetLastPlayedChannel();
663   if (channel && channel->HasPVRChannelInfoTag())
664   {
665     CLog::Log(LOGNOTICE, "PVRManager - %s - continue playback on channel '%s'", __FUNCTION__, channel->GetPVRChannelInfoTag()->ChannelName().c_str());
666     return StartPlayback(channel->GetPVRChannelInfoTag(), (CSettings::Get().GetInt("pvrplayback.startlast") == START_LAST_CHANNEL_MIN));
667   }
668
669   return false;
670 }
671
672 void CPVRManager::ResetDatabase(bool bResetEPGOnly /* = false */)
673 {
674   CLog::Log(LOGNOTICE,"PVRManager - %s - clearing the PVR database", __FUNCTION__);
675
676   g_EpgContainer.Stop();
677
678   CGUIDialogProgress* pDlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
679   pDlgProgress->SetLine(0, StringUtils::EmptyString);
680   pDlgProgress->SetLine(1, g_localizeStrings.Get(19186)); // All data in the PVR database is being erased
681   pDlgProgress->SetLine(2, StringUtils::EmptyString);
682   pDlgProgress->StartModal();
683   pDlgProgress->Progress();
684
685   if (m_addons && m_addons->IsPlaying())
686   {
687     CLog::Log(LOGNOTICE,"PVRManager - %s - stopping playback", __FUNCTION__);
688     CApplicationMessenger::Get().MediaStop();
689   }
690
691   pDlgProgress->SetPercentage(10);
692   pDlgProgress->Progress();
693
694   /* reset the EPG pointers */
695   if (m_database)
696     m_database->ResetEPG();
697
698   /* stop the thread */
699   Stop();
700
701   pDlgProgress->SetPercentage(20);
702   pDlgProgress->Progress();
703
704   if (!m_database)
705     m_database = new CPVRDatabase;
706
707   if (m_database && m_database->Open())
708   {
709     /* clean the EPG database */
710     g_EpgContainer.Reset();
711     pDlgProgress->SetPercentage(30);
712     pDlgProgress->Progress();
713
714     if (!bResetEPGOnly)
715     {
716       m_database->DeleteChannelGroups();
717       pDlgProgress->SetPercentage(50);
718       pDlgProgress->Progress();
719
720       /* delete all channels */
721       m_database->DeleteChannels();
722       pDlgProgress->SetPercentage(70);
723       pDlgProgress->Progress();
724
725       /* delete all channel settings */
726       m_database->DeleteChannelSettings();
727       pDlgProgress->SetPercentage(80);
728       pDlgProgress->Progress();
729
730       /* delete all client information */
731       m_database->DeleteClients();
732       pDlgProgress->SetPercentage(90);
733       pDlgProgress->Progress();
734     }
735
736     m_database->Close();
737   }
738
739   CLog::Log(LOGNOTICE,"PVRManager - %s - %s database cleared", __FUNCTION__, bResetEPGOnly ? "EPG" : "PVR and EPG");
740
741   if (CSettings::Get().GetBool("pvrmanager.enabled"))
742   {
743     CLog::Log(LOGNOTICE,"PVRManager - %s - restarting the PVRManager", __FUNCTION__);
744     m_database->Open();
745     Cleanup();
746     Start();
747   }
748
749   pDlgProgress->SetPercentage(100);
750   pDlgProgress->Close();
751 }
752
753 bool CPVRManager::IsPlaying(void) const
754 {
755   return IsStarted() && m_addons && m_addons->IsPlaying();
756 }
757
758 bool CPVRManager::GetCurrentChannel(CPVRChannelPtr &channel) const
759 {
760   return m_addons && m_addons->GetPlayingChannel(channel);
761 }
762
763 int CPVRManager::GetCurrentEpg(CFileItemList &results) const
764 {
765   int iReturn = -1;
766
767   CPVRChannelPtr channel;
768   if (m_addons->GetPlayingChannel(channel))
769     iReturn = channel->GetEPG(results);
770   else
771     CLog::Log(LOGDEBUG,"PVRManager - %s - no current channel set", __FUNCTION__);
772
773   return iReturn;
774 }
775
776 void CPVRManager::ResetPlayingTag(void)
777 {
778   CSingleLock lock(m_critSection);
779   if (IsStarted() && m_guiInfo)
780     m_guiInfo->ResetPlayingTag();
781 }
782
783 int CPVRManager::GetPreviousChannel(void)
784 {
785   CPVRChannelPtr currentChannel;
786   if (GetCurrentChannel(currentChannel))
787   {
788     CPVRChannelGroupPtr selectedGroup = GetPlayingGroup(currentChannel->IsRadio());
789     CFileItemPtr channel = selectedGroup->GetLastPlayedChannel(currentChannel->ChannelID());
790     if (channel && channel->HasPVRChannelInfoTag())
791       return channel->GetPVRChannelInfoTag()->ChannelNumber();
792   }
793   return -1;
794 }
795
796 bool CPVRManager::ToggleRecordingOnChannel(unsigned int iChannelId)
797 {
798   bool bReturn = false;
799
800   CPVRChannelPtr channel = m_channelGroups->GetChannelById(iChannelId);
801   if (!channel)
802     return bReturn;
803
804   if (m_addons->HasTimerSupport(channel->ClientID()))
805   {
806     /* timers are supported on this channel */
807     if (!channel->IsRecording())
808     {
809       bReturn = m_timers->InstantTimer(*channel);
810       if (!bReturn)
811         CGUIDialogOK::ShowAndGetInput(19033,0,19164,0);
812     }
813     else
814     {
815       /* delete active timers */
816       bReturn = m_timers->DeleteTimersOnChannel(*channel, false, true);
817     }
818   }
819
820   return bReturn;
821 }
822
823 bool CPVRManager::StartRecordingOnPlayingChannel(bool bOnOff)
824 {
825   bool bReturn = false;
826
827   CPVRChannelPtr channel;
828   if (!m_addons->GetPlayingChannel(channel))
829     return bReturn;
830
831   if (m_addons->HasTimerSupport(channel->ClientID()))
832   {
833     /* timers are supported on this channel */
834     if (bOnOff && !channel->IsRecording())
835     {
836       bReturn = m_timers->InstantTimer(*channel);
837       if (!bReturn)
838         CGUIDialogOK::ShowAndGetInput(19033,0,19164,0);
839     }
840     else if (!bOnOff && channel->IsRecording())
841     {
842       /* delete active timers */
843       bReturn = m_timers->DeleteTimersOnChannel(*channel, true, true);
844     }
845   }
846
847   return bReturn;
848 }
849
850 bool CPVRManager::CheckParentalLock(const CPVRChannel &channel)
851 {
852   bool bReturn = !IsParentalLocked(channel) ||
853       CheckParentalPIN();
854
855   if (!bReturn)
856     CLog::Log(LOGERROR, "PVRManager - %s - parental lock verification failed for channel '%s': wrong PIN entered.", __FUNCTION__, channel.ChannelName().c_str());
857
858   return bReturn;
859 }
860
861 bool CPVRManager::IsParentalLocked(const CPVRChannel &channel)
862 {
863   bool bReturn(false);
864   CSingleLock lock(m_managerStateMutex);
865   if (!IsStarted())
866     return bReturn;
867   CPVRChannelPtr currentChannel(new CPVRChannel(false));
868
869   if (// different channel
870       (!GetCurrentChannel(currentChannel) || channel != *currentChannel) &&
871       // parental control enabled
872       CSettings::Get().GetBool("pvrparental.enabled") &&
873       // channel is locked
874       channel.IsLocked())
875   {
876     float parentalDurationMs = CSettings::Get().GetInt("pvrparental.duration") * 1000.0f;
877     bReturn = m_parentalTimer &&
878         (!m_parentalTimer->IsRunning() ||
879           m_parentalTimer->GetElapsedMilliseconds() > parentalDurationMs);
880   }
881
882   return bReturn;
883 }
884
885 bool CPVRManager::CheckParentalPIN(const char *strTitle /* = NULL */)
886 {
887   CStdString pinCode = CSettings::Get().GetString("pvrparental.pin");
888
889   if (!CSettings::Get().GetBool("pvrparental.enabled") || pinCode.empty())
890     return true;
891
892   // Locked channel. Enter PIN:
893   bool bValidPIN = CGUIDialogNumeric::ShowAndVerifyInput(pinCode, strTitle ? strTitle : g_localizeStrings.Get(19263).c_str(), true);
894   if (!bValidPIN)
895     // display message: The entered PIN number was incorrect
896     CGUIDialogOK::ShowAndGetInput(19264,0,19265,0);
897   else if (m_parentalTimer)
898   {
899     // reset the timer
900     m_parentalTimer->StartZero();
901   }
902
903   return bValidPIN;
904 }
905
906 void CPVRManager::SaveCurrentChannelSettings(void)
907 {
908   m_addons->SaveCurrentChannelSettings();
909 }
910
911 void CPVRManager::LoadCurrentChannelSettings()
912 {
913   m_addons->LoadCurrentChannelSettings();
914 }
915
916 void CPVRManager::SetPlayingGroup(CPVRChannelGroupPtr group)
917 {
918   if (m_channelGroups && group)
919     m_channelGroups->Get(group->IsRadio())->SetSelectedGroup(group);
920 }
921
922 CPVRChannelGroupPtr CPVRManager::GetPlayingGroup(bool bRadio /* = false */)
923 {
924   if (m_channelGroups)
925     return m_channelGroups->GetSelectedGroup(bRadio);
926
927   return CPVRChannelGroupPtr();
928 }
929
930 bool CPVREpgsCreateJob::DoWork(void)
931 {
932   return g_PVRManager.CreateChannelEpgs();
933 }
934
935 bool CPVRRecordingsUpdateJob::DoWork(void)
936 {
937   g_PVRRecordings->Update();
938   return true;
939 }
940
941 bool CPVRTimersUpdateJob::DoWork(void)
942 {
943   return g_PVRTimers->Update();
944 }
945
946 bool CPVRChannelsUpdateJob::DoWork(void)
947 {
948   return g_PVRChannelGroups->Update(true);
949 }
950
951 bool CPVRChannelGroupsUpdateJob::DoWork(void)
952 {
953   return g_PVRChannelGroups->Update(false);
954 }
955
956 bool CPVRChannelSettingsSaveJob::DoWork(void)
957 {
958   g_PVRManager.SaveCurrentChannelSettings();
959   return true;
960 }
961
962 bool CPVRManager::OpenLiveStream(const CFileItem &channel)
963 {
964   bool bReturn(false);
965   if (!channel.HasPVRChannelInfoTag())
966     return bReturn;
967
968   CLog::Log(LOGDEBUG,"PVRManager - %s - opening live stream on channel '%s'",
969       __FUNCTION__, channel.GetPVRChannelInfoTag()->ChannelName().c_str());
970
971   // check if we're allowed to play this file
972   if (IsParentalLocked(*channel.GetPVRChannelInfoTag()))
973     return bReturn;
974
975   CPVRChannelPtr playingChannel;
976   bool bPersistChannel(false);
977   if ((bReturn = m_addons->OpenStream(*channel.GetPVRChannelInfoTag(), false)) != false)
978   {
979     CSingleLock lock(m_critSection);
980     if(m_currentFile)
981       delete m_currentFile;
982     m_currentFile = new CFileItem(channel);
983
984     if (m_addons->GetPlayingChannel(playingChannel))
985     {
986       /* store current time in iLastWatched */
987       time_t tNow;
988       CDateTime::GetCurrentDateTime().GetAsTime(tNow);
989       playingChannel->SetLastWatched(tNow);
990       bPersistChannel = true;
991
992       m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(playingChannel->IsRadio()));
993     }
994   }
995
996   if (bPersistChannel)
997     playingChannel->Persist();
998
999   return bReturn;
1000 }
1001
1002 bool CPVRManager::OpenRecordedStream(const CPVRRecording &tag)
1003 {
1004   bool bReturn = false;
1005   CSingleLock lock(m_critSection);
1006
1007   if ((bReturn = m_addons->OpenStream(tag)) != false)
1008   {
1009     delete m_currentFile;
1010     m_currentFile = new CFileItem(tag);
1011   }
1012
1013   return bReturn;
1014 }
1015
1016 void CPVRManager::CloseStream(void)
1017 {
1018   CPVRChannelPtr channel;
1019   bool bPersistChannel(false);
1020
1021   {
1022     CSingleLock lock(m_critSection);
1023
1024     if (m_addons->GetPlayingChannel(channel))
1025     {
1026       /* store current time in iLastWatched */
1027       time_t tNow;
1028       CDateTime::GetCurrentDateTime().GetAsTime(tNow);
1029       channel->SetLastWatched(tNow);
1030       bPersistChannel = true;
1031
1032       m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(channel->IsRadio()));
1033     }
1034
1035     m_addons->CloseStream();
1036     SAFE_DELETE(m_currentFile);
1037   }
1038
1039   if (bPersistChannel)
1040     channel->Persist();
1041 }
1042
1043 void CPVRManager::UpdateCurrentFile(void)
1044 {
1045   CSingleLock lock(m_critSection);
1046   if (m_currentFile)
1047     UpdateItem(*m_currentFile);
1048 }
1049
1050 bool CPVRManager::UpdateItem(CFileItem& item)
1051 {
1052   /* Don't update if a recording is played */
1053   if (item.IsPVRRecording())
1054     return false;
1055
1056   if (!item.IsPVRChannel())
1057   {
1058     CLog::Log(LOGERROR, "CPVRManager - %s - no channel tag provided", __FUNCTION__);
1059     return false;
1060   }
1061
1062   CSingleLock lock(m_critSection);
1063   if (!m_currentFile || *m_currentFile->GetPVRChannelInfoTag() == *item.GetPVRChannelInfoTag())
1064     return false;
1065
1066   g_application.CurrentFileItem() = *m_currentFile;
1067   g_infoManager.SetCurrentItem(*m_currentFile);
1068
1069   CPVRChannel* channelTag = item.GetPVRChannelInfoTag();
1070   CEpgInfoTag epgTagNow;
1071   bool bHasTagNow = channelTag->GetEPGNow(epgTagNow);
1072
1073   if (channelTag->IsRadio())
1074   {
1075     CMusicInfoTag* musictag = item.GetMusicInfoTag();
1076     if (musictag)
1077     {
1078       musictag->SetTitle(bHasTagNow ?
1079           epgTagNow.Title() :
1080           CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
1081               StringUtils::EmptyString :
1082               g_localizeStrings.Get(19055)); // no information available
1083       if (bHasTagNow)
1084         musictag->SetGenre(epgTagNow.Genre());
1085       musictag->SetDuration(bHasTagNow ? epgTagNow.GetDuration() : 3600);
1086       musictag->SetURL(channelTag->Path());
1087       musictag->SetArtist(channelTag->ChannelName());
1088       musictag->SetAlbumArtist(channelTag->ChannelName());
1089       musictag->SetLoaded(true);
1090       musictag->SetComment(StringUtils::EmptyString);
1091       musictag->SetLyrics(StringUtils::EmptyString);
1092     }
1093   }
1094   else
1095   {
1096     CVideoInfoTag *videotag = item.GetVideoInfoTag();
1097     if (videotag)
1098     {
1099       videotag->m_strTitle = bHasTagNow ?
1100           epgTagNow.Title() :
1101           CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
1102               StringUtils::EmptyString :
1103               g_localizeStrings.Get(19055); // no information available
1104       if (bHasTagNow)
1105         videotag->m_genre = epgTagNow.Genre();
1106       videotag->m_strPath = channelTag->Path();
1107       videotag->m_strFileNameAndPath = channelTag->Path();
1108       videotag->m_strPlot = bHasTagNow ? epgTagNow.Plot() : StringUtils::EmptyString;
1109       videotag->m_strPlotOutline = bHasTagNow ? epgTagNow.PlotOutline() : StringUtils::EmptyString;
1110       videotag->m_iEpisode = bHasTagNow ? epgTagNow.EpisodeNum() : 0;
1111     }
1112   }
1113
1114   return false;
1115 }
1116
1117 bool CPVRManager::StartPlayback(const CPVRChannel *channel, bool bPreview /* = false */)
1118 {
1119   CMediaSettings::Get().SetVideoStartWindowed(bPreview);
1120   CApplicationMessenger::Get().MediaPlay(CFileItem(*channel));
1121   CLog::Log(LOGNOTICE, "PVRManager - %s - started playback on channel '%s'",
1122       __FUNCTION__, channel->ChannelName().c_str());
1123   return true;
1124 }
1125
1126 bool CPVRManager::StartPlayback(PlaybackType type /* = PlaybackTypeAny */)
1127 {
1128   bool bIsRadio(false);
1129   bool bReturn(false);
1130   bool bIsPlaying(false);
1131   CFileItemPtr channel;
1132
1133   // check if the desired PlaybackType is already playing,
1134   // and if not, try to grab the last played channel of this type
1135   switch (type)
1136   {
1137     case PlaybackTypeRadio:
1138       if (IsPlayingRadio())
1139         bIsPlaying = true;
1140       else
1141         channel = m_channelGroups->GetGroupAllRadio()->GetLastPlayedChannel();
1142       bIsRadio = true;
1143       break;
1144
1145     case PlaybackTypeTv:
1146       if (IsPlayingTV())
1147         bIsPlaying = true;
1148       else
1149         channel = m_channelGroups->GetGroupAllTV()->GetLastPlayedChannel();
1150       break;
1151
1152     default:
1153       if (IsPlaying())
1154         bIsPlaying = true;
1155       else
1156         channel = m_channelGroups->GetLastPlayedChannel();
1157   }
1158
1159   // we're already playing? Then nothing to do
1160   if (bIsPlaying)
1161     return true;
1162
1163   // if we have a last played channel, start playback
1164   if (channel && channel->HasPVRChannelInfoTag())
1165   {
1166     bReturn = StartPlayback(channel->GetPVRChannelInfoTag(), false);
1167   }
1168   else
1169   {
1170     // if we don't, find the active channel group of the demanded type and play it's first channel
1171     CPVRChannelGroupPtr channelGroup = GetPlayingGroup(bIsRadio);
1172     if (channelGroup)
1173     {
1174       // try to start playback of first channel in this group
1175       CFileItemPtr channel = channelGroup->GetByIndex(0);
1176       if (channel && channel->HasPVRChannelInfoTag())
1177         bReturn = StartPlayback(channel->GetPVRChannelInfoTag(), false);
1178     }
1179   }
1180
1181   if (!bReturn)
1182   {
1183     CLog::Log(LOGNOTICE, "PVRManager - %s - could not determine %s channel to start playback with. No last played channel found, and first channel of active group could also not be determined.", __FUNCTION__, bIsRadio ? "radio": "tv");
1184
1185     CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), g_localizeStrings.Get(bIsRadio ? 19021 : 19020).c_str()); // RADIO/TV could not be played. Check the log for details.
1186     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
1187             g_localizeStrings.Get(19166), // PVR information
1188             msg);
1189   }
1190
1191   return bReturn;
1192 }
1193
1194
1195 bool CPVRManager::PerformChannelSwitch(const CPVRChannel &channel, bool bPreview)
1196 {
1197   // check parental lock state
1198   if (IsParentalLocked(channel))
1199     return false;
1200
1201   // invalid channel
1202   if (channel.ClientID() < 0)
1203     return false;
1204
1205   // check whether we're waiting for a previous switch to complete
1206   {
1207     CSingleLock lock(m_critSection);
1208     if (m_bIsSwitchingChannels)
1209     {
1210       CLog::Log(LOGDEBUG, "PVRManager - %s - can't switch to channel '%s'. waiting for the previous switch to complete",
1211           __FUNCTION__, channel.ChannelName().c_str());
1212       return false;
1213     }
1214
1215     // no need to do anything except switching m_currentFile
1216     if (bPreview)
1217     {
1218       delete m_currentFile;
1219       m_currentFile = new CFileItem(channel);
1220       return true;
1221     }
1222
1223     m_bIsSwitchingChannels = true;
1224   }
1225
1226   CLog::Log(LOGDEBUG, "PVRManager - %s - switching to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
1227
1228   // store current time in iLastWatched
1229   CPVRChannelPtr currentChannel;
1230   if (m_addons->GetPlayingChannel(currentChannel))
1231   {
1232     time_t tNow;
1233     CDateTime::GetCurrentDateTime().GetAsTime(tNow);
1234     currentChannel->SetLastWatched(tNow);
1235
1236     m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(currentChannel->IsRadio()));
1237   }
1238
1239   // store channel settings
1240   SaveCurrentChannelSettings();
1241
1242   // will be deleted by CPVRChannelSwitchJob::DoWork()
1243   CFileItem* previousFile = m_currentFile;
1244   m_currentFile = NULL;
1245
1246   bool bSwitched(false);
1247
1248   // switch channel
1249   if (!m_addons->SwitchChannel(channel))
1250   {
1251     // switch failed
1252     CSingleLock lock(m_critSection);
1253     m_bIsSwitchingChannels = false;
1254
1255     CLog::Log(LOGERROR, "PVRManager - %s - failed to switch to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
1256
1257     CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel.ChannelName().c_str()); // CHANNELNAME could not be played. Check the log for details.
1258     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
1259         g_localizeStrings.Get(19166), // PVR information
1260         msg);
1261   }
1262   else
1263   {
1264     // switch successful
1265     bSwitched = true;
1266
1267     CSingleLock lock(m_critSection);
1268     m_currentFile = new CFileItem(channel);
1269     m_bIsSwitchingChannels = false;
1270
1271     CLog::Log(LOGNOTICE, "PVRManager - %s - switched to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
1272   }
1273
1274   // announce OnStop and OnPlay. yes, this ain't pretty
1275   {
1276     CSingleLock lock(m_critSectionTriggers);
1277     m_pendingUpdates.push_back(new CPVRChannelSwitchJob(previousFile, m_currentFile));
1278   }
1279   m_triggerEvent.Set();
1280
1281   return bSwitched;
1282 }
1283
1284 int CPVRManager::GetTotalTime(void) const
1285 {
1286   return IsStarted() && m_guiInfo ? m_guiInfo->GetDuration() : 0;
1287 }
1288
1289 int CPVRManager::GetStartTime(void) const
1290 {
1291   return IsStarted() && m_guiInfo ? m_guiInfo->GetStartTime() : 0;
1292 }
1293
1294 bool CPVRManager::TranslateBoolInfo(DWORD dwInfo) const
1295 {
1296    return IsStarted() && m_guiInfo ? m_guiInfo->TranslateBoolInfo(dwInfo) : false;
1297 }
1298
1299 bool CPVRManager::TranslateCharInfo(DWORD dwInfo, CStdString &strValue) const
1300 {
1301   return IsStarted() && m_guiInfo ? m_guiInfo->TranslateCharInfo(dwInfo, strValue) : false;
1302 }
1303
1304 int CPVRManager::TranslateIntInfo(DWORD dwInfo) const
1305 {
1306   return IsStarted() && m_guiInfo ? m_guiInfo->TranslateIntInfo(dwInfo) : 0;
1307 }
1308
1309 bool CPVRManager::HasTimers(void) const
1310 {
1311   return IsStarted() && m_timers ? m_timers->HasActiveTimers() : false;
1312 }
1313
1314 bool CPVRManager::IsRecording(void) const
1315 {
1316   return IsStarted() && m_timers ? m_timers->IsRecording() : false;
1317 }
1318
1319 bool CPVRManager::IsIdle(void) const
1320 {
1321   if (!IsStarted())
1322     return true;
1323
1324   if (IsRecording() || IsPlaying()) // pvr recording or playing?
1325   {
1326     return false;
1327   }
1328   else if (m_timers) // has active timers, etc.?
1329   {
1330     const CDateTime now = CDateTime::GetUTCDateTime();
1331     const CDateTimeSpan idle(0, 0, CSettings::Get().GetInt("pvrpowermanagement.backendidletime"), 0);
1332
1333     const CDateTime next = m_timers->GetNextEventTime();
1334     const CDateTimeSpan delta = next - now;
1335
1336     if (delta <= idle)
1337       return false;
1338   }
1339
1340   return true;
1341 }
1342
1343 void CPVRManager::ShowPlayerInfo(int iTimeout)
1344 {
1345   if (IsStarted() && m_guiInfo)
1346     m_guiInfo->ShowPlayerInfo(iTimeout);
1347 }
1348
1349 void CPVRManager::LocalizationChanged(void)
1350 {
1351   CSingleLock lock(m_critSection);
1352   if (IsStarted())
1353   {
1354     static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllRadio().get())->CheckGroupName();
1355     static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllTV().get())->CheckGroupName();
1356   }
1357 }
1358
1359 bool CPVRManager::EpgsCreated(void) const
1360 {
1361   CSingleLock lock(m_critSection);
1362   return m_bEpgsCreated;
1363 }
1364
1365 bool CPVRManager::IsPlayingTV(void) const
1366 {
1367   return IsStarted() && m_addons && m_addons->IsPlayingTV();
1368 }
1369
1370 bool CPVRManager::IsPlayingRadio(void) const
1371 {
1372   return IsStarted() && m_addons && m_addons->IsPlayingRadio();
1373 }
1374
1375 bool CPVRManager::IsPlayingRecording(void) const
1376 {
1377   return IsStarted() && m_addons && m_addons->IsPlayingRecording();
1378 }
1379
1380 bool CPVRManager::IsRunningChannelScan(void) const
1381 {
1382   return IsStarted() && m_addons && m_addons->IsRunningChannelScan();
1383 }
1384
1385 void CPVRManager::StartChannelScan(void)
1386 {
1387   if (IsStarted() && m_addons)
1388     m_addons->StartChannelScan();
1389 }
1390
1391 void CPVRManager::SearchMissingChannelIcons(void)
1392 {
1393   if (IsStarted() && m_channelGroups)
1394     m_channelGroups->SearchMissingChannelIcons();
1395 }
1396
1397 bool CPVRManager::IsJobPending(const char *strJobName) const
1398 {
1399   bool bReturn(false);
1400   CSingleLock lock(m_critSectionTriggers);
1401   for (unsigned int iJobPtr = 0; IsStarted() && iJobPtr < m_pendingUpdates.size(); iJobPtr++)
1402   {
1403     if (!strcmp(m_pendingUpdates.at(iJobPtr)->GetType(), strJobName))
1404     {
1405       bReturn = true;
1406       break;
1407     }
1408   }
1409
1410   return bReturn;
1411 }
1412
1413 void CPVRManager::QueueJob(CJob *job)
1414 {
1415   CSingleLock lock(m_critSectionTriggers);
1416   if (!IsStarted() || IsJobPending(job->GetType()))
1417   {
1418     delete job;
1419     return;
1420   }
1421
1422   m_pendingUpdates.push_back(job);
1423
1424   lock.Leave();
1425   m_triggerEvent.Set();
1426 }
1427
1428 void CPVRManager::TriggerEpgsCreate(void)
1429 {
1430   QueueJob(new CPVREpgsCreateJob());
1431 }
1432
1433 void CPVRManager::TriggerRecordingsUpdate(void)
1434 {
1435   QueueJob(new CPVRRecordingsUpdateJob());
1436 }
1437
1438 void CPVRManager::TriggerTimersUpdate(void)
1439 {
1440   QueueJob(new CPVRTimersUpdateJob());
1441 }
1442
1443 void CPVRManager::TriggerChannelsUpdate(void)
1444 {
1445   QueueJob(new CPVRChannelsUpdateJob());
1446 }
1447
1448 void CPVRManager::TriggerChannelGroupsUpdate(void)
1449 {
1450   QueueJob(new CPVRChannelGroupsUpdateJob());
1451 }
1452
1453 void CPVRManager::TriggerSaveChannelSettings(void)
1454 {
1455   QueueJob(new CPVRChannelSettingsSaveJob());
1456 }
1457
1458 void CPVRManager::ExecutePendingJobs(void)
1459 {
1460   CSingleLock lock(m_critSectionTriggers);
1461
1462   while (m_pendingUpdates.size() > 0)
1463   {
1464     CJob *job = m_pendingUpdates.at(0);
1465     m_pendingUpdates.erase(m_pendingUpdates.begin());
1466     lock.Leave();
1467
1468     job->DoWork();
1469     delete job;
1470
1471     lock.Enter();
1472   }
1473
1474   m_triggerEvent.Reset();
1475 }
1476
1477 bool CPVRManager::OnAction(const CAction &action)
1478 {
1479   // process PVR specific play actions
1480   if (action.GetID() == ACTION_PVR_PLAY || action.GetID() == ACTION_PVR_PLAY_TV || action.GetID() == ACTION_PVR_PLAY_RADIO)
1481   {
1482     // pvr not active yet, show error message
1483     if (!IsStarted())
1484     {
1485       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(19045), g_localizeStrings.Get(19044));
1486     }
1487     else
1488     {
1489       // see if we're already playing a PVR stream and if not or the stream type
1490       // doesn't match the demanded type, start playback of according type
1491       bool isPlayingPvr(IsPlaying() && g_application.CurrentFileItem().HasPVRChannelInfoTag());
1492       switch (action.GetID())
1493       {
1494         case ACTION_PVR_PLAY:
1495           if (!isPlayingPvr)
1496             StartPlayback(PlaybackTypeAny);
1497           break;
1498         case ACTION_PVR_PLAY_TV:
1499           if (!isPlayingPvr || g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
1500             StartPlayback(PlaybackTypeTv);
1501           break;
1502         case ACTION_PVR_PLAY_RADIO:
1503           if (!isPlayingPvr || !g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
1504             StartPlayback(PlaybackTypeRadio);
1505           break;
1506       }
1507     }
1508     return true;
1509   }
1510   return false;
1511 }
1512
1513 void CPVRManager::SettingOptionsPvrStartLastChannelFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current)
1514 {
1515   list.push_back(make_pair(g_localizeStrings.Get(106),   PVR::START_LAST_CHANNEL_OFF));
1516   list.push_back(make_pair(g_localizeStrings.Get(19190), PVR::START_LAST_CHANNEL_MIN));
1517   list.push_back(make_pair(g_localizeStrings.Get(107),   PVR::START_LAST_CHANNEL_ON));
1518 }
1519
1520 bool CPVRChannelSwitchJob::DoWork(void)
1521 {
1522   // announce OnStop and delete m_previous when done
1523   if (m_previous)
1524   {
1525     CVariant data(CVariant::VariantTypeObject);
1526     data["end"] = true;
1527     ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnStop", CFileItemPtr(m_previous), data);
1528   }
1529
1530   // announce OnPlay if the switch was successful
1531   if (m_next)
1532   {
1533     CVariant param;
1534     param["player"]["speed"] = 1;
1535     param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
1536     ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnPlay", CFileItemPtr(new CFileItem(*m_next)), param);
1537   }
1538
1539   return true;
1540 }
1541
1542 bool CPVRManager::CreateChannelEpgs(void)
1543 {
1544   if (EpgsCreated())
1545     return true;
1546
1547   CSingleLock lock(m_critSection);
1548   m_bEpgsCreated = m_channelGroups->CreateChannelEpgs();
1549   return m_bEpgsCreated;
1550 }