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 CSingleLock lock(m_critSection);
102 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
103 if (itr->second->ID() == addon->ID())
104 return itr->second->ReadyToUse();
108 int CPVRClients::GetClientId(const AddonPtr client) const
110 CSingleLock lock(m_critSection);
112 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
113 if (itr->second->ID() == client->ID())
119 bool CPVRClients::GetClient(int iClientId, PVR_CLIENT &addon) const
122 if (iClientId <= PVR_INVALID_CLIENT_ID || iClientId == PVR_VIRTUAL_CLIENT_ID)
125 CSingleLock lock(m_critSection);
127 PVR_CLIENTMAP_CITR itr = m_clientMap.find(iClientId);
128 if (itr != m_clientMap.end())
137 bool CPVRClients::GetConnectedClient(int iClientId, PVR_CLIENT &addon) const
139 if (GetClient(iClientId, addon))
140 return addon->ReadyToUse();
144 bool CPVRClients::RequestRestart(AddonPtr addon, bool bDataChanged)
146 return StopClient(addon, true);
149 bool CPVRClients::RequestRemoval(AddonPtr addon)
151 return StopClient(addon, false);
154 void CPVRClients::Unload(void)
158 CSingleLock lock(m_critSection);
160 /* destroy all clients */
161 for (PVR_CLIENTMAP_ITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
162 itr->second->Destroy();
164 /* reset class properties */
165 m_bChannelScanRunning = false;
166 m_bIsPlayingLiveTV = false;
167 m_bIsPlayingRecording = false;
168 m_strPlayingClientName = "";
173 int CPVRClients::GetFirstConnectedClientID(void)
175 CSingleLock lock(m_critSection);
177 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
178 if (itr->second->ReadyToUse())
179 return itr->second->GetID();
184 int CPVRClients::EnabledClientAmount(void) const
187 CSingleLock lock(m_critSection);
189 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
190 if (itr->second->Enabled())
196 bool CPVRClients::HasEnabledClients(void) const
198 return EnabledClientAmount() > 0;
201 bool CPVRClients::StopClient(AddonPtr client, bool bRestart)
203 CSingleLock lock(m_critSection);
204 int iId = GetClientId(client);
205 PVR_CLIENT mappedClient;
206 if (GetClient(iId, mappedClient))
209 mappedClient->ReCreate();
211 mappedClient->Destroy();
219 int CPVRClients::ConnectedClientAmount(void) const
222 CSingleLock lock(m_critSection);
224 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
225 if (itr->second->ReadyToUse())
231 bool CPVRClients::HasConnectedClients(void) const
233 CSingleLock lock(m_critSection);
235 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
236 if (itr->second->ReadyToUse())
242 bool CPVRClients::GetClientName(int iClientId, CStdString &strName) const
246 if ((bReturn = GetConnectedClient(iClientId, client)) == true)
247 strName = client->GetFriendlyName();
252 int CPVRClients::GetConnectedClients(PVR_CLIENTMAP &clients) const
255 CSingleLock lock(m_critSection);
257 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
259 if (itr->second->ReadyToUse())
261 clients.insert(std::make_pair(itr->second->GetID(), itr->second));
269 int CPVRClients::GetPlayingClientID(void) const
271 CSingleLock lock(m_critSection);
273 if (m_bIsPlayingLiveTV || m_bIsPlayingRecording)
274 return m_playingClientId;
278 const CStdString CPVRClients::GetPlayingClientName(void) const
280 CSingleLock lock(m_critSection);
281 return m_strPlayingClientName;
284 CStdString CPVRClients::GetStreamURL(const CPVRChannel &tag)
286 CStdString strReturn;
288 if (GetConnectedClient(tag.ClientID(), client))
289 strReturn = client->GetLiveStreamURL(tag);
291 CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, tag.ClientID());
296 bool CPVRClients::SwitchChannel(const CPVRChannel &channel)
299 CSingleLock lock(m_critSection);
300 if (m_bIsSwitchingChannels)
302 CLog::Log(LOGDEBUG, "PVRClients - %s - can't switch to channel '%s'. waiting for the previous switch to complete", __FUNCTION__, channel.ChannelName().c_str());
305 m_bIsSwitchingChannels = true;
308 bool bSwitchSuccessful(false);
309 CPVRChannelPtr currentChannel;
310 if (// no channel is currently playing
311 !GetPlayingChannel(currentChannel) ||
313 currentChannel->ClientID() != channel.ClientID() ||
314 // stream URL should always be opened as a new file
315 !channel.StreamURL().empty() || !currentChannel->StreamURL().empty())
317 if (channel.StreamURL().empty())
320 bSwitchSuccessful = OpenStream(channel, true);
324 CFileItem m_currentFile(channel);
325 CApplicationMessenger::Get().PlayFile(m_currentFile, false);
326 bSwitchSuccessful = true;
330 else if (currentChannel.get() && *currentChannel == channel)
332 bSwitchSuccessful = true;
337 if (GetConnectedClient(channel.ClientID(), client))
338 bSwitchSuccessful = client->SwitchChannel(channel);
342 CSingleLock lock(m_critSection);
343 m_bIsSwitchingChannels = false;
344 if (bSwitchSuccessful)
345 m_bIsValidChannelSettings = false;
348 if (!bSwitchSuccessful)
349 CLog::Log(LOGERROR, "PVR - %s - cannot switch to channel '%s' on client '%d'",__FUNCTION__, channel.ChannelName().c_str(), channel.ClientID());
351 return bSwitchSuccessful;
354 bool CPVRClients::GetPlayingChannel(CPVRChannelPtr &channel) const
357 if (GetPlayingClient(client))
358 return client->GetPlayingChannel(channel);
362 bool CPVRClients::GetPlayingRecording(CPVRRecording &recording) const
365 if (GetPlayingClient(client))
366 return client->GetPlayingRecording(recording);
370 bool CPVRClients::HasTimerSupport(int iClientId)
373 if (GetConnectedClient(iClientId, client))
374 return client->SupportsTimers();
379 PVR_ERROR CPVRClients::GetTimers(CPVRTimers *timers)
381 PVR_ERROR error(PVR_ERROR_NO_ERROR);
382 PVR_CLIENTMAP clients;
383 GetConnectedClients(clients);
385 /* get the timer list from each client */
386 for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
388 PVR_ERROR currentError = (*itrClients).second->GetTimers(timers);
389 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
390 currentError != PVR_ERROR_NO_ERROR)
392 CLog::Log(LOGERROR, "PVR - %s - cannot get timers from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
393 error = currentError;
400 PVR_ERROR CPVRClients::AddTimer(const CPVRTimerInfoTag &timer)
402 PVR_ERROR error(PVR_ERROR_UNKNOWN);
405 if (GetConnectedClient(timer.m_iClientId, client))
406 error = client->AddTimer(timer);
408 if (error != PVR_ERROR_NO_ERROR)
409 CLog::Log(LOGERROR, "PVR - %s - cannot add timer to client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
414 PVR_ERROR CPVRClients::UpdateTimer(const CPVRTimerInfoTag &timer)
416 PVR_ERROR error(PVR_ERROR_UNKNOWN);
419 if (GetConnectedClient(timer.m_iClientId, client))
420 error = client->UpdateTimer(timer);
422 if (error != PVR_ERROR_NO_ERROR)
423 CLog::Log(LOGERROR, "PVR - %s - cannot update timer on client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
428 PVR_ERROR CPVRClients::DeleteTimer(const CPVRTimerInfoTag &timer, bool bForce)
430 PVR_ERROR error(PVR_ERROR_UNKNOWN);
433 if (GetConnectedClient(timer.m_iClientId, client))
434 error = client->DeleteTimer(timer, bForce);
439 PVR_ERROR CPVRClients::RenameTimer(const CPVRTimerInfoTag &timer, const CStdString &strNewName)
441 PVR_ERROR error(PVR_ERROR_UNKNOWN);
444 if (GetConnectedClient(timer.m_iClientId, client))
445 error = client->RenameTimer(timer, strNewName);
447 if (error != PVR_ERROR_NO_ERROR)
448 CLog::Log(LOGERROR, "PVR - %s - cannot rename timer on client '%d': %s",__FUNCTION__, timer.m_iClientId, CPVRClient::ToString(error));
453 PVR_ERROR CPVRClients::GetRecordings(CPVRRecordings *recordings)
455 PVR_ERROR error(PVR_ERROR_NO_ERROR);
456 PVR_CLIENTMAP clients;
457 GetConnectedClients(clients);
459 for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
461 PVR_ERROR currentError = (*itrClients).second->GetRecordings(recordings);
462 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
463 currentError != PVR_ERROR_NO_ERROR)
465 CLog::Log(LOGERROR, "PVR - %s - cannot get recordings from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
466 error = currentError;
473 PVR_ERROR CPVRClients::RenameRecording(const CPVRRecording &recording)
475 PVR_ERROR error(PVR_ERROR_UNKNOWN);
478 if (GetConnectedClient(recording.m_iClientId, client))
479 error = client->RenameRecording(recording);
481 if (error != PVR_ERROR_NO_ERROR)
482 CLog::Log(LOGERROR, "PVR - %s - cannot rename recording on client '%d': %s",__FUNCTION__, recording.m_iClientId, CPVRClient::ToString(error));
487 PVR_ERROR CPVRClients::DeleteRecording(const CPVRRecording &recording)
489 PVR_ERROR error(PVR_ERROR_UNKNOWN);
492 if (GetConnectedClient(recording.m_iClientId, client))
493 error = client->DeleteRecording(recording);
495 if (error != PVR_ERROR_NO_ERROR)
496 CLog::Log(LOGERROR, "PVR - %s - cannot delete recording from client '%d': %s",__FUNCTION__, recording.m_iClientId, CPVRClient::ToString(error));
501 bool CPVRClients::SetRecordingLastPlayedPosition(const CPVRRecording &recording, int lastplayedposition, PVR_ERROR *error)
503 *error = PVR_ERROR_UNKNOWN;
505 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
506 *error = client->SetRecordingLastPlayedPosition(recording, lastplayedposition);
508 CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
510 return *error == PVR_ERROR_NO_ERROR;
513 int CPVRClients::GetRecordingLastPlayedPosition(const CPVRRecording &recording)
518 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
519 rc = client->GetRecordingLastPlayedPosition(recording);
521 CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
526 bool CPVRClients::SetRecordingPlayCount(const CPVRRecording &recording, int count, PVR_ERROR *error)
528 *error = PVR_ERROR_UNKNOWN;
530 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingPlayCount())
531 *error = client->SetRecordingPlayCount(recording, count);
533 CLog::Log(LOGERROR, "PVR - %s - client %d does not support setting recording's play count",__FUNCTION__, recording.m_iClientId);
535 return *error == PVR_ERROR_NO_ERROR;
538 std::vector<PVR_EDL_ENTRY> CPVRClients::GetRecordingEdl(const CPVRRecording &recording)
541 if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingEdl())
542 return client->GetRecordingEdl(recording);
544 CLog::Log(LOGERROR, "PVR - %s - client %d does not support getting Edl", __FUNCTION__, recording.m_iClientId);
546 return std::vector<PVR_EDL_ENTRY>();
549 bool CPVRClients::IsRecordingOnPlayingChannel(void) const
551 CPVRChannelPtr currentChannel;
552 return GetPlayingChannel(currentChannel) &&
553 currentChannel->IsRecording();
556 bool CPVRClients::CanRecordInstantly(void)
558 CPVRChannelPtr currentChannel;
559 return GetPlayingChannel(currentChannel) &&
560 currentChannel->CanRecord();
563 bool CPVRClients::CanPauseStream(void) const
567 if (GetPlayingClient(client))
569 return m_bIsPlayingRecording || client->CanPauseStream();
575 bool CPVRClients::CanSeekStream(void) const
579 if (GetPlayingClient(client))
581 return m_bIsPlayingRecording || client->CanSeekStream();
587 PVR_ERROR CPVRClients::GetEPGForChannel(const CPVRChannel &channel, CEpg *epg, time_t start, time_t end)
589 PVR_ERROR error(PVR_ERROR_UNKNOWN);
591 if (GetConnectedClient(channel.ClientID(), client))
592 error = client->GetEPGForChannel(channel, epg, start, end);
594 if (error != PVR_ERROR_NO_ERROR)
595 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));
600 PVR_ERROR CPVRClients::GetChannels(CPVRChannelGroupInternal *group)
602 PVR_ERROR error(PVR_ERROR_NO_ERROR);
603 PVR_CLIENTMAP clients;
604 GetConnectedClients(clients);
606 /* get the channel list from each client */
607 for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
609 PVR_ERROR currentError = (*itrClients).second->GetChannels(*group, group->IsRadio());
610 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
611 currentError != PVR_ERROR_NO_ERROR)
613 error = currentError;
614 CLog::Log(LOGERROR, "PVR - %s - cannot get channels from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
621 PVR_ERROR CPVRClients::GetChannelGroups(CPVRChannelGroups *groups)
623 PVR_ERROR error(PVR_ERROR_NO_ERROR);
624 PVR_CLIENTMAP clients;
625 GetConnectedClients(clients);
627 for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
629 PVR_ERROR currentError = (*itrClients).second->GetChannelGroups(groups);
630 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
631 currentError != PVR_ERROR_NO_ERROR)
633 error = currentError;
634 CLog::Log(LOGERROR, "PVR - %s - cannot get groups from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
641 PVR_ERROR CPVRClients::GetChannelGroupMembers(CPVRChannelGroup *group)
643 PVR_ERROR error(PVR_ERROR_NO_ERROR);
644 PVR_CLIENTMAP clients;
645 GetConnectedClients(clients);
647 /* get the member list from each client */
648 for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
650 PVR_ERROR currentError = (*itrClients).second->GetChannelGroupMembers(group);
651 if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
652 currentError != PVR_ERROR_NO_ERROR)
654 error = currentError;
655 CLog::Log(LOGERROR, "PVR - %s - cannot get group members from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
662 bool CPVRClients::HasMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat)
665 iClientID = GetPlayingClientID();
668 return (GetConnectedClient(iClientID, client) &&
669 client->HaveMenuHooks(cat));
672 bool CPVRClients::GetMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, PVR_MENUHOOKS *hooks)
677 iClientID = GetPlayingClientID();
680 if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
682 *hooks = *(client->GetMenuHooks());
689 void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CFileItem *item)
691 PVR_MENUHOOKS *hooks = NULL;
694 if (iClientID < 0 && cat == PVR_MENUHOOK_SETTING)
696 PVR_CLIENTMAP clients;
697 GetConnectedClients(clients);
699 if (clients.size() == 1)
701 iClientID = clients.begin()->first;
703 else if (clients.size() > 1)
705 // have user select client
706 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
708 pDialog->SetHeading(19196);
710 PVR_CLIENTMAP_CITR itrClients;
711 for (itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
713 pDialog->Add(itrClients->second->GetBackendName());
717 int selection = pDialog->GetSelectedLabel();
720 itrClients = clients.begin();
721 for (int i = 0; i < selection; i++)
723 iClientID = itrClients->first;
729 iClientID = GetPlayingClientID();
732 if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
734 hooks = client->GetMenuHooks();
735 std::vector<int> hookIDs;
737 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
739 pDialog->SetHeading(19196);
740 for (unsigned int i = 0; i < hooks->size(); i++)
741 if (hooks->at(i).category == cat || hooks->at(i).category == PVR_MENUHOOK_ALL)
743 pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId));
744 hookIDs.push_back(i);
748 int selection = pDialog->GetSelectedLabel();
750 client->CallMenuHook(hooks->at(hookIDs.at(selection)), item);
754 bool CPVRClients::IsRunningChannelScan(void) const
756 CSingleLock lock(m_critSection);
757 return m_bChannelScanRunning;
760 vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelScan(void) const
762 vector<PVR_CLIENT> possibleScanClients;
763 CSingleLock lock(m_critSection);
765 /* get clients that support channel scanning */
766 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
768 if (itr->second->ReadyToUse() && itr->second->SupportsChannelScan())
769 possibleScanClients.push_back(itr->second);
772 return possibleScanClients;
775 void CPVRClients::StartChannelScan(void)
777 PVR_CLIENT scanClient;
778 CSingleLock lock(m_critSection);
779 vector<PVR_CLIENT> possibleScanClients = GetClientsSupportingChannelScan();
780 m_bChannelScanRunning = true;
782 /* multiple clients found */
783 if (possibleScanClients.size() > 1)
785 CGUIDialogSelect* pDialog= (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
788 pDialog->SetHeading(19119);
790 for (unsigned int i = 0; i < possibleScanClients.size(); i++)
791 pDialog->Add(possibleScanClients[i]->GetFriendlyName());
795 int selection = pDialog->GetSelectedLabel();
797 scanClient = possibleScanClients[selection];
799 /* one client found */
800 else if (possibleScanClients.size() == 1)
802 scanClient = possibleScanClients[0];
804 /* no clients found */
805 else if (!scanClient)
807 CGUIDialogOK::ShowAndGetInput(19033,0,19192,0);
811 /* start the channel scan */
812 CLog::Log(LOGNOTICE,"PVR - %s - starting to scan for channels on client %s",
813 __FUNCTION__, scanClient->GetFriendlyName().c_str());
814 long perfCnt = XbmcThreads::SystemClockMillis();
816 /* stop the supervisor thread */
817 g_PVRManager.StopUpdateThreads();
820 if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR)
821 /* an error occured */
822 CGUIDialogOK::ShowAndGetInput(19111,0,19193,0);
824 /* restart the supervisor thread */
825 g_PVRManager.StartUpdateThreads();
827 CLog::Log(LOGNOTICE, "PVRManager - %s - channel scan finished after %li.%li seconds",
828 __FUNCTION__, (XbmcThreads::SystemClockMillis()-perfCnt)/1000, (XbmcThreads::SystemClockMillis()-perfCnt)%1000);
829 m_bChannelScanRunning = false;
832 bool CPVRClients::IsKnownClient(const AddonPtr client) const
834 // database IDs start at 1
835 return GetClientId(client) > 0;
838 int CPVRClients::RegisterClient(AddonPtr client)
841 if (!client->Enabled())
844 CLog::Log(LOGDEBUG, "%s - registering add-on '%s'", __FUNCTION__, client->Name().c_str());
846 CPVRDatabase *database = GetPVRDatabase();
850 // check whether we already know this client
851 iClientId = database->GetClientId(client->ID());
853 // try to register the new client in the db
854 if (iClientId < 0 && (iClientId = database->Persist(client)) < 0)
856 CLog::Log(LOGERROR, "PVR - %s - can't add client '%s' to the database", __FUNCTION__, client->Name().c_str());
861 // load and initialise the client libraries
863 CSingleLock lock(m_critSection);
864 PVR_CLIENTMAP_CITR existingClient = m_clientMap.find(iClientId);
865 if (existingClient != m_clientMap.end())
867 // return existing client
868 addon = existingClient->second;
872 // create a new client instance
873 addon = boost::dynamic_pointer_cast<CPVRClient>(client);
874 m_clientMap.insert(std::make_pair(iClientId, addon));
879 CLog::Log(LOGERROR, "PVR - %s - can't register add-on '%s'", __FUNCTION__, client->Name().c_str());
884 bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */)
888 VECADDONS disableAddons;
890 CSingleLock lock(m_critSection);
897 for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++)
899 const AddonPtr clientAddon = map.at(iClientPtr);
900 bool bEnabled = clientAddon->Enabled() &&
901 !CAddonMgr::Get().IsAddonDisabled(clientAddon->ID());
903 if (!bEnabled && IsKnownClient(clientAddon))
905 CSingleLock lock(m_critSection);
906 /* stop the client and remove it from the db */
907 StopClient(clientAddon, false);
908 VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), clientAddon);
909 if (addonPtr != m_addons.end())
910 m_addons.erase(addonPtr);
913 else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(clientAddon) || !IsConnectedClient(clientAddon)))
915 bool bDisabled(false);
917 // register the add-on in the pvr db, and create the CPVRClient instance
918 int iClientId = RegisterClient(clientAddon);
921 // failed to register or create the add-on, disable it
922 CLog::Log(LOGWARNING, "%s - failed to register add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
923 disableAddons.push_back(clientAddon);
928 ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
931 CSingleLock lock(m_critSection);
932 if (!GetClient(iClientId, addon))
934 CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
935 disableAddons.push_back(clientAddon);
940 // throttle connection attempts, no more than 1 attempt per 5 seconds
941 if (!bDisabled && addon->Enabled())
944 CDateTime::GetCurrentDateTime().GetAsTime(now);
945 std::map<int, time_t>::iterator it = m_connectionAttempts.find(iClientId);
946 if (it != m_connectionAttempts.end() && now < it->second)
948 m_connectionAttempts[iClientId] = now + 5;
951 // re-check the enabled status. newly installed clients get disabled when they're added to the db
952 if (!bDisabled && addon->Enabled() && (status = addon->Create(iClientId)) != ADDON_STATUS_OK)
954 CLog::Log(LOGWARNING, "%s - failed to create add-on %s, status = %d", __FUNCTION__, clientAddon->Name().c_str(), status);
955 if (!addon.get() || !addon->DllLoaded() || status == ADDON_STATUS_PERMANENT_FAILURE)
957 // failed to load the dll of this add-on, disable it
958 CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
959 disableAddons.push_back(clientAddon);
965 if (bDisabled && (g_PVRManager.IsStarted() || g_PVRManager.IsInitialising()))
966 CGUIDialogOK::ShowAndGetInput(24070, 24071, 16029, 0);
970 // disable add-ons that failed to initialise
971 if (disableAddons.size() > 0)
973 CSingleLock lock(m_critSection);
974 for (VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); it++)
976 // disable in the add-on db
977 CAddonMgr::Get().DisableAddon((*it)->ID(), true);
979 // remove from the pvr add-on list
980 VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), *it);
981 if (addonPtr != m_addons.end())
982 m_addons.erase(addonPtr);
989 void CPVRClients::Process(void)
991 bool bCheckedEnabledClientsOnStartup(false);
993 CAddonMgr::Get().RegisterAddonMgrCallback(ADDON_PVRDLL, this);
994 CAddonMgr::Get().RegisterObserver(this);
998 while (!g_application.m_bStop && !m_bStop)
1000 UpdateAndInitialiseClients();
1002 if (!bCheckedEnabledClientsOnStartup)
1004 bCheckedEnabledClientsOnStartup = true;
1005 if (!HasEnabledClients() && !m_bNoAddonWarningDisplayed)
1006 ShowDialogNoClientsEnabled();
1010 if (GetPlayingClient(client))
1011 client->UpdateCharInfoSignalStatus();
1016 void CPVRClients::ShowDialogNoClientsEnabled(void)
1018 if (!g_PVRManager.IsStarted() && !g_PVRManager.IsInitialising())
1021 CGUIDialogOK::ShowAndGetInput(19240, 19241, 19242, 19243);
1023 vector<CStdString> params;
1024 params.push_back("addons://disabled/xbmc.pvrclient");
1025 params.push_back("return");
1026 g_windowManager.ActivateWindow(WINDOW_ADDON_BROWSER, params);
1029 void CPVRClients::SaveCurrentChannelSettings(void)
1031 CPVRChannelPtr channel;
1033 CSingleLock lock(m_critSection);
1034 if (!GetPlayingChannel(channel) || !m_bIsValidChannelSettings)
1038 CPVRDatabase *database = GetPVRDatabase();
1042 if (CMediaSettings::Get().GetCurrentVideoSettings() != CMediaSettings::Get().GetDefaultVideoSettings())
1044 CLog::Log(LOGDEBUG, "PVR - %s - persisting custom channel settings for channel '%s'",
1045 __FUNCTION__, channel->ChannelName().c_str());
1046 database->PersistChannelSettings(*channel, CMediaSettings::Get().GetCurrentVideoSettings());
1050 CLog::Log(LOGDEBUG, "PVR - %s - no custom channel settings for channel '%s'",
1051 __FUNCTION__, channel->ChannelName().c_str());
1052 database->DeleteChannelSettings(*channel);
1056 void CPVRClients::LoadCurrentChannelSettings(void)
1058 CPVRChannelPtr channel;
1060 CSingleLock lock(m_critSection);
1061 if (!GetPlayingChannel(channel))
1065 CPVRDatabase *database = GetPVRDatabase();
1069 if (g_application.m_pPlayer->HasPlayer())
1071 /* store the current settings so we can compare if anything has changed */
1072 CVideoSettings previousSettings = CMediaSettings::Get().GetCurrentVideoSettings();
1074 /* load the persisted channel settings and set them as current */
1075 CVideoSettings loadedChannelSettings = CMediaSettings::Get().GetDefaultVideoSettings();
1076 database->GetChannelSettings(*channel, loadedChannelSettings);
1077 CMediaSettings::Get().GetCurrentVideoSettings() = loadedChannelSettings;
1079 /* update the view mode if it set to custom or differs from the previous mode */
1080 if (previousSettings.m_ViewMode != loadedChannelSettings.m_ViewMode || loadedChannelSettings.m_ViewMode == ViewModeCustom)
1081 g_renderManager.SetViewMode(loadedChannelSettings.m_ViewMode);
1083 /* only change the subtitle stream, if it's different */
1084 if (previousSettings.m_SubtitleStream != loadedChannelSettings.m_SubtitleStream)
1085 g_application.m_pPlayer->SetSubtitle(loadedChannelSettings.m_SubtitleStream);
1087 /* only change the audio stream if it's different */
1088 if (g_application.m_pPlayer->GetAudioStream() != loadedChannelSettings.m_AudioStream && loadedChannelSettings.m_AudioStream >= 0)
1089 g_application.m_pPlayer->SetAudioStream(loadedChannelSettings.m_AudioStream);
1091 g_application.m_pPlayer->SetAVDelay(loadedChannelSettings.m_AudioDelay);
1092 g_application.m_pPlayer->SetDynamicRangeCompression((long)(loadedChannelSettings.m_VolumeAmplification * 100));
1093 g_application.m_pPlayer->SetSubtitleVisible(loadedChannelSettings.m_SubtitleOn);
1094 g_application.m_pPlayer->SetSubTitleDelay(loadedChannelSettings.m_SubtitleDelay);
1096 /* settings can be saved on next channel switch */
1097 m_bIsValidChannelSettings = true;
1101 bool CPVRClients::UpdateAddons(void)
1104 bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true));
1108 CSingleLock lock(m_critSection);
1112 // handle "new" addons which aren't yet in the db - these have to be added first
1113 for (unsigned iClientPtr = 0; iClientPtr < m_addons.size(); iClientPtr++)
1115 const AddonPtr clientAddon = m_addons.at(iClientPtr);
1117 if (!m_addonDb.HasAddon(clientAddon->ID()))
1119 m_addonDb.AddAddon(clientAddon, -1);
1123 if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed &&
1124 !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) &&
1125 (g_PVRManager.IsStarted() || g_PVRManager.IsInitialising()))
1127 // No PVR add-ons could be found
1128 // You need a tuner, backend software, and an add-on for the backend to be able to use PVR.
1129 // Please visit xbmc.org/pvr to learn more.
1130 m_bNoAddonWarningDisplayed = true;
1131 CSettings::Get().SetBool("pvrmanager.enabled", false);
1132 CGUIDialogOK::ShowAndGetInput(19271, 19272, 19273, 19274);
1133 CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_MYPVR, 0);
1134 g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_MYPVR);
1140 void CPVRClients::Notify(const Observable &obs, const ObservableMessage msg)
1142 if (msg == ObservableMessageAddons)
1146 bool CPVRClients::GetClient(const CStdString &strId, AddonPtr &addon) const
1148 CSingleLock lock(m_critSection);
1149 for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
1151 if (itr->second->ID() == strId)
1153 addon = itr->second;
1160 bool CPVRClients::SupportsChannelGroups(int iClientId) const
1163 return GetConnectedClient(iClientId, client) && client->SupportsChannelGroups();
1166 bool CPVRClients::SupportsChannelScan(int iClientId) const
1169 return GetConnectedClient(iClientId, client) && client->SupportsChannelScan();
1172 bool CPVRClients::SupportsEPG(int iClientId) const
1175 return GetConnectedClient(iClientId, client) && client->SupportsEPG();
1178 bool CPVRClients::SupportsLastPlayedPosition(int iClientId) const
1181 return GetConnectedClient(iClientId, client) && client->SupportsLastPlayedPosition();
1184 bool CPVRClients::SupportsRadio(int iClientId) const
1187 return GetConnectedClient(iClientId, client) && client->SupportsRadio();
1190 bool CPVRClients::SupportsRecordings(int iClientId) const
1193 return GetConnectedClient(iClientId, client) && client->SupportsRecordings();
1196 bool CPVRClients::SupportsRecordingFolders(int iClientId) const
1199 return GetConnectedClient(iClientId, client) && client->SupportsRecordingFolders();
1202 bool CPVRClients::SupportsRecordingPlayCount(int iClientId) const
1205 return GetConnectedClient(iClientId, client) && client->SupportsRecordingPlayCount();
1208 bool CPVRClients::SupportsRecordingEdl(int iClientId) const
1211 return GetConnectedClient(iClientId, client) && client->SupportsRecordingEdl();
1214 bool CPVRClients::SupportsTimers(int iClientId) const
1217 return GetConnectedClient(iClientId, client) && client->SupportsTimers();
1220 bool CPVRClients::SupportsTV(int iClientId) const
1223 return GetConnectedClient(iClientId, client) && client->SupportsTV();
1226 bool CPVRClients::HandlesDemuxing(int iClientId) const
1229 return GetConnectedClient(iClientId, client) && client->HandlesDemuxing();
1232 bool CPVRClients::HandlesInputStream(int iClientId) const
1235 return GetConnectedClient(iClientId, client) && client->HandlesInputStream();
1238 bool CPVRClients::GetPlayingClient(PVR_CLIENT &client) const
1240 return GetConnectedClient(GetPlayingClientID(), client);
1243 bool CPVRClients::OpenStream(const CPVRChannel &tag, bool bIsSwitchingChannel)
1245 bool bReturn(false);
1248 /* try to open the stream on the client */
1250 if (GetConnectedClient(tag.ClientID(), client) &&
1251 client->OpenStream(tag, bIsSwitchingChannel))
1253 CSingleLock lock(m_critSection);
1254 m_playingClientId = tag.ClientID();
1255 m_bIsPlayingLiveTV = true;
1257 if (tag.ClientID() == PVR_VIRTUAL_CLIENT_ID)
1258 m_strPlayingClientName = g_localizeStrings.Get(19209);
1259 else if (!tag.IsVirtual() && client.get())
1260 m_strPlayingClientName = client->GetFriendlyName();
1262 m_strPlayingClientName = g_localizeStrings.Get(13205);
1270 bool CPVRClients::OpenStream(const CPVRRecording &tag)
1272 bool bReturn(false);
1275 /* try to open the recording stream on the client */
1277 if (GetConnectedClient(tag.m_iClientId, client) &&
1278 client->OpenStream(tag))
1280 CSingleLock lock(m_critSection);
1281 m_playingClientId = tag.m_iClientId;
1282 m_bIsPlayingRecording = true;
1283 m_strPlayingClientName = client->GetFriendlyName();
1290 void CPVRClients::CloseStream(void)
1292 PVR_CLIENT playingClient;
1293 if (GetPlayingClient(playingClient))
1294 playingClient->CloseStream();
1296 CSingleLock lock(m_critSection);
1297 m_bIsPlayingLiveTV = false;
1298 m_bIsPlayingRecording = false;
1299 m_playingClientId = PVR_INVALID_CLIENT_ID;
1300 m_strPlayingClientName = "";
1303 int CPVRClients::ReadStream(void* lpBuf, int64_t uiBufSize)
1306 if (GetPlayingClient(client))
1307 return client->ReadStream(lpBuf, uiBufSize);
1311 int64_t CPVRClients::GetStreamLength(void)
1314 if (GetPlayingClient(client))
1315 return client->GetStreamLength();
1319 int64_t CPVRClients::SeekStream(int64_t iFilePosition, int iWhence/* = SEEK_SET*/)
1322 if (GetPlayingClient(client))
1323 return client->SeekStream(iFilePosition, iWhence);
1327 int64_t CPVRClients::GetStreamPosition(void)
1330 if (GetPlayingClient(client))
1331 return client->GetStreamPosition();
1335 void CPVRClients::PauseStream(bool bPaused)
1338 if (GetPlayingClient(client))
1339 client->PauseStream(bPaused);
1342 CStdString CPVRClients::GetCurrentInputFormat(void) const
1344 CStdString strReturn;
1345 CPVRChannelPtr currentChannel;
1346 if (GetPlayingChannel(currentChannel))
1347 strReturn = currentChannel->InputFormat();
1352 PVR_STREAM_PROPERTIES CPVRClients::GetCurrentStreamProperties(void)
1354 PVR_STREAM_PROPERTIES props;
1357 memset(&props, 0, sizeof(props));
1358 if (GetPlayingClient(client))
1359 client->GetStreamProperties(&props);
1364 bool CPVRClients::IsPlaying(void) const
1366 CSingleLock lock(m_critSection);
1367 return m_bIsPlayingRecording || m_bIsPlayingLiveTV;
1370 bool CPVRClients::IsPlayingRadio(void) const
1373 if (GetPlayingClient(client))
1374 return client->IsPlayingLiveRadio();
1378 bool CPVRClients::IsPlayingTV(void) const
1381 if (GetPlayingClient(client))
1382 return client->IsPlayingLiveTV();
1386 bool CPVRClients::IsPlayingRecording(void) const
1388 CSingleLock lock(m_critSection);
1389 return m_bIsPlayingRecording;
1392 bool CPVRClients::IsReadingLiveStream(void) const
1394 CSingleLock lock(m_critSection);
1395 return m_bIsPlayingLiveTV;
1398 bool CPVRClients::IsEncrypted(void) const
1401 if (GetPlayingClient(client))
1402 return client->IsPlayingEncryptedChannel();
1406 time_t CPVRClients::GetPlayingTime() const
1411 if (GetPlayingClient(client))
1413 time = client->GetPlayingTime();
1419 time_t CPVRClients::GetBufferTimeStart() const
1424 if (GetPlayingClient(client))
1426 time = client->GetBufferTimeStart();
1432 time_t CPVRClients::GetBufferTimeEnd() const
1437 if (GetPlayingClient(client))
1439 time = client->GetBufferTimeEnd();