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 "PVRClients.h"
23 #include "Application.h"
24 #include "ApplicationMessenger.h"
25 #include "GUIUserMessages.h"
26 #include "dialogs/GUIDialogOK.h"
27 #include "dialogs/GUIDialogSelect.h"
28 #include "pvr/PVRManager.h"
29 #include "pvr/PVRDatabase.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "settings/DisplaySettings.h"
32 #include "settings/MediaSettings.h"
33 #include "settings/Settings.h"
34 #include "pvr/channels/PVRChannelGroups.h"
35 #include "pvr/channels/PVRChannelGroupInternal.h"
36 #include "pvr/recordings/PVRRecordings.h"
37 #include "pvr/timers/PVRTimers.h"
38 #include "cores/IPlayer.h"
40 #ifdef HAS_VIDEO_PLAYBACK
41 #include "cores/VideoRenderers/RenderManager.h"
45 using namespace ADDON;
49 CPVRClients::CPVRClients(void) :
51 m_bChannelScanRunning(false),
52 m_bIsSwitchingChannels(false),
53 m_bIsValidChannelSettings(false),
54 m_playingClientId(-EINVAL),
55 m_bIsPlayingLiveTV(false),
56 m_bIsPlayingRecording(false),
58 m_bNoAddonWarningDisplayed(false)
62 CPVRClients::~CPVRClients(void)
67 bool CPVRClients::IsInUse(const std::string& strAddonId) const
69 CSingleLock lock(m_critSection);
71 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
72 if (itr->second->Enabled() && itr->second->ID().Equals(strAddonId.c_str()))
77 void CPVRClients::Start(void)
86 void CPVRClients::Stop(void)
92 bool CPVRClients::IsConnectedClient(int iClientId) const
95 return GetConnectedClient(iClientId, client);
98 bool CPVRClients::IsConnectedClient(const AddonPtr addon)
100 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
101 if (itr->second->ID() == addon->ID())
102 return itr->second->ReadyToUse();
106 int CPVRClients::GetClientId(const AddonPtr client) const
108 CSingleLock lock(m_critSection);
110 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
111 if (itr->second->ID() == client->ID())
117 bool CPVRClients::GetClient(int iClientId, PVR_CLIENT &addon) const
120 if (iClientId <= PVR_INVALID_CLIENT_ID || iClientId == PVR_VIRTUAL_CLIENT_ID)
123 CSingleLock lock(m_critSection);
125 PVR_CLIENTMAP_CITR itr = m_clientMap.find(iClientId);
126 if (itr != m_clientMap.end())
135 bool CPVRClients::GetConnectedClient(int iClientId, PVR_CLIENT &addon) const
137 if (GetClient(iClientId, addon))
138 return addon->ReadyToUse();
142 bool CPVRClients::RequestRestart(AddonPtr addon, bool bDataChanged)
144 return StopClient(addon, true);
147 bool CPVRClients::RequestRemoval(AddonPtr addon)
149 return StopClient(addon, false);
152 void CPVRClients::Unload(void)
156 CSingleLock lock(m_critSection);
158 /* destroy all clients */
159 for (PVR_CLIENTMAP_ITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
160 itr->second->Destroy();
162 /* reset class properties */
163 m_bChannelScanRunning = false;
164 m_bIsPlayingLiveTV = false;
165 m_bIsPlayingRecording = false;
166 m_strPlayingClientName = "";
171 int CPVRClients::GetFirstConnectedClientID(void)
173 CSingleLock lock(m_critSection);
175 for (PVR_CLIENTMAP_ITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
176 if (itr->second->ReadyToUse())
177 return itr->second->GetID();
182 int CPVRClients::EnabledClientAmount(void) const
185 CSingleLock lock(m_critSection);
187 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
188 if (itr->second->Enabled())
194 bool CPVRClients::HasEnabledClients(void) const
196 return EnabledClientAmount() > 0;
199 bool CPVRClients::StopClient(AddonPtr client, bool bRestart)
201 CSingleLock lock(m_critSection);
202 int iId = GetClientId(client);
203 PVR_CLIENT mappedClient;
204 if (GetConnectedClient(iId, mappedClient))
207 mappedClient->ReCreate();
209 mappedClient->Destroy();
217 int CPVRClients::ConnectedClientAmount(void) const
220 CSingleLock lock(m_critSection);
222 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
223 if (itr->second->ReadyToUse())
229 bool CPVRClients::HasConnectedClients(void) const
231 CSingleLock lock(m_critSection);
233 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
234 if (itr->second->ReadyToUse())
240 bool CPVRClients::GetClientName(int iClientId, CStdString &strName) const
244 if ((bReturn = GetConnectedClient(iClientId, client)) == true)
245 strName = client->GetFriendlyName();
250 int CPVRClients::GetConnectedClients(PVR_CLIENTMAP &clients) const
253 CSingleLock lock(m_critSection);
255 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
257 if (itr->second->ReadyToUse())
259 clients.insert(std::make_pair(itr->second->GetID(), itr->second));
267 int CPVRClients::GetPlayingClientID(void) const
269 CSingleLock lock(m_critSection);
271 if (m_bIsPlayingLiveTV || m_bIsPlayingRecording)
272 return m_playingClientId;
276 const CStdString CPVRClients::GetPlayingClientName(void) const
278 CSingleLock lock(m_critSection);
279 return m_strPlayingClientName;
282 CStdString CPVRClients::GetStreamURL(const CPVRChannel &tag)
284 CStdString strReturn;
286 if (GetConnectedClient(tag.ClientID(), client))
287 strReturn = client->GetLiveStreamURL(tag);
289 CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, tag.ClientID());
294 bool CPVRClients::SwitchChannel(const CPVRChannel &channel)
297 CSingleLock lock(m_critSection);
298 if (m_bIsSwitchingChannels)
300 CLog::Log(LOGDEBUG, "PVRClients - %s - can't switch to channel '%s'. waiting for the previous switch to complete", __FUNCTION__, channel.ChannelName().c_str());
303 m_bIsSwitchingChannels = true;
306 bool bSwitchSuccessful(false);
307 CPVRChannelPtr currentChannel;
308 if (// no channel is currently playing
309 !GetPlayingChannel(currentChannel) ||
311 currentChannel->ClientID() != channel.ClientID() ||
312 // stream URL should always be opened as a new file
313 !channel.StreamURL().IsEmpty() || !currentChannel->StreamURL().IsEmpty())
315 if (channel.StreamURL().IsEmpty())
318 bSwitchSuccessful = OpenStream(channel, true);
322 CFileItem m_currentFile(channel);
323 CApplicationMessenger::Get().PlayFile(m_currentFile, false);
324 bSwitchSuccessful = true;
328 else if (currentChannel.get() && *currentChannel == channel)
330 bSwitchSuccessful = true;
335 if (GetConnectedClient(channel.ClientID(), client))
336 bSwitchSuccessful = client->SwitchChannel(channel);
340 CSingleLock lock(m_critSection);
341 m_bIsSwitchingChannels = false;
342 if (bSwitchSuccessful)
343 m_bIsValidChannelSettings = false;
346 if (!bSwitchSuccessful)
347 CLog::Log(LOGERROR, "PVR - %s - cannot switch to channel '%s' on client '%d'",__FUNCTION__, channel.ChannelName().c_str(), channel.ClientID());
349 return bSwitchSuccessful;
352 bool CPVRClients::GetPlayingChannel(CPVRChannelPtr &channel) const
355 if (GetPlayingClient(client))
356 return client->GetPlayingChannel(channel);
360 bool CPVRClients::GetPlayingRecording(CPVRRecording &recording) const
363 if (GetPlayingClient(client))
364 return client->GetPlayingRecording(recording);
368 bool CPVRClients::HasTimerSupport(int iClientId)
370 CSingleLock lock(m_critSection);
372 return IsConnectedClient(iClientId) && m_clientMap[iClientId]->SupportsTimers();
375 PVR_ERROR CPVRClients::GetTimers(CPVRTimers *timers)
377 PVR_ERROR error(PVR_ERROR_NO_ERROR);
378 PVR_CLIENTMAP clients;
379 GetConnectedClients(clients);
381 /* get the timer list from each client */
382 for (PVR_CLIENTMAP_ITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
384 PVR_ERROR currentError = (*itrClients).second->GetTimers(timers);
385 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
386 currentError != PVR_ERROR_NO_ERROR)
388 CLog::Log(LOGERROR, "PVR - %s - cannot get timers from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
389 error = currentError;
396 PVR_ERROR CPVRClients::AddTimer(const CPVRTimerInfoTag &timer)
398 PVR_ERROR error(PVR_ERROR_UNKNOWN);
401 if (GetConnectedClient(timer.m_iClientId, client))
402 error = client->AddTimer(timer);
404 if (error != PVR_ERROR_NO_ERROR)
405 CLog::Log(LOGERROR, "PVR - %s - cannot add timer to client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
410 PVR_ERROR CPVRClients::UpdateTimer(const CPVRTimerInfoTag &timer)
412 PVR_ERROR error(PVR_ERROR_UNKNOWN);
415 if (GetConnectedClient(timer.m_iClientId, client))
416 error = client->UpdateTimer(timer);
418 if (error != PVR_ERROR_NO_ERROR)
419 CLog::Log(LOGERROR, "PVR - %s - cannot update timer on client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
424 PVR_ERROR CPVRClients::DeleteTimer(const CPVRTimerInfoTag &timer, bool bForce)
426 PVR_ERROR error(PVR_ERROR_UNKNOWN);
429 if (GetConnectedClient(timer.m_iClientId, client))
430 error = client->DeleteTimer(timer, bForce);
435 PVR_ERROR CPVRClients::RenameTimer(const CPVRTimerInfoTag &timer, const CStdString &strNewName)
437 PVR_ERROR error(PVR_ERROR_UNKNOWN);
440 if (GetConnectedClient(timer.m_iClientId, client))
441 error = client->RenameTimer(timer, strNewName);
443 if (error != PVR_ERROR_NO_ERROR)
444 CLog::Log(LOGERROR, "PVR - %s - cannot rename timer on client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
449 PVR_ERROR CPVRClients::GetRecordings(CPVRRecordings *recordings)
451 PVR_ERROR error(PVR_ERROR_NO_ERROR);
452 PVR_CLIENTMAP clients;
453 GetConnectedClients(clients);
455 for (PVR_CLIENTMAP_ITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
457 PVR_ERROR currentError = (*itrClients).second->GetRecordings(recordings);
458 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
459 currentError != PVR_ERROR_NO_ERROR)
461 CLog::Log(LOGERROR, "PVR - %s - cannot get recordings from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
462 error = currentError;
469 PVR_ERROR CPVRClients::RenameRecording(const CPVRRecording &recording)
471 PVR_ERROR error(PVR_ERROR_UNKNOWN);
474 if (GetConnectedClient(recording.m_iClientId, client))
475 error = client->RenameRecording(recording);
477 if (error != PVR_ERROR_NO_ERROR)
478 CLog::Log(LOGERROR, "PVR - %s - cannot rename recording on client '%d': %s",__FUNCTION__, recording.m_iClientId, CPVRClient::ToString(error));
483 PVR_ERROR CPVRClients::DeleteRecording(const CPVRRecording &recording)
485 PVR_ERROR error(PVR_ERROR_UNKNOWN);
488 if (GetConnectedClient(recording.m_iClientId, client))
489 error = client->DeleteRecording(recording);
491 if (error != PVR_ERROR_NO_ERROR)
492 CLog::Log(LOGERROR, "PVR - %s - cannot delete recording from client '%d': %s",__FUNCTION__, recording.m_iClientId, CPVRClient::ToString(error));
497 bool CPVRClients::SetRecordingLastPlayedPosition(const CPVRRecording &recording, int lastplayedposition, PVR_ERROR *error)
499 *error = PVR_ERROR_UNKNOWN;
501 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
502 *error = client->SetRecordingLastPlayedPosition(recording, lastplayedposition);
504 CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
506 return *error == PVR_ERROR_NO_ERROR;
509 int CPVRClients::GetRecordingLastPlayedPosition(const CPVRRecording &recording)
514 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
515 rc = client->GetRecordingLastPlayedPosition(recording);
517 CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
522 bool CPVRClients::SetRecordingPlayCount(const CPVRRecording &recording, int count, PVR_ERROR *error)
524 *error = PVR_ERROR_UNKNOWN;
526 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingPlayCount())
527 *error = client->SetRecordingPlayCount(recording, count);
529 CLog::Log(LOGERROR, "PVR - %s - client %d does not support setting recording's play count",__FUNCTION__, recording.m_iClientId);
531 return *error == PVR_ERROR_NO_ERROR;
534 std::vector<PVR_EDL_ENTRY> CPVRClients::GetRecordingEdl(const CPVRRecording &recording)
537 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingEdl())
538 return client->GetRecordingEdl(recording);
540 CLog::Log(LOGERROR, "PVR - %s - client %d does not support getting Edl", __FUNCTION__, recording.m_iClientId);
542 return std::vector<PVR_EDL_ENTRY>();
545 bool CPVRClients::IsRecordingOnPlayingChannel(void) const
547 CPVRChannelPtr currentChannel;
548 return GetPlayingChannel(currentChannel) &&
549 currentChannel->IsRecording();
552 bool CPVRClients::CanRecordInstantly(void)
554 CPVRChannelPtr currentChannel;
555 return GetPlayingChannel(currentChannel) &&
556 currentChannel->CanRecord();
559 bool CPVRClients::CanPauseStream(void) const
563 if (GetPlayingClient(client))
565 return m_bIsPlayingRecording || client->CanPauseStream();
571 bool CPVRClients::CanSeekStream(void) const
575 if (GetPlayingClient(client))
577 return m_bIsPlayingRecording || client->CanSeekStream();
583 PVR_ERROR CPVRClients::GetEPGForChannel(const CPVRChannel &channel, CEpg *epg, time_t start, time_t end)
585 PVR_ERROR error(PVR_ERROR_UNKNOWN);
587 if (GetConnectedClient(channel.ClientID(), client))
588 error = client->GetEPGForChannel(channel, epg, start, end);
590 if (error != PVR_ERROR_NO_ERROR)
591 CLog::Log(LOGERROR, "PVR - %s - cannot get EPG for channel '%s' from client '%d': %s",__FUNCTION__, channel.ChannelName().c_str(), channel.ClientID(), CPVRClient::ToString(error));
596 PVR_ERROR CPVRClients::GetChannels(CPVRChannelGroupInternal *group)
598 PVR_ERROR error(PVR_ERROR_NO_ERROR);
599 PVR_CLIENTMAP clients;
600 GetConnectedClients(clients);
602 /* get the channel list from each client */
603 for (PVR_CLIENTMAP_ITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
605 PVR_ERROR currentError = (*itrClients).second->GetChannels(*group, group->IsRadio());
606 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
607 currentError != PVR_ERROR_NO_ERROR)
609 error = currentError;
610 CLog::Log(LOGERROR, "PVR - %s - cannot get channels from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
617 PVR_ERROR CPVRClients::GetChannelGroups(CPVRChannelGroups *groups)
619 PVR_ERROR error(PVR_ERROR_NO_ERROR);
620 PVR_CLIENTMAP clients;
621 GetConnectedClients(clients);
623 for (PVR_CLIENTMAP_ITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
625 PVR_ERROR currentError = (*itrClients).second->GetChannelGroups(groups);
626 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
627 currentError != PVR_ERROR_NO_ERROR)
629 error = currentError;
630 CLog::Log(LOGERROR, "PVR - %s - cannot get groups from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
637 PVR_ERROR CPVRClients::GetChannelGroupMembers(CPVRChannelGroup *group)
639 PVR_ERROR error(PVR_ERROR_NO_ERROR);
640 PVR_CLIENTMAP clients;
641 GetConnectedClients(clients);
643 /* get the member list from each client */
644 for (PVR_CLIENTMAP_ITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
646 PVR_ERROR currentError = (*itrClients).second->GetChannelGroupMembers(group);
647 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
648 currentError != PVR_ERROR_NO_ERROR)
650 error = currentError;
651 CLog::Log(LOGERROR, "PVR - %s - cannot get group members from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
658 bool CPVRClients::HasMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat)
661 iClientID = GetPlayingClientID();
664 return (GetConnectedClient(iClientID, client) &&
665 client->HaveMenuHooks(cat));
668 bool CPVRClients::GetMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, PVR_MENUHOOKS *hooks)
673 iClientID = GetPlayingClientID();
676 if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
678 *hooks = *(client->GetMenuHooks());
685 void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CFileItem *item)
687 PVR_MENUHOOKS *hooks = NULL;
690 if (iClientID < 0 && cat == PVR_MENUHOOK_SETTING)
692 PVR_CLIENTMAP clients;
693 GetConnectedClients(clients);
695 if (clients.size() == 1)
697 iClientID = clients.begin()->first;
699 else if (clients.size() > 1)
701 // have user select client
702 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
704 pDialog->SetHeading(19196);
706 PVR_CLIENTMAP_ITR itrClients;
707 for (itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
709 pDialog->Add(itrClients->second->GetBackendName());
713 int selection = pDialog->GetSelectedLabel();
716 itrClients = clients.begin();
717 for (int i = 0; i < selection; i++)
719 iClientID = itrClients->first;
725 iClientID = GetPlayingClientID();
728 if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
730 hooks = client->GetMenuHooks();
731 std::vector<int> hookIDs;
733 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
735 pDialog->SetHeading(19196);
736 for (unsigned int i = 0; i < hooks->size(); i++)
737 if (hooks->at(i).category == cat || hooks->at(i).category == PVR_MENUHOOK_ALL)
739 pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId));
740 hookIDs.push_back(i);
744 int selection = pDialog->GetSelectedLabel();
746 client->CallMenuHook(hooks->at(hookIDs.at(selection)), item);
750 bool CPVRClients::IsRunningChannelScan(void) const
752 CSingleLock lock(m_critSection);
753 return m_bChannelScanRunning;
756 vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelScan(void) const
758 vector<PVR_CLIENT> possibleScanClients;
759 CSingleLock lock(m_critSection);
761 /* get clients that support channel scanning */
762 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
764 if (itr->second->ReadyToUse() && itr->second->SupportsChannelScan())
765 possibleScanClients.push_back(itr->second);
768 return possibleScanClients;
771 void CPVRClients::StartChannelScan(void)
773 PVR_CLIENT scanClient;
774 CSingleLock lock(m_critSection);
775 vector<PVR_CLIENT> possibleScanClients = GetClientsSupportingChannelScan();
776 m_bChannelScanRunning = true;
778 /* multiple clients found */
779 if (possibleScanClients.size() > 1)
781 CGUIDialogSelect* pDialog= (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
784 pDialog->SetHeading(19119);
786 for (unsigned int i = 0; i < possibleScanClients.size(); i++)
787 pDialog->Add(possibleScanClients[i]->GetFriendlyName());
791 int selection = pDialog->GetSelectedLabel();
793 scanClient = possibleScanClients[selection];
795 /* one client found */
796 else if (possibleScanClients.size() == 1)
798 scanClient = possibleScanClients[0];
800 /* no clients found */
801 else if (!scanClient)
803 CGUIDialogOK::ShowAndGetInput(19033,0,19192,0);
807 /* start the channel scan */
808 CLog::Log(LOGNOTICE,"PVR - %s - starting to scan for channels on client %s",
809 __FUNCTION__, scanClient->GetFriendlyName().c_str());
810 long perfCnt = XbmcThreads::SystemClockMillis();
812 /* stop the supervisor thread */
813 g_PVRManager.StopUpdateThreads();
816 if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR)
817 /* an error occured */
818 CGUIDialogOK::ShowAndGetInput(19111,0,19193,0);
820 /* restart the supervisor thread */
821 g_PVRManager.StartUpdateThreads();
823 CLog::Log(LOGNOTICE, "PVRManager - %s - channel scan finished after %li.%li seconds",
824 __FUNCTION__, (XbmcThreads::SystemClockMillis()-perfCnt)/1000, (XbmcThreads::SystemClockMillis()-perfCnt)%1000);
825 m_bChannelScanRunning = false;
828 bool CPVRClients::IsKnownClient(const AddonPtr client) const
830 // database IDs start at 1
831 return GetClientId(client) > 0;
834 int CPVRClients::RegisterClient(AddonPtr client)
837 if (!client->Enabled())
840 CLog::Log(LOGDEBUG, "%s - registering add-on '%s'", __FUNCTION__, client->Name().c_str());
842 CPVRDatabase *database = GetPVRDatabase();
846 // check whether we already know this client
847 iClientId = database->GetClientId(client->ID());
849 // try to register the new client in the db
850 if (iClientId < 0 && (iClientId = database->Persist(client)) < 0)
852 CLog::Log(LOGERROR, "PVR - %s - can't add client '%s' to the database", __FUNCTION__, client->Name().c_str());
857 // load and initialise the client libraries
859 CSingleLock lock(m_critSection);
860 PVR_CLIENTMAP_ITR existingClient = m_clientMap.find(iClientId);
861 if (existingClient != m_clientMap.end())
863 // return existing client
864 addon = existingClient->second;
868 // create a new client instance
869 addon = boost::dynamic_pointer_cast<CPVRClient>(client);
870 m_clientMap.insert(std::make_pair(iClientId, addon));
875 CLog::Log(LOGERROR, "PVR - %s - can't register add-on '%s'", __FUNCTION__, client->Name().c_str());
880 bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */)
883 ADDON::VECADDONS map;
884 ADDON::VECADDONS disableAddons;
886 CSingleLock lock(m_critSection);
893 for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++)
895 const AddonPtr clientAddon = map.at(iClientPtr);
896 bool bEnabled = clientAddon->Enabled() &&
897 !CAddonMgr::Get().IsAddonDisabled(clientAddon->ID());
899 if (!bEnabled && IsKnownClient(clientAddon))
901 CSingleLock lock(m_critSection);
902 /* stop the client and remove it from the db */
903 StopClient(clientAddon, false);
904 ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), clientAddon);
905 if (addonPtr != m_addons.end())
906 m_addons.erase(addonPtr);
909 else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(clientAddon) || !IsConnectedClient(clientAddon)))
911 bool bDisabled(false);
913 // register the add-on in the pvr db, and create the CPVRClient instance
914 int iClientId = RegisterClient(clientAddon);
917 // failed to register or create the add-on, disable it
918 CLog::Log(LOGWARNING, "%s - failed to register add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
919 disableAddons.push_back(clientAddon);
924 ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
927 CSingleLock lock(m_critSection);
928 if (!GetClient(iClientId, addon))
930 CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
931 disableAddons.push_back(clientAddon);
936 // throttle connection attempts, no more than 1 attempt per 5 seconds
937 if (!bDisabled && addon->Enabled())
940 CDateTime::GetCurrentDateTime().GetAsTime(now);
941 std::map<int, time_t>::iterator it = m_connectionAttempts.find(iClientId);
942 if (it != m_connectionAttempts.end() && now < it->second)
944 m_connectionAttempts[iClientId] = now + 5;
947 // re-check the enabled status. newly installed clients get disabled when they're added to the db
948 if (!bDisabled && addon->Enabled() && (status = addon->Create(iClientId)) != ADDON_STATUS_OK)
950 CLog::Log(LOGWARNING, "%s - failed to create add-on %s, status = %d", __FUNCTION__, clientAddon->Name().c_str(), status);
951 if (!addon.get() || !addon->DllLoaded() || status == ADDON_STATUS_PERMANENT_FAILURE)
953 // failed to load the dll of this add-on, disable it
954 CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
955 disableAddons.push_back(clientAddon);
961 if (bDisabled && (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting))
962 CGUIDialogOK::ShowAndGetInput(24070, 24071, 16029, 0);
966 // disable add-ons that failed to initialise
967 if (disableAddons.size() > 0)
969 CSingleLock lock(m_critSection);
970 for (ADDON::VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); it++)
972 // disable in the add-on db
973 CAddonMgr::Get().DisableAddon((*it)->ID(), true);
975 // remove from the pvr add-on list
976 ADDON::VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), *it);
977 if (addonPtr != m_addons.end())
978 m_addons.erase(addonPtr);
985 void CPVRClients::Process(void)
987 bool bCheckedEnabledClientsOnStartup(false);
989 CAddonMgr::Get().RegisterAddonMgrCallback(ADDON_PVRDLL, this);
990 CAddonMgr::Get().RegisterObserver(this);
994 while (!g_application.m_bStop && !m_bStop)
996 UpdateAndInitialiseClients();
998 if (!bCheckedEnabledClientsOnStartup)
1000 bCheckedEnabledClientsOnStartup = true;
1001 if (!HasEnabledClients() && !m_bNoAddonWarningDisplayed)
1002 ShowDialogNoClientsEnabled();
1006 if (GetPlayingClient(client))
1007 client->UpdateCharInfoSignalStatus();
1012 void CPVRClients::ShowDialogNoClientsEnabled(void)
1014 if (g_PVRManager.GetState() != ManagerStateStarted && g_PVRManager.GetState() != ManagerStateStarting)
1017 CGUIDialogOK::ShowAndGetInput(19240, 19241, 19242, 19243);
1019 vector<CStdString> params;
1020 params.push_back("addons://disabled/xbmc.pvrclient");
1021 params.push_back("return");
1022 g_windowManager.ActivateWindow(WINDOW_ADDON_BROWSER, params);
1025 void CPVRClients::SaveCurrentChannelSettings(void)
1027 CPVRChannelPtr channel;
1029 CSingleLock lock(m_critSection);
1030 if (!GetPlayingChannel(channel) || !m_bIsValidChannelSettings)
1034 CPVRDatabase *database = GetPVRDatabase();
1038 if (CMediaSettings::Get().GetCurrentVideoSettings() != CMediaSettings::Get().GetDefaultVideoSettings())
1040 CLog::Log(LOGDEBUG, "PVR - %s - persisting custom channel settings for channel '%s'",
1041 __FUNCTION__, channel->ChannelName().c_str());
1042 database->PersistChannelSettings(*channel, CMediaSettings::Get().GetCurrentVideoSettings());
1046 CLog::Log(LOGDEBUG, "PVR - %s - no custom channel settings for channel '%s'",
1047 __FUNCTION__, channel->ChannelName().c_str());
1048 database->DeleteChannelSettings(*channel);
1052 void CPVRClients::LoadCurrentChannelSettings(void)
1054 CPVRChannelPtr channel;
1056 CSingleLock lock(m_critSection);
1057 if (!GetPlayingChannel(channel))
1061 CPVRDatabase *database = GetPVRDatabase();
1065 if (g_application.m_pPlayer->HasPlayer())
1067 /* set the default settings first */
1068 CVideoSettings loadedChannelSettings = CMediaSettings::Get().GetDefaultVideoSettings();
1070 /* try to load the settings from the database */
1071 database->GetChannelSettings(*channel, loadedChannelSettings);
1073 CMediaSettings::Get().GetCurrentVideoSettings() = CMediaSettings::Get().GetDefaultVideoSettings();
1074 CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness = loadedChannelSettings.m_Brightness;
1075 CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast = loadedChannelSettings.m_Contrast;
1076 CMediaSettings::Get().GetCurrentVideoSettings().m_Gamma = loadedChannelSettings.m_Gamma;
1077 CMediaSettings::Get().GetCurrentVideoSettings().m_Crop = loadedChannelSettings.m_Crop;
1078 CMediaSettings::Get().GetCurrentVideoSettings().m_CropLeft = loadedChannelSettings.m_CropLeft;
1079 CMediaSettings::Get().GetCurrentVideoSettings().m_CropRight = loadedChannelSettings.m_CropRight;
1080 CMediaSettings::Get().GetCurrentVideoSettings().m_CropTop = loadedChannelSettings.m_CropTop;
1081 CMediaSettings::Get().GetCurrentVideoSettings().m_CropBottom = loadedChannelSettings.m_CropBottom;
1082 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomPixelRatio = loadedChannelSettings.m_CustomPixelRatio;
1083 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomZoomAmount = loadedChannelSettings.m_CustomZoomAmount;
1084 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomVerticalShift = loadedChannelSettings.m_CustomVerticalShift;
1085 CMediaSettings::Get().GetCurrentVideoSettings().m_NoiseReduction = loadedChannelSettings.m_NoiseReduction;
1086 CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness = loadedChannelSettings.m_Sharpness;
1087 CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod = loadedChannelSettings.m_InterlaceMethod;
1088 CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers = loadedChannelSettings.m_OutputToAllSpeakers;
1089 CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay = loadedChannelSettings.m_AudioDelay;
1090 CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream = loadedChannelSettings.m_AudioStream;
1091 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn = loadedChannelSettings.m_SubtitleOn;
1092 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay = loadedChannelSettings.m_SubtitleDelay;
1093 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomNonLinStretch = loadedChannelSettings.m_CustomNonLinStretch;
1094 CMediaSettings::Get().GetCurrentVideoSettings().m_ScalingMethod = loadedChannelSettings.m_ScalingMethod;
1095 CMediaSettings::Get().GetCurrentVideoSettings().m_PostProcess = loadedChannelSettings.m_PostProcess;
1096 CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode = loadedChannelSettings.m_DeinterlaceMode;
1098 /* only change the view mode if it's different */
1099 if (CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode != loadedChannelSettings.m_ViewMode)
1101 CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode = loadedChannelSettings.m_ViewMode;
1103 g_renderManager.SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode);
1104 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomZoomAmount = CDisplaySettings::Get().GetZoomAmount();
1105 CMediaSettings::Get().GetCurrentVideoSettings().m_CustomPixelRatio = CDisplaySettings::Get().GetPixelRatio();
1108 /* only change the subtitle stream, if it's different */
1109 if (CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream != loadedChannelSettings.m_SubtitleStream)
1111 CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream = loadedChannelSettings.m_SubtitleStream;
1113 g_application.m_pPlayer->SetSubtitle(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleStream);
1116 /* only change the audio stream if it's different */
1117 if (g_application.m_pPlayer->GetAudioStream() != CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream &&
1118 CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream >= 0)
1119 g_application.m_pPlayer->SetAudioStream(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioStream);
1121 g_application.m_pPlayer->SetAVDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay);
1122 g_application.m_pPlayer->SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100));
1123 g_application.m_pPlayer->SetSubtitleVisible(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleOn);
1124 g_application.m_pPlayer->SetSubTitleDelay(CMediaSettings::Get().GetCurrentVideoSettings().m_SubtitleDelay);
1126 /* settings can be saved on next channel switch */
1127 m_bIsValidChannelSettings = true;
1131 bool CPVRClients::UpdateAddons(void)
1133 ADDON::VECADDONS addons;
1134 bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true));
1138 CSingleLock lock(m_critSection);
1142 // handle "new" addons which aren't yet in the db - these have to be added first
1143 for (unsigned iClientPtr = 0; iClientPtr < m_addons.size(); iClientPtr++)
1145 const AddonPtr clientAddon = m_addons.at(iClientPtr);
1147 if (!m_addonDb.HasAddon(clientAddon->ID()))
1149 m_addonDb.AddAddon(clientAddon, -1);
1153 if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed &&
1154 !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) &&
1155 (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting))
1157 // No PVR add-ons could be found
1158 // You need a tuner, backend software, and an add-on for the backend to be able to use PVR.
1159 // Please visit xbmc.org/pvr to learn more.
1160 m_bNoAddonWarningDisplayed = true;
1161 CSettings::Get().SetBool("pvrmanager.enabled", false);
1162 CGUIDialogOK::ShowAndGetInput(19271, 19272, 19273, 19274);
1163 CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_MYPVR, 0);
1164 g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_MYPVR);
1170 void CPVRClients::Notify(const Observable &obs, const ObservableMessage msg)
1172 if (msg == ObservableMessageAddons)
1176 bool CPVRClients::GetClient(const CStdString &strId, ADDON::AddonPtr &addon) const
1178 CSingleLock lock(m_critSection);
1179 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
1181 if (itr->second->ID() == strId)
1183 addon = itr->second;
1190 bool CPVRClients::SupportsChannelGroups(int iClientId) const
1193 return GetConnectedClient(iClientId, client) && client->SupportsChannelGroups();
1196 bool CPVRClients::SupportsChannelScan(int iClientId) const
1199 return GetConnectedClient(iClientId, client) && client->SupportsChannelScan();
1202 bool CPVRClients::SupportsEPG(int iClientId) const
1205 return GetConnectedClient(iClientId, client) && client->SupportsEPG();
1208 bool CPVRClients::SupportsLastPlayedPosition(int iClientId) const
1211 return GetConnectedClient(iClientId, client) && client->SupportsLastPlayedPosition();
1214 bool CPVRClients::SupportsRadio(int iClientId) const
1217 return GetConnectedClient(iClientId, client) && client->SupportsRadio();
1220 bool CPVRClients::SupportsRecordings(int iClientId) const
1223 return GetConnectedClient(iClientId, client) && client->SupportsRecordings();
1226 bool CPVRClients::SupportsRecordingFolders(int iClientId) const
1229 return GetConnectedClient(iClientId, client) && client->SupportsRecordingFolders();
1232 bool CPVRClients::SupportsRecordingPlayCount(int iClientId) const
1235 return GetConnectedClient(iClientId, client) && client->SupportsRecordingPlayCount();
1238 bool CPVRClients::SupportsRecordingEdl(int iClientId) const
1241 return GetConnectedClient(iClientId, client) && client->SupportsRecordingEdl();
1244 bool CPVRClients::SupportsTimers(int iClientId) const
1247 return GetConnectedClient(iClientId, client) && client->SupportsTimers();
1250 bool CPVRClients::SupportsTV(int iClientId) const
1253 return GetConnectedClient(iClientId, client) && client->SupportsTV();
1256 bool CPVRClients::HandlesDemuxing(int iClientId) const
1259 return GetConnectedClient(iClientId, client) && client->HandlesDemuxing();
1262 bool CPVRClients::HandlesInputStream(int iClientId) const
1265 return GetConnectedClient(iClientId, client) && client->HandlesInputStream();
1268 bool CPVRClients::GetPlayingClient(PVR_CLIENT &client) const
1270 return GetConnectedClient(GetPlayingClientID(), client);
1273 bool CPVRClients::OpenStream(const CPVRChannel &tag, bool bIsSwitchingChannel)
1275 bool bReturn(false);
1278 /* try to open the stream on the client */
1280 if (GetConnectedClient(tag.ClientID(), client) &&
1281 client->OpenStream(tag, bIsSwitchingChannel))
1283 CSingleLock lock(m_critSection);
1284 m_playingClientId = tag.ClientID();
1285 m_bIsPlayingLiveTV = true;
1287 if (tag.ClientID() == PVR_VIRTUAL_CLIENT_ID)
1288 m_strPlayingClientName = g_localizeStrings.Get(19209);
1289 else if (!tag.IsVirtual() && client.get())
1290 m_strPlayingClientName = client->GetFriendlyName();
1292 m_strPlayingClientName = g_localizeStrings.Get(13205);
1300 bool CPVRClients::OpenStream(const CPVRRecording &tag)
1302 bool bReturn(false);
1305 /* try to open the recording stream on the client */
1307 if (GetConnectedClient(tag.m_iClientId, client) &&
1308 client->OpenStream(tag))
1310 CSingleLock lock(m_critSection);
1311 m_playingClientId = tag.m_iClientId;
1312 m_bIsPlayingRecording = true;
1313 m_strPlayingClientName = client->GetFriendlyName();
1320 void CPVRClients::CloseStream(void)
1322 PVR_CLIENT playingClient;
1323 if (GetPlayingClient(playingClient))
1324 playingClient->CloseStream();
1326 CSingleLock lock(m_critSection);
1327 m_bIsPlayingLiveTV = false;
1328 m_bIsPlayingRecording = false;
1329 m_playingClientId = PVR_INVALID_CLIENT_ID;
1330 m_strPlayingClientName = "";
1333 int CPVRClients::ReadStream(void* lpBuf, int64_t uiBufSize)
1336 if (GetPlayingClient(client))
1337 return client->ReadStream(lpBuf, uiBufSize);
1341 int64_t CPVRClients::GetStreamLength(void)
1344 if (GetPlayingClient(client))
1345 return client->GetStreamLength();
1349 int64_t CPVRClients::SeekStream(int64_t iFilePosition, int iWhence/* = SEEK_SET*/)
1352 if (GetPlayingClient(client))
1353 return client->SeekStream(iFilePosition, iWhence);
1357 int64_t CPVRClients::GetStreamPosition(void)
1360 if (GetPlayingClient(client))
1361 return client->GetStreamPosition();
1365 void CPVRClients::PauseStream(bool bPaused)
1368 if (GetPlayingClient(client))
1369 client->PauseStream(bPaused);
1372 CStdString CPVRClients::GetCurrentInputFormat(void) const
1374 CStdString strReturn;
1375 CPVRChannelPtr currentChannel;
1376 if (GetPlayingChannel(currentChannel))
1377 strReturn = currentChannel->InputFormat();
1382 PVR_STREAM_PROPERTIES CPVRClients::GetCurrentStreamProperties(void)
1384 PVR_STREAM_PROPERTIES props;
1387 memset(&props, 0, sizeof(props));
1388 if (GetPlayingClient(client))
1389 client->GetStreamProperties(&props);
1394 bool CPVRClients::IsPlaying(void) const
1396 CSingleLock lock(m_critSection);
1397 return m_bIsPlayingRecording || m_bIsPlayingLiveTV;
1400 bool CPVRClients::IsPlayingRadio(void) const
1403 if (GetPlayingClient(client))
1404 return client->IsPlayingLiveRadio();
1408 bool CPVRClients::IsPlayingTV(void) const
1411 if (GetPlayingClient(client))
1412 return client->IsPlayingLiveTV();
1416 bool CPVRClients::IsPlayingRecording(void) const
1418 CSingleLock lock(m_critSection);
1419 return m_bIsPlayingRecording;
1422 bool CPVRClients::IsReadingLiveStream(void) const
1424 CSingleLock lock(m_critSection);
1425 return m_bIsPlayingLiveTV;
1428 bool CPVRClients::IsEncrypted(void) const
1431 if (GetPlayingClient(client))
1432 return client->IsPlayingEncryptedChannel();