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