2 * Copyright (C) 2012-2013 Team XBMC
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)
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.
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/>.
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"
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"
63 using namespace MUSIC_INFO;
66 using namespace ANNOUNCEMENT;
68 CPVRManager::CPVRManager(void) :
69 CThread("PVRManager"),
70 m_channelGroups(NULL),
79 m_bEpgsCreated(false),
80 m_progressHandle(NULL),
81 m_managerState(ManagerStateStopped),
82 m_bOpenPVRWindow(false)
84 CAnnouncementManager::AddAnnouncer(this);
88 CPVRManager::~CPVRManager(void)
90 CAnnouncementManager::RemoveAnnouncer(this);
92 CLog::Log(LOGDEBUG,"PVRManager - destroyed");
95 void CPVRManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
97 if (!IsStarted() || (flag & (System)) == 0)
100 if (strcmp(message, "OnWake") == 0)
101 ContinueLastChannel();
104 CPVRManager &CPVRManager::Get(void)
106 static CPVRManager pvrManagerInstance;
107 return pvrManagerInstance;
110 void CPVRManager::OnSettingChanged(const CSetting *setting)
115 const std::string &settingId = setting->GetId();
116 if (settingId == "pvrmanager.enabled")
118 if (((CSettingBool*)setting)->GetValue())
119 CApplicationMessenger::Get().ExecBuiltIn("XBMC.StartPVRManager", false);
121 CApplicationMessenger::Get().ExecBuiltIn("XBMC.StopPVRManager", false);
123 else if (settingId == "pvrparental.enabled")
125 if (((CSettingBool*)setting)->GetValue() && CSettings::Get().GetString("pvrparental.pin").empty())
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
133 ((CSettingBool*)setting)->SetValue(false);
138 void CPVRManager::OnSettingAction(const CSetting *setting)
143 const std::string &settingId = setting->GetId();
144 if (settingId == "pvrmenu.searchicons")
147 SearchMissingChannelIcons();
149 else if (settingId == "pvrmanager.resetdb")
151 if (CheckParentalPIN(g_localizeStrings.Get(19262).c_str()) &&
152 CGUIDialogYesNo::ShowAndGetInput(19098, 19186, 750, 0))
154 CDateTime::ResetTimezoneBias();
155 ResetDatabase(false);
158 else if (settingId == "epg.resetepg")
160 if (CGUIDialogYesNo::ShowAndGetInput(19098, 19188, 750, 0))
162 CDateTime::ResetTimezoneBias();
166 else if (settingId == "pvrmanager.channelscan")
171 else if (settingId == "pvrmanager.channelmanager")
175 CGUIDialogPVRChannelManager *dialog = (CGUIDialogPVRChannelManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
180 else if (settingId == "pvrclient.menuhook")
183 Clients()->ProcessMenuHooks(-1, PVR_MENUHOOK_SETTING, NULL);
187 bool CPVRManager::IsPVRWindowActive(void) const
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);
202 bool CPVRManager::InstallAddonAllowed(const std::string& strAddonId) const
204 return !IsStarted() ||
205 !m_addons->IsInUse(strAddonId) ||
206 (!IsPVRWindowActive() && !IsPlaying());
209 void CPVRManager::MarkAsOutdated(const std::string& strAddonId, const std::string& strReferer)
211 if (IsStarted() && CSettings::Get().GetBool("general.addonautoupdate"))
213 CSingleLock lock(m_critSection);
214 m_outdatedAddons.insert(make_pair(strAddonId, strReferer));
218 bool CPVRManager::UpgradeOutdatedAddons(void)
220 CSingleLock lock(m_critSection);
221 if (m_outdatedAddons.empty())
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++)
227 if (!InstallAddonAllowed(it->first))
229 // we can't upgrade right now
234 // all outdated add-ons can be upgraded now
235 CLog::Log(LOGINFO, "PVR - upgrading outdated add-ons");
237 map<string, string> outdatedAddons = m_outdatedAddons;
238 // stop threads and unload
239 SetState(ManagerStateInterrupted);
240 g_EpgContainer.Stop();
245 // upgrade all add-ons
246 for (map<string, string>::iterator it = outdatedAddons.begin(); it != outdatedAddons.end(); it++)
248 CLog::Log(LOGINFO, "PVR - updating add-on '%s'", it->first.c_str());
249 CAddonInstaller::Get().Install(it->first, true, it->second, false);
253 CLog::Log(LOGINFO, "PVRManager - %s - restarting the PVR manager", __FUNCTION__);
254 SetState(ManagerStateStarting);
257 while (!Load() && IsInitialising())
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();
266 if (IsInitialising())
268 SetState(ManagerStateStarted);
269 g_EpgContainer.Start();
271 CLog::Log(LOGDEBUG, "PVRManager - %s - restarted", __FUNCTION__);
278 void CPVRManager::Cleanup(void)
280 CSingleLock lock(m_critSection);
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();
291 m_currentFile = NULL;
292 m_bIsSwitchingChannels = false;
293 m_outdatedAddons.clear();
294 m_bOpenPVRWindow = false;
295 m_bEpgsCreated = false;
297 for (unsigned int iJobPtr = 0; iJobPtr < m_pendingUpdates.size(); iJobPtr++)
298 delete m_pendingUpdates.at(iJobPtr);
299 m_pendingUpdates.clear();
301 HideProgressDialog();
303 SetState(ManagerStateStopped);
306 void CPVRManager::ResetProperties(void)
308 CSingleLock lock(m_critSection);
311 if (!g_application.m_bStop)
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;
322 class CPVRManagerStartJob : public CJob
325 CPVRManagerStartJob(bool bOpenPVRWindow = false) :
326 m_bOpenPVRWindow(bOpenPVRWindow) {}
327 ~CPVRManagerStartJob(void) {}
331 g_PVRManager.Start(false, m_bOpenPVRWindow);
335 bool m_bOpenPVRWindow;
338 void CPVRManager::Start(bool bAsync /* = false */, bool bOpenPVRWindow /* = false */)
342 CPVRManagerStartJob *job = new CPVRManagerStartJob(bOpenPVRWindow);
343 CJobManager::GetInstance().AddJob(job, NULL);
347 CSingleLock lock(m_critSection);
349 /* first stop and remove any clients */
352 /* don't start if Settings->Video->TV->Enable isn't checked */
353 if (!CSettings::Get().GetBool("pvrmanager.enabled"))
357 SetState(ManagerStateStarting);
358 m_bOpenPVRWindow = bOpenPVRWindow;
360 /* create and open database */
362 m_database = new CPVRDatabase;
365 /* create the supervisor thread to do all background activities */
366 StartUpdateThreads();
369 void CPVRManager::Stop(void)
371 /* check whether the pvrmanager is loaded */
372 if (IsStopping() || IsStopped())
375 SetState(ManagerStateStopping);
377 /* stop the EPG updater, since it might be using the pvr add-ons */
378 g_EpgContainer.Stop();
380 CLog::Log(LOGNOTICE, "PVRManager - stopping");
382 /* stop playback if needed */
385 CLog::Log(LOGNOTICE,"PVRManager - %s - stopping PVR playback", __FUNCTION__);
386 CApplicationMessenger::Get().MediaStop();
389 /* stop all update threads */
392 /* executes the set wakeup command */
396 if (m_database->IsOpen())
399 /* unload all data */
403 ManagerState CPVRManager::GetState(void) const
405 CSingleLock lock(m_managerStateMutex);
406 return m_managerState;
409 void CPVRManager::SetState(ManagerState state)
412 CSingleLock lock(m_managerStateMutex);
413 m_managerState = state;
417 NotifyObservers(ObservableMessageManagerStateChanged);
420 void CPVRManager::Process(void)
422 g_EpgContainer.Stop();
424 /* load the pvr data from the db and clients if it's not already loaded */
425 while (!Load() && IsInitialising())
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();
434 if (IsInitialising())
435 SetState(ManagerStateStarted);
440 CLog::Log(LOGDEBUG, "PVRManager - %s - entering main loop", __FUNCTION__);
441 g_EpgContainer.Start();
443 if (m_bOpenPVRWindow)
445 m_bOpenPVRWindow = false;
446 CApplicationMessenger::Get().ExecBuiltIn("XBMC.ActivateWindowAndFocus(MyPVR, 32,0, 11,0)");
449 bool bRestart(false);
450 while (IsStarted() && m_addons && m_addons->HasConnectedClients() && !bRestart)
452 /* continue last watched channel after first startup */
456 CSingleLock lock(m_critSection);
457 m_bFirstStart = false;
459 ContinueLastChannel();
461 /* execute the next pending jobs if there are any */
464 ExecutePendingJobs();
468 CLog::Log(LOGERROR, "PVRManager - %s - an error occured while trying to execute the last update job, trying to recover", __FUNCTION__);
472 if (!UpgradeOutdatedAddons())
474 // failed to load after upgrading
475 CLog::Log(LOGERROR, "PVRManager - %s - could not load pvr data after upgrading. stopping the pvrmanager", __FUNCTION__);
477 else if (IsStarted() && !bRestart)
478 m_triggerEvent.WaitMSec(1000);
483 CLog::Log(LOGNOTICE, "PVRManager - %s - no add-ons enabled anymore. restarting the pvrmanager", __FUNCTION__);
484 CApplicationMessenger::Get().ExecBuiltIn("StartPVRManager", false);
488 if (g_windowManager.GetActiveWindow() == WINDOW_PVR)
489 g_windowManager.ActivateWindow(WINDOW_HOME);
493 bool CPVRManager::SetWakeupCommand(void)
495 if (!CSettings::Get().GetBool("pvrpowermanagement.enabled"))
498 const CStdString strWakeupCommand = CSettings::Get().GetString("pvrpowermanagement.setwakeupcmd");
499 if (!strWakeupCommand.empty() && m_timers)
502 const CDateTime nextEvent = m_timers->GetNextEventTime();
503 if (nextEvent.IsValid())
505 nextEvent.GetAsTime(iWakeupTime);
507 CStdString strExecCommand = StringUtils::Format("%s %d", strWakeupCommand.c_str(), iWakeupTime);
509 const int iReturn = system(strExecCommand.c_str());
511 CLog::Log(LOGERROR, "%s - failed to execute wakeup command '%s': %s (%d)", __FUNCTION__, strExecCommand.c_str(), strerror(iReturn), iReturn);
520 bool CPVRManager::StartUpdateThreads(void)
523 CLog::Log(LOGNOTICE, "PVRManager - starting up");
525 /* create the pvrmanager thread, which will ensure that all data will be loaded */
526 SetState(ManagerStateStarting);
533 void CPVRManager::StopUpdateThreads(void)
535 SetState(ManagerStateInterrupted);
544 bool CPVRManager::Load(void)
546 /* start the add-on update thread */
550 /* load at least one client */
551 while (IsInitialising() && m_addons && !m_addons->HasConnectedClients())
554 if (!IsInitialising() || !m_addons || !m_addons->HasConnectedClients())
557 CLog::Log(LOGDEBUG, "PVRManager - %s - active clients found. continue to start", __FUNCTION__);
559 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
563 /* load all channels and groups */
564 ShowProgressDialog(g_localizeStrings.Get(19236), 0); // Loading channels from clients
565 if (!m_channelGroups->Load() || !IsInitialising())
568 /* get timers from the backends */
569 ShowProgressDialog(g_localizeStrings.Get(19237), 50); // Loading timers from clients
572 /* get recordings from the backend */
573 ShowProgressDialog(g_localizeStrings.Get(19238), 75); // Loading recordings from clients
574 m_recordings->Load();
576 if (!IsInitialising())
579 /* start the other pvr related update threads */
580 ShowProgressDialog(g_localizeStrings.Get(19239), 85); // Starting background threads
583 /* close the progess dialog */
584 HideProgressDialog();
589 void CPVRManager::ShowProgressDialog(const CStdString &strText, int iProgress)
591 if (!m_progressHandle)
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
597 m_progressHandle->SetPercentage((float)iProgress);
598 m_progressHandle->SetText(strText);
601 void CPVRManager::HideProgressDialog(void)
603 if (m_progressHandle)
605 m_progressHandle->MarkFinished();
606 m_progressHandle = NULL;
610 bool CPVRManager::ChannelSwitch(unsigned int iChannelNumber)
612 CSingleLock lock(m_critSection);
614 CPVRChannelGroupPtr playingGroup = GetPlayingGroup(m_addons->IsPlayingRadio());
617 CLog::Log(LOGERROR, "PVRManager - %s - cannot get the selected group", __FUNCTION__);
621 CFileItemPtr channel = playingGroup->GetByChannelNumber(iChannelNumber);
622 if (!channel || !channel->HasPVRChannelInfoTag())
624 CLog::Log(LOGERROR, "PVRManager - %s - cannot find channel %d", __FUNCTION__, iChannelNumber);
628 return PerformChannelSwitch(*channel->GetPVRChannelInfoTag(), false);
631 bool CPVRManager::ChannelUpDown(unsigned int *iNewChannelNumber, bool bPreview, bool bUp)
633 bool bReturn = false;
634 if (IsPlayingTV() || IsPlayingRadio())
636 CFileItem currentFile(g_application.CurrentFileItem());
637 CPVRChannel *currentChannel = currentFile.GetPVRChannelInfoTag();
638 CPVRChannelGroupPtr group = GetPlayingGroup(currentChannel->IsRadio());
641 CFileItemPtr newChannel = bUp ?
642 group->GetByChannelUp(*currentChannel) :
643 group->GetByChannelDown(*currentChannel);
645 if (newChannel && newChannel->HasPVRChannelInfoTag() &&
646 PerformChannelSwitch(*newChannel->GetPVRChannelInfoTag(), bPreview))
648 *iNewChannelNumber = newChannel->GetPVRChannelInfoTag()->ChannelNumber();
657 bool CPVRManager::ContinueLastChannel(void)
659 if (CSettings::Get().GetInt("pvrplayback.startlast") == START_LAST_CHANNEL_OFF)
662 CFileItemPtr channel = m_channelGroups->GetLastPlayedChannel();
663 if (channel && channel->HasPVRChannelInfoTag())
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));
672 void CPVRManager::ResetDatabase(bool bResetEPGOnly /* = false */)
674 CLog::Log(LOGNOTICE,"PVRManager - %s - clearing the PVR database", __FUNCTION__);
676 g_EpgContainer.Stop();
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();
685 if (m_addons && m_addons->IsPlaying())
687 CLog::Log(LOGNOTICE,"PVRManager - %s - stopping playback", __FUNCTION__);
688 CApplicationMessenger::Get().MediaStop();
691 pDlgProgress->SetPercentage(10);
692 pDlgProgress->Progress();
694 /* reset the EPG pointers */
696 m_database->ResetEPG();
698 /* stop the thread */
701 pDlgProgress->SetPercentage(20);
702 pDlgProgress->Progress();
705 m_database = new CPVRDatabase;
707 if (m_database && m_database->Open())
709 /* clean the EPG database */
710 g_EpgContainer.Reset();
711 pDlgProgress->SetPercentage(30);
712 pDlgProgress->Progress();
716 m_database->DeleteChannelGroups();
717 pDlgProgress->SetPercentage(50);
718 pDlgProgress->Progress();
720 /* delete all channels */
721 m_database->DeleteChannels();
722 pDlgProgress->SetPercentage(70);
723 pDlgProgress->Progress();
725 /* delete all channel settings */
726 m_database->DeleteChannelSettings();
727 pDlgProgress->SetPercentage(80);
728 pDlgProgress->Progress();
730 /* delete all client information */
731 m_database->DeleteClients();
732 pDlgProgress->SetPercentage(90);
733 pDlgProgress->Progress();
739 CLog::Log(LOGNOTICE,"PVRManager - %s - %s database cleared", __FUNCTION__, bResetEPGOnly ? "EPG" : "PVR and EPG");
741 if (CSettings::Get().GetBool("pvrmanager.enabled"))
743 CLog::Log(LOGNOTICE,"PVRManager - %s - restarting the PVRManager", __FUNCTION__);
749 pDlgProgress->SetPercentage(100);
750 pDlgProgress->Close();
753 bool CPVRManager::IsPlaying(void) const
755 return IsStarted() && m_addons && m_addons->IsPlaying();
758 bool CPVRManager::GetCurrentChannel(CPVRChannelPtr &channel) const
760 return m_addons && m_addons->GetPlayingChannel(channel);
763 int CPVRManager::GetCurrentEpg(CFileItemList &results) const
767 CPVRChannelPtr channel;
768 if (m_addons->GetPlayingChannel(channel))
769 iReturn = channel->GetEPG(results);
771 CLog::Log(LOGDEBUG,"PVRManager - %s - no current channel set", __FUNCTION__);
776 void CPVRManager::ResetPlayingTag(void)
778 CSingleLock lock(m_critSection);
779 if (IsStarted() && m_guiInfo)
780 m_guiInfo->ResetPlayingTag();
783 int CPVRManager::GetPreviousChannel(void)
785 CPVRChannelPtr currentChannel;
786 if (GetCurrentChannel(currentChannel))
788 CPVRChannelGroupPtr selectedGroup = GetPlayingGroup(currentChannel->IsRadio());
789 CFileItemPtr channel = selectedGroup->GetLastPlayedChannel(currentChannel->ChannelID());
790 if (channel && channel->HasPVRChannelInfoTag())
791 return channel->GetPVRChannelInfoTag()->ChannelNumber();
796 bool CPVRManager::ToggleRecordingOnChannel(unsigned int iChannelId)
798 bool bReturn = false;
800 CPVRChannelPtr channel = m_channelGroups->GetChannelById(iChannelId);
804 if (m_addons->HasTimerSupport(channel->ClientID()))
806 /* timers are supported on this channel */
807 if (!channel->IsRecording())
809 bReturn = m_timers->InstantTimer(*channel);
811 CGUIDialogOK::ShowAndGetInput(19033,0,19164,0);
815 /* delete active timers */
816 bReturn = m_timers->DeleteTimersOnChannel(*channel, false, true);
823 bool CPVRManager::StartRecordingOnPlayingChannel(bool bOnOff)
825 bool bReturn = false;
827 CPVRChannelPtr channel;
828 if (!m_addons->GetPlayingChannel(channel))
831 if (m_addons->HasTimerSupport(channel->ClientID()))
833 /* timers are supported on this channel */
834 if (bOnOff && !channel->IsRecording())
836 bReturn = m_timers->InstantTimer(*channel);
838 CGUIDialogOK::ShowAndGetInput(19033,0,19164,0);
840 else if (!bOnOff && channel->IsRecording())
842 /* delete active timers */
843 bReturn = m_timers->DeleteTimersOnChannel(*channel, true, true);
850 bool CPVRManager::CheckParentalLock(const CPVRChannel &channel)
852 bool bReturn = !IsParentalLocked(channel) ||
856 CLog::Log(LOGERROR, "PVRManager - %s - parental lock verification failed for channel '%s': wrong PIN entered.", __FUNCTION__, channel.ChannelName().c_str());
861 bool CPVRManager::IsParentalLocked(const CPVRChannel &channel)
864 CSingleLock lock(m_managerStateMutex);
867 CPVRChannelPtr currentChannel(new CPVRChannel(false));
869 if (// different channel
870 (!GetCurrentChannel(currentChannel) || channel != *currentChannel) &&
871 // parental control enabled
872 CSettings::Get().GetBool("pvrparental.enabled") &&
876 float parentalDurationMs = CSettings::Get().GetInt("pvrparental.duration") * 1000.0f;
877 bReturn = m_parentalTimer &&
878 (!m_parentalTimer->IsRunning() ||
879 m_parentalTimer->GetElapsedMilliseconds() > parentalDurationMs);
885 bool CPVRManager::CheckParentalPIN(const char *strTitle /* = NULL */)
887 CStdString pinCode = CSettings::Get().GetString("pvrparental.pin");
889 if (!CSettings::Get().GetBool("pvrparental.enabled") || pinCode.empty())
892 // Locked channel. Enter PIN:
893 bool bValidPIN = CGUIDialogNumeric::ShowAndVerifyInput(pinCode, strTitle ? strTitle : g_localizeStrings.Get(19263).c_str(), true);
895 // display message: The entered PIN number was incorrect
896 CGUIDialogOK::ShowAndGetInput(19264,0,19265,0);
897 else if (m_parentalTimer)
900 m_parentalTimer->StartZero();
906 void CPVRManager::SaveCurrentChannelSettings(void)
908 m_addons->SaveCurrentChannelSettings();
911 void CPVRManager::LoadCurrentChannelSettings()
913 m_addons->LoadCurrentChannelSettings();
916 void CPVRManager::SetPlayingGroup(CPVRChannelGroupPtr group)
918 if (m_channelGroups && group)
919 m_channelGroups->Get(group->IsRadio())->SetSelectedGroup(group);
922 CPVRChannelGroupPtr CPVRManager::GetPlayingGroup(bool bRadio /* = false */)
925 return m_channelGroups->GetSelectedGroup(bRadio);
927 return CPVRChannelGroupPtr();
930 bool CPVREpgsCreateJob::DoWork(void)
932 return g_PVRManager.CreateChannelEpgs();
935 bool CPVRRecordingsUpdateJob::DoWork(void)
937 g_PVRRecordings->Update();
941 bool CPVRTimersUpdateJob::DoWork(void)
943 return g_PVRTimers->Update();
946 bool CPVRChannelsUpdateJob::DoWork(void)
948 return g_PVRChannelGroups->Update(true);
951 bool CPVRChannelGroupsUpdateJob::DoWork(void)
953 return g_PVRChannelGroups->Update(false);
956 bool CPVRChannelSettingsSaveJob::DoWork(void)
958 g_PVRManager.SaveCurrentChannelSettings();
962 bool CPVRManager::OpenLiveStream(const CFileItem &channel)
965 if (!channel.HasPVRChannelInfoTag())
968 CLog::Log(LOGDEBUG,"PVRManager - %s - opening live stream on channel '%s'",
969 __FUNCTION__, channel.GetPVRChannelInfoTag()->ChannelName().c_str());
971 // check if we're allowed to play this file
972 if (IsParentalLocked(*channel.GetPVRChannelInfoTag()))
975 CPVRChannelPtr playingChannel;
976 bool bPersistChannel(false);
977 if ((bReturn = m_addons->OpenStream(*channel.GetPVRChannelInfoTag(), false)) != false)
979 CSingleLock lock(m_critSection);
981 delete m_currentFile;
982 m_currentFile = new CFileItem(channel);
984 if (m_addons->GetPlayingChannel(playingChannel))
986 /* store current time in iLastWatched */
988 CDateTime::GetCurrentDateTime().GetAsTime(tNow);
989 playingChannel->SetLastWatched(tNow);
990 bPersistChannel = true;
992 m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(playingChannel->IsRadio()));
997 playingChannel->Persist();
1002 bool CPVRManager::OpenRecordedStream(const CPVRRecording &tag)
1004 bool bReturn = false;
1005 CSingleLock lock(m_critSection);
1007 if ((bReturn = m_addons->OpenStream(tag)) != false)
1009 delete m_currentFile;
1010 m_currentFile = new CFileItem(tag);
1016 void CPVRManager::CloseStream(void)
1018 CPVRChannelPtr channel;
1019 bool bPersistChannel(false);
1022 CSingleLock lock(m_critSection);
1024 if (m_addons->GetPlayingChannel(channel))
1026 /* store current time in iLastWatched */
1028 CDateTime::GetCurrentDateTime().GetAsTime(tNow);
1029 channel->SetLastWatched(tNow);
1030 bPersistChannel = true;
1032 m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(channel->IsRadio()));
1035 m_addons->CloseStream();
1036 SAFE_DELETE(m_currentFile);
1039 if (bPersistChannel)
1043 void CPVRManager::UpdateCurrentFile(void)
1045 CSingleLock lock(m_critSection);
1047 UpdateItem(*m_currentFile);
1050 bool CPVRManager::UpdateItem(CFileItem& item)
1052 /* Don't update if a recording is played */
1053 if (item.IsPVRRecording())
1056 if (!item.IsPVRChannel())
1058 CLog::Log(LOGERROR, "CPVRManager - %s - no channel tag provided", __FUNCTION__);
1062 CSingleLock lock(m_critSection);
1063 if (!m_currentFile || *m_currentFile->GetPVRChannelInfoTag() == *item.GetPVRChannelInfoTag())
1066 g_application.CurrentFileItem() = *m_currentFile;
1067 g_infoManager.SetCurrentItem(*m_currentFile);
1069 CPVRChannel* channelTag = item.GetPVRChannelInfoTag();
1070 CEpgInfoTag epgTagNow;
1071 bool bHasTagNow = channelTag->GetEPGNow(epgTagNow);
1073 if (channelTag->IsRadio())
1075 CMusicInfoTag* musictag = item.GetMusicInfoTag();
1078 musictag->SetTitle(bHasTagNow ?
1080 CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
1081 StringUtils::EmptyString :
1082 g_localizeStrings.Get(19055)); // no information available
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);
1096 CVideoInfoTag *videotag = item.GetVideoInfoTag();
1099 videotag->m_strTitle = bHasTagNow ?
1101 CSettings::Get().GetBool("epg.hidenoinfoavailable") ?
1102 StringUtils::EmptyString :
1103 g_localizeStrings.Get(19055); // no information available
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;
1117 bool CPVRManager::StartPlayback(const CPVRChannel *channel, bool bPreview /* = false */)
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());
1126 bool CPVRManager::StartPlayback(PlaybackType type /* = PlaybackTypeAny */)
1128 bool bIsRadio(false);
1129 bool bReturn(false);
1130 bool bIsPlaying(false);
1131 CFileItemPtr channel;
1133 // check if the desired PlaybackType is already playing,
1134 // and if not, try to grab the last played channel of this type
1137 case PlaybackTypeRadio:
1138 if (IsPlayingRadio())
1141 channel = m_channelGroups->GetGroupAllRadio()->GetLastPlayedChannel();
1145 case PlaybackTypeTv:
1149 channel = m_channelGroups->GetGroupAllTV()->GetLastPlayedChannel();
1156 channel = m_channelGroups->GetLastPlayedChannel();
1159 // we're already playing? Then nothing to do
1163 // if we have a last played channel, start playback
1164 if (channel && channel->HasPVRChannelInfoTag())
1166 bReturn = StartPlayback(channel->GetPVRChannelInfoTag(), false);
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);
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);
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");
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
1195 bool CPVRManager::PerformChannelSwitch(const CPVRChannel &channel, bool bPreview)
1197 // check parental lock state
1198 if (IsParentalLocked(channel))
1202 if (channel.ClientID() < 0)
1205 // check whether we're waiting for a previous switch to complete
1207 CSingleLock lock(m_critSection);
1208 if (m_bIsSwitchingChannels)
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());
1215 // no need to do anything except switching m_currentFile
1218 delete m_currentFile;
1219 m_currentFile = new CFileItem(channel);
1223 m_bIsSwitchingChannels = true;
1226 CLog::Log(LOGDEBUG, "PVRManager - %s - switching to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
1228 // store current time in iLastWatched
1229 CPVRChannelPtr currentChannel;
1230 if (m_addons->GetPlayingChannel(currentChannel))
1233 CDateTime::GetCurrentDateTime().GetAsTime(tNow);
1234 currentChannel->SetLastWatched(tNow);
1236 m_channelGroups->SetLastPlayedGroup(GetPlayingGroup(currentChannel->IsRadio()));
1239 // store channel settings
1240 SaveCurrentChannelSettings();
1242 // will be deleted by CPVRChannelSwitchJob::DoWork()
1243 CFileItem* previousFile = m_currentFile;
1244 m_currentFile = NULL;
1246 bool bSwitched(false);
1249 if (!m_addons->SwitchChannel(channel))
1252 CSingleLock lock(m_critSection);
1253 m_bIsSwitchingChannels = false;
1255 CLog::Log(LOGERROR, "PVRManager - %s - failed to switch to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
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
1264 // switch successful
1267 CSingleLock lock(m_critSection);
1268 m_currentFile = new CFileItem(channel);
1269 m_bIsSwitchingChannels = false;
1271 CLog::Log(LOGNOTICE, "PVRManager - %s - switched to channel '%s'", __FUNCTION__, channel.ChannelName().c_str());
1274 // announce OnStop and OnPlay. yes, this ain't pretty
1276 CSingleLock lock(m_critSectionTriggers);
1277 m_pendingUpdates.push_back(new CPVRChannelSwitchJob(previousFile, m_currentFile));
1279 m_triggerEvent.Set();
1284 int CPVRManager::GetTotalTime(void) const
1286 return IsStarted() && m_guiInfo ? m_guiInfo->GetDuration() : 0;
1289 int CPVRManager::GetStartTime(void) const
1291 return IsStarted() && m_guiInfo ? m_guiInfo->GetStartTime() : 0;
1294 bool CPVRManager::TranslateBoolInfo(DWORD dwInfo) const
1296 return IsStarted() && m_guiInfo ? m_guiInfo->TranslateBoolInfo(dwInfo) : false;
1299 bool CPVRManager::TranslateCharInfo(DWORD dwInfo, CStdString &strValue) const
1301 return IsStarted() && m_guiInfo ? m_guiInfo->TranslateCharInfo(dwInfo, strValue) : false;
1304 int CPVRManager::TranslateIntInfo(DWORD dwInfo) const
1306 return IsStarted() && m_guiInfo ? m_guiInfo->TranslateIntInfo(dwInfo) : 0;
1309 bool CPVRManager::HasTimers(void) const
1311 return IsStarted() && m_timers ? m_timers->HasActiveTimers() : false;
1314 bool CPVRManager::IsRecording(void) const
1316 return IsStarted() && m_timers ? m_timers->IsRecording() : false;
1319 bool CPVRManager::IsIdle(void) const
1324 if (IsRecording() || IsPlaying()) // pvr recording or playing?
1328 else if (m_timers) // has active timers, etc.?
1330 const CDateTime now = CDateTime::GetUTCDateTime();
1331 const CDateTimeSpan idle(0, 0, CSettings::Get().GetInt("pvrpowermanagement.backendidletime"), 0);
1333 const CDateTime next = m_timers->GetNextEventTime();
1334 const CDateTimeSpan delta = next - now;
1343 void CPVRManager::ShowPlayerInfo(int iTimeout)
1345 if (IsStarted() && m_guiInfo)
1346 m_guiInfo->ShowPlayerInfo(iTimeout);
1349 void CPVRManager::LocalizationChanged(void)
1351 CSingleLock lock(m_critSection);
1354 static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllRadio().get())->CheckGroupName();
1355 static_cast<CPVRChannelGroupInternal *>(m_channelGroups->GetGroupAllTV().get())->CheckGroupName();
1359 bool CPVRManager::EpgsCreated(void) const
1361 CSingleLock lock(m_critSection);
1362 return m_bEpgsCreated;
1365 bool CPVRManager::IsPlayingTV(void) const
1367 return IsStarted() && m_addons && m_addons->IsPlayingTV();
1370 bool CPVRManager::IsPlayingRadio(void) const
1372 return IsStarted() && m_addons && m_addons->IsPlayingRadio();
1375 bool CPVRManager::IsPlayingRecording(void) const
1377 return IsStarted() && m_addons && m_addons->IsPlayingRecording();
1380 bool CPVRManager::IsRunningChannelScan(void) const
1382 return IsStarted() && m_addons && m_addons->IsRunningChannelScan();
1385 void CPVRManager::StartChannelScan(void)
1387 if (IsStarted() && m_addons)
1388 m_addons->StartChannelScan();
1391 void CPVRManager::SearchMissingChannelIcons(void)
1393 if (IsStarted() && m_channelGroups)
1394 m_channelGroups->SearchMissingChannelIcons();
1397 bool CPVRManager::IsJobPending(const char *strJobName) const
1399 bool bReturn(false);
1400 CSingleLock lock(m_critSectionTriggers);
1401 for (unsigned int iJobPtr = 0; IsStarted() && iJobPtr < m_pendingUpdates.size(); iJobPtr++)
1403 if (!strcmp(m_pendingUpdates.at(iJobPtr)->GetType(), strJobName))
1413 void CPVRManager::QueueJob(CJob *job)
1415 CSingleLock lock(m_critSectionTriggers);
1416 if (!IsStarted() || IsJobPending(job->GetType()))
1422 m_pendingUpdates.push_back(job);
1425 m_triggerEvent.Set();
1428 void CPVRManager::TriggerEpgsCreate(void)
1430 QueueJob(new CPVREpgsCreateJob());
1433 void CPVRManager::TriggerRecordingsUpdate(void)
1435 QueueJob(new CPVRRecordingsUpdateJob());
1438 void CPVRManager::TriggerTimersUpdate(void)
1440 QueueJob(new CPVRTimersUpdateJob());
1443 void CPVRManager::TriggerChannelsUpdate(void)
1445 QueueJob(new CPVRChannelsUpdateJob());
1448 void CPVRManager::TriggerChannelGroupsUpdate(void)
1450 QueueJob(new CPVRChannelGroupsUpdateJob());
1453 void CPVRManager::TriggerSaveChannelSettings(void)
1455 QueueJob(new CPVRChannelSettingsSaveJob());
1458 void CPVRManager::ExecutePendingJobs(void)
1460 CSingleLock lock(m_critSectionTriggers);
1462 while (m_pendingUpdates.size() > 0)
1464 CJob *job = m_pendingUpdates.at(0);
1465 m_pendingUpdates.erase(m_pendingUpdates.begin());
1474 m_triggerEvent.Reset();
1477 bool CPVRManager::OnAction(const CAction &action)
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)
1482 // pvr not active yet, show error message
1485 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(19045), g_localizeStrings.Get(19044));
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())
1494 case ACTION_PVR_PLAY:
1496 StartPlayback(PlaybackTypeAny);
1498 case ACTION_PVR_PLAY_TV:
1499 if (!isPlayingPvr || g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
1500 StartPlayback(PlaybackTypeTv);
1502 case ACTION_PVR_PLAY_RADIO:
1503 if (!isPlayingPvr || !g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
1504 StartPlayback(PlaybackTypeRadio);
1513 void CPVRManager::SettingOptionsPvrStartLastChannelFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t)
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));
1520 bool CPVRChannelSwitchJob::DoWork(void)
1522 // announce OnStop and delete m_previous when done
1525 CVariant data(CVariant::VariantTypeObject);
1527 ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::Player, "xbmc", "OnStop", CFileItemPtr(m_previous), data);
1530 // announce OnPlay if the switch was successful
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);
1542 bool CPVRManager::CreateChannelEpgs(void)
1547 CSingleLock lock(m_critSection);
1548 m_bEpgsCreated = m_channelGroups->CreateChannelEpgs();
1549 return m_bEpgsCreated;