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().empty() || !currentChannel->StreamURL().empty())
315 if (channel.StreamURL().empty())
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 /* store the current settings so we can compare if anything has changed */
1068 CVideoSettings previousSettings = CMediaSettings::Get().GetCurrentVideoSettings();
1070 /* load the persisted channel settings and set them as current */
1071 CVideoSettings loadedChannelSettings = CMediaSettings::Get().GetDefaultVideoSettings();
1072 database->GetChannelSettings(*channel, loadedChannelSettings);
1073 CMediaSettings::Get().GetCurrentVideoSettings() = loadedChannelSettings;
1075 /* update the view mode if it set to custom or differs from the previous mode */
1076 if (previousSettings.m_ViewMode != loadedChannelSettings.m_ViewMode || loadedChannelSettings.m_ViewMode == ViewModeCustom)
1077 g_renderManager.SetViewMode(loadedChannelSettings.m_ViewMode);
1079 /* only change the subtitle stream, if it's different */
1080 if (previousSettings.m_SubtitleStream != loadedChannelSettings.m_SubtitleStream)
1081 g_application.m_pPlayer->SetSubtitle(loadedChannelSettings.m_SubtitleStream);
1083 /* only change the audio stream if it's different */
1084 if (g_application.m_pPlayer->GetAudioStream() != loadedChannelSettings.m_AudioStream && loadedChannelSettings.m_AudioStream >= 0)
1085 g_application.m_pPlayer->SetAudioStream(loadedChannelSettings.m_AudioStream);
1087 g_application.m_pPlayer->SetAVDelay(loadedChannelSettings.m_AudioDelay);
1088 g_application.m_pPlayer->SetDynamicRangeCompression((long)(loadedChannelSettings.m_VolumeAmplification * 100));
1089 g_application.m_pPlayer->SetSubtitleVisible(loadedChannelSettings.m_SubtitleOn);
1090 g_application.m_pPlayer->SetSubTitleDelay(loadedChannelSettings.m_SubtitleDelay);
1092 /* settings can be saved on next channel switch */
1093 m_bIsValidChannelSettings = true;
1097 bool CPVRClients::UpdateAddons(void)
1099 ADDON::VECADDONS addons;
1100 bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true));
1104 CSingleLock lock(m_critSection);
1108 // handle "new" addons which aren't yet in the db - these have to be added first
1109 for (unsigned iClientPtr = 0; iClientPtr < m_addons.size(); iClientPtr++)
1111 const AddonPtr clientAddon = m_addons.at(iClientPtr);
1113 if (!m_addonDb.HasAddon(clientAddon->ID()))
1115 m_addonDb.AddAddon(clientAddon, -1);
1119 if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed &&
1120 !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) &&
1121 (g_PVRManager.GetState() == ManagerStateStarted || g_PVRManager.GetState() == ManagerStateStarting))
1123 // No PVR add-ons could be found
1124 // You need a tuner, backend software, and an add-on for the backend to be able to use PVR.
1125 // Please visit xbmc.org/pvr to learn more.
1126 m_bNoAddonWarningDisplayed = true;
1127 CSettings::Get().SetBool("pvrmanager.enabled", false);
1128 CGUIDialogOK::ShowAndGetInput(19271, 19272, 19273, 19274);
1129 CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_MYPVR, 0);
1130 g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_MYPVR);
1136 void CPVRClients::Notify(const Observable &obs, const ObservableMessage msg)
1138 if (msg == ObservableMessageAddons)
1142 bool CPVRClients::GetClient(const CStdString &strId, ADDON::AddonPtr &addon) const
1144 CSingleLock lock(m_critSection);
1145 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
1147 if (itr->second->ID() == strId)
1149 addon = itr->second;
1156 bool CPVRClients::SupportsChannelGroups(int iClientId) const
1159 return GetConnectedClient(iClientId, client) && client->SupportsChannelGroups();
1162 bool CPVRClients::SupportsChannelScan(int iClientId) const
1165 return GetConnectedClient(iClientId, client) && client->SupportsChannelScan();
1168 bool CPVRClients::SupportsEPG(int iClientId) const
1171 return GetConnectedClient(iClientId, client) && client->SupportsEPG();
1174 bool CPVRClients::SupportsLastPlayedPosition(int iClientId) const
1177 return GetConnectedClient(iClientId, client) && client->SupportsLastPlayedPosition();
1180 bool CPVRClients::SupportsRadio(int iClientId) const
1183 return GetConnectedClient(iClientId, client) && client->SupportsRadio();
1186 bool CPVRClients::SupportsRecordings(int iClientId) const
1189 return GetConnectedClient(iClientId, client) && client->SupportsRecordings();
1192 bool CPVRClients::SupportsRecordingFolders(int iClientId) const
1195 return GetConnectedClient(iClientId, client) && client->SupportsRecordingFolders();
1198 bool CPVRClients::SupportsRecordingPlayCount(int iClientId) const
1201 return GetConnectedClient(iClientId, client) && client->SupportsRecordingPlayCount();
1204 bool CPVRClients::SupportsRecordingEdl(int iClientId) const
1207 return GetConnectedClient(iClientId, client) && client->SupportsRecordingEdl();
1210 bool CPVRClients::SupportsTimers(int iClientId) const
1213 return GetConnectedClient(iClientId, client) && client->SupportsTimers();
1216 bool CPVRClients::SupportsTV(int iClientId) const
1219 return GetConnectedClient(iClientId, client) && client->SupportsTV();
1222 bool CPVRClients::HandlesDemuxing(int iClientId) const
1225 return GetConnectedClient(iClientId, client) && client->HandlesDemuxing();
1228 bool CPVRClients::HandlesInputStream(int iClientId) const
1231 return GetConnectedClient(iClientId, client) && client->HandlesInputStream();
1234 bool CPVRClients::GetPlayingClient(PVR_CLIENT &client) const
1236 return GetConnectedClient(GetPlayingClientID(), client);
1239 bool CPVRClients::OpenStream(const CPVRChannel &tag, bool bIsSwitchingChannel)
1241 bool bReturn(false);
1244 /* try to open the stream on the client */
1246 if (GetConnectedClient(tag.ClientID(), client) &&
1247 client->OpenStream(tag, bIsSwitchingChannel))
1249 CSingleLock lock(m_critSection);
1250 m_playingClientId = tag.ClientID();
1251 m_bIsPlayingLiveTV = true;
1253 if (tag.ClientID() == PVR_VIRTUAL_CLIENT_ID)
1254 m_strPlayingClientName = g_localizeStrings.Get(19209);
1255 else if (!tag.IsVirtual() && client.get())
1256 m_strPlayingClientName = client->GetFriendlyName();
1258 m_strPlayingClientName = g_localizeStrings.Get(13205);
1266 bool CPVRClients::OpenStream(const CPVRRecording &tag)
1268 bool bReturn(false);
1271 /* try to open the recording stream on the client */
1273 if (GetConnectedClient(tag.m_iClientId, client) &&
1274 client->OpenStream(tag))
1276 CSingleLock lock(m_critSection);
1277 m_playingClientId = tag.m_iClientId;
1278 m_bIsPlayingRecording = true;
1279 m_strPlayingClientName = client->GetFriendlyName();
1286 void CPVRClients::CloseStream(void)
1288 PVR_CLIENT playingClient;
1289 if (GetPlayingClient(playingClient))
1290 playingClient->CloseStream();
1292 CSingleLock lock(m_critSection);
1293 m_bIsPlayingLiveTV = false;
1294 m_bIsPlayingRecording = false;
1295 m_playingClientId = PVR_INVALID_CLIENT_ID;
1296 m_strPlayingClientName = "";
1299 int CPVRClients::ReadStream(void* lpBuf, int64_t uiBufSize)
1302 if (GetPlayingClient(client))
1303 return client->ReadStream(lpBuf, uiBufSize);
1307 int64_t CPVRClients::GetStreamLength(void)
1310 if (GetPlayingClient(client))
1311 return client->GetStreamLength();
1315 int64_t CPVRClients::SeekStream(int64_t iFilePosition, int iWhence/* = SEEK_SET*/)
1318 if (GetPlayingClient(client))
1319 return client->SeekStream(iFilePosition, iWhence);
1323 int64_t CPVRClients::GetStreamPosition(void)
1326 if (GetPlayingClient(client))
1327 return client->GetStreamPosition();
1331 void CPVRClients::PauseStream(bool bPaused)
1334 if (GetPlayingClient(client))
1335 client->PauseStream(bPaused);
1338 CStdString CPVRClients::GetCurrentInputFormat(void) const
1340 CStdString strReturn;
1341 CPVRChannelPtr currentChannel;
1342 if (GetPlayingChannel(currentChannel))
1343 strReturn = currentChannel->InputFormat();
1348 PVR_STREAM_PROPERTIES CPVRClients::GetCurrentStreamProperties(void)
1350 PVR_STREAM_PROPERTIES props;
1353 memset(&props, 0, sizeof(props));
1354 if (GetPlayingClient(client))
1355 client->GetStreamProperties(&props);
1360 bool CPVRClients::IsPlaying(void) const
1362 CSingleLock lock(m_critSection);
1363 return m_bIsPlayingRecording || m_bIsPlayingLiveTV;
1366 bool CPVRClients::IsPlayingRadio(void) const
1369 if (GetPlayingClient(client))
1370 return client->IsPlayingLiveRadio();
1374 bool CPVRClients::IsPlayingTV(void) const
1377 if (GetPlayingClient(client))
1378 return client->IsPlayingLiveTV();
1382 bool CPVRClients::IsPlayingRecording(void) const
1384 CSingleLock lock(m_critSection);
1385 return m_bIsPlayingRecording;
1388 bool CPVRClients::IsReadingLiveStream(void) const
1390 CSingleLock lock(m_critSection);
1391 return m_bIsPlayingLiveTV;
1394 bool CPVRClients::IsEncrypted(void) const
1397 if (GetPlayingClient(client))
1398 return client->IsPlayingEncryptedChannel();
1402 time_t CPVRClients::GetPlayingTime() const
1407 if (GetPlayingClient(client))
1409 time = client->GetPlayingTime();
1415 time_t CPVRClients::GetBufferTimeStart() const
1420 if (GetPlayingClient(client))
1422 time = client->GetBufferTimeStart();
1428 time_t CPVRClients::GetBufferTimeEnd() const
1433 if (GetPlayingClient(client))
1435 time = client->GetBufferTimeEnd();