Merge pull request #4655 from codesnake/allow_restart_of_a_pvr_addon_while_in_create
[vuplus_xbmc] / xbmc / pvr / addons / PVRClients.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "PVRClients.h"
22
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"
39
40 #ifdef HAS_VIDEO_PLAYBACK
41 #include "cores/VideoRenderers/RenderManager.h"
42 #endif
43
44 using namespace std;
45 using namespace ADDON;
46 using namespace PVR;
47 using namespace EPG;
48
49 CPVRClients::CPVRClients(void) :
50     CThread("PVRClient"),
51     m_bChannelScanRunning(false),
52     m_bIsSwitchingChannels(false),
53     m_bIsValidChannelSettings(false),
54     m_playingClientId(-EINVAL),
55     m_bIsPlayingLiveTV(false),
56     m_bIsPlayingRecording(false),
57     m_scanStart(0),
58     m_bNoAddonWarningDisplayed(false)
59 {
60 }
61
62 CPVRClients::~CPVRClients(void)
63 {
64   Unload();
65 }
66
67 bool CPVRClients::IsInUse(const std::string& strAddonId) const
68 {
69   CSingleLock lock(m_critSection);
70
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()))
73       return true;
74   return false;
75 }
76
77 void CPVRClients::Start(void)
78 {
79   Stop();
80
81   m_addonDb.Open();
82   Create();
83   SetPriority(-1);
84 }
85
86 void CPVRClients::Stop(void)
87 {
88   StopThread();
89   m_addonDb.Close();
90 }
91
92 bool CPVRClients::IsConnectedClient(int iClientId) const
93 {
94   PVR_CLIENT client;
95   return GetConnectedClient(iClientId, client);
96 }
97
98 bool CPVRClients::IsConnectedClient(const AddonPtr addon)
99 {
100   CSingleLock lock(m_critSection);
101   
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();
105   return false;
106 }
107
108 int CPVRClients::GetClientId(const AddonPtr client) const
109 {
110   CSingleLock lock(m_critSection);
111
112   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
113     if (itr->second->ID() == client->ID())
114       return itr->first;
115
116   return -1;
117 }
118
119 bool CPVRClients::GetClient(int iClientId, PVR_CLIENT &addon) const
120 {
121   bool bReturn(false);
122   if (iClientId <= PVR_INVALID_CLIENT_ID || iClientId == PVR_VIRTUAL_CLIENT_ID)
123     return bReturn;
124
125   CSingleLock lock(m_critSection);
126
127   PVR_CLIENTMAP_CITR itr = m_clientMap.find(iClientId);
128   if (itr != m_clientMap.end())
129   {
130     addon = itr->second;
131     bReturn = true;
132   }
133
134   return bReturn;
135 }
136
137 bool CPVRClients::GetConnectedClient(int iClientId, PVR_CLIENT &addon) const
138 {
139   if (GetClient(iClientId, addon))
140     return addon->ReadyToUse();
141   return false;
142 }
143
144 bool CPVRClients::RequestRestart(AddonPtr addon, bool bDataChanged)
145 {
146   return StopClient(addon, true);
147 }
148
149 bool CPVRClients::RequestRemoval(AddonPtr addon)
150 {
151   return StopClient(addon, false);
152 }
153
154 void CPVRClients::Unload(void)
155 {
156   Stop();
157
158   CSingleLock lock(m_critSection);
159
160   /* destroy all clients */
161   for (PVR_CLIENTMAP_ITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
162     itr->second->Destroy();
163
164   /* reset class properties */
165   m_bChannelScanRunning  = false;
166   m_bIsPlayingLiveTV     = false;
167   m_bIsPlayingRecording  = false;
168   m_strPlayingClientName = "";
169
170   m_clientMap.clear();
171 }
172
173 int CPVRClients::GetFirstConnectedClientID(void)
174 {
175   CSingleLock lock(m_critSection);
176
177   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
178     if (itr->second->ReadyToUse())
179       return itr->second->GetID();
180
181   return -1;
182 }
183
184 int CPVRClients::EnabledClientAmount(void) const
185 {
186   int iReturn(0);
187   CSingleLock lock(m_critSection);
188
189   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
190     if (itr->second->Enabled())
191       ++iReturn;
192
193   return iReturn;
194 }
195
196 bool CPVRClients::HasEnabledClients(void) const
197 {
198   return EnabledClientAmount() > 0;
199 }
200
201 bool CPVRClients::StopClient(AddonPtr client, bool bRestart)
202 {
203   CSingleLock lock(m_critSection);  
204   int iId = GetClientId(client);
205   PVR_CLIENT mappedClient;
206   if (GetClient(iId, mappedClient))
207   {
208     if (bRestart)
209       mappedClient->ReCreate();
210     else
211       mappedClient->Destroy();
212
213     return true;
214   }
215
216   return false;
217 }
218
219 int CPVRClients::ConnectedClientAmount(void) const
220 {
221   int iReturn(0);
222   CSingleLock lock(m_critSection);
223
224   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
225     if (itr->second->ReadyToUse())
226       ++iReturn;
227
228   return iReturn;
229 }
230
231 bool CPVRClients::HasConnectedClients(void) const
232 {
233   CSingleLock lock(m_critSection);
234
235   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
236     if (itr->second->ReadyToUse())
237       return true;
238
239   return false;
240 }
241
242 bool CPVRClients::GetClientName(int iClientId, CStdString &strName) const
243 {
244   bool bReturn(false);
245   PVR_CLIENT client;
246   if ((bReturn = GetConnectedClient(iClientId, client)) == true)
247     strName = client->GetFriendlyName();
248
249   return bReturn;
250 }
251
252 int CPVRClients::GetConnectedClients(PVR_CLIENTMAP &clients) const
253 {
254   int iReturn(0);
255   CSingleLock lock(m_critSection);
256
257   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
258   {
259     if (itr->second->ReadyToUse())
260     {
261       clients.insert(std::make_pair(itr->second->GetID(), itr->second));
262       ++iReturn;
263     }
264   }
265
266   return iReturn;
267 }
268
269 int CPVRClients::GetPlayingClientID(void) const
270 {
271   CSingleLock lock(m_critSection);
272
273   if (m_bIsPlayingLiveTV || m_bIsPlayingRecording)
274     return m_playingClientId;
275   return -EINVAL;
276 }
277
278 const CStdString CPVRClients::GetPlayingClientName(void) const
279 {
280   CSingleLock lock(m_critSection);
281   return m_strPlayingClientName;
282 }
283
284 CStdString CPVRClients::GetStreamURL(const CPVRChannel &tag)
285 {
286   CStdString strReturn;
287   PVR_CLIENT client;
288   if (GetConnectedClient(tag.ClientID(), client))
289     strReturn = client->GetLiveStreamURL(tag);
290   else
291     CLog::Log(LOGERROR, "PVR - %s - cannot find client %d",__FUNCTION__, tag.ClientID());
292
293   return strReturn;
294 }
295
296 bool CPVRClients::SwitchChannel(const CPVRChannel &channel)
297 {
298   {
299     CSingleLock lock(m_critSection);
300     if (m_bIsSwitchingChannels)
301     {
302       CLog::Log(LOGDEBUG, "PVRClients - %s - can't switch to channel '%s'. waiting for the previous switch to complete", __FUNCTION__, channel.ChannelName().c_str());
303       return false;
304     }
305     m_bIsSwitchingChannels = true;
306   }
307
308   bool bSwitchSuccessful(false);
309   CPVRChannelPtr currentChannel;
310   if (// no channel is currently playing
311       !GetPlayingChannel(currentChannel) ||
312       // different backend
313       currentChannel->ClientID() != channel.ClientID() ||
314       // stream URL should always be opened as a new file
315       !channel.StreamURL().empty() || !currentChannel->StreamURL().empty())
316   {
317     if (channel.StreamURL().empty())
318     {
319       CloseStream();
320       bSwitchSuccessful = OpenStream(channel, true);
321     }
322     else
323     {
324       CFileItem m_currentFile(channel);
325       CApplicationMessenger::Get().PlayFile(m_currentFile, false);
326       bSwitchSuccessful = true;
327     }
328   }
329   // same channel
330   else if (currentChannel.get() && *currentChannel == channel)
331   {
332     bSwitchSuccessful = true;
333   }
334   else
335   {
336     PVR_CLIENT client;
337     if (GetConnectedClient(channel.ClientID(), client))
338       bSwitchSuccessful = client->SwitchChannel(channel);
339   }
340
341   {
342     CSingleLock lock(m_critSection);
343     m_bIsSwitchingChannels = false;
344     if (bSwitchSuccessful)
345       m_bIsValidChannelSettings = false;
346   }
347
348   if (!bSwitchSuccessful)
349     CLog::Log(LOGERROR, "PVR - %s - cannot switch to channel '%s' on client '%d'",__FUNCTION__, channel.ChannelName().c_str(), channel.ClientID());
350
351   return bSwitchSuccessful;
352 }
353
354 bool CPVRClients::GetPlayingChannel(CPVRChannelPtr &channel) const
355 {
356   PVR_CLIENT client;
357   if (GetPlayingClient(client))
358     return client->GetPlayingChannel(channel);
359   return false;
360 }
361
362 bool CPVRClients::GetPlayingRecording(CPVRRecording &recording) const
363 {
364   PVR_CLIENT client;
365   if (GetPlayingClient(client))
366     return client->GetPlayingRecording(recording);
367   return false;
368 }
369
370 bool CPVRClients::HasTimerSupport(int iClientId)
371 {
372   PVR_CLIENT client;
373   if (GetConnectedClient(iClientId, client))
374     return client->SupportsTimers();
375
376   return false;
377 }
378
379 PVR_ERROR CPVRClients::GetTimers(CPVRTimers *timers)
380 {
381   PVR_ERROR error(PVR_ERROR_NO_ERROR);
382   PVR_CLIENTMAP clients;
383   GetConnectedClients(clients);
384
385   /* get the timer list from each client */
386   for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
387   {
388     PVR_ERROR currentError = (*itrClients).second->GetTimers(timers);
389     if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
390         currentError != PVR_ERROR_NO_ERROR)
391     {
392       CLog::Log(LOGERROR, "PVR - %s - cannot get timers from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
393       error = currentError;
394     }
395   }
396
397   return error;
398 }
399
400 PVR_ERROR CPVRClients::AddTimer(const CPVRTimerInfoTag &timer)
401 {
402   PVR_ERROR error(PVR_ERROR_UNKNOWN);
403
404   PVR_CLIENT client;
405   if (GetConnectedClient(timer.m_iClientId, client))
406     error = client->AddTimer(timer);
407
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));
410
411   return error;
412 }
413
414 PVR_ERROR CPVRClients::UpdateTimer(const CPVRTimerInfoTag &timer)
415 {
416   PVR_ERROR error(PVR_ERROR_UNKNOWN);
417
418   PVR_CLIENT client;
419   if (GetConnectedClient(timer.m_iClientId, client))
420     error = client->UpdateTimer(timer);
421
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));
424
425   return error;
426 }
427
428 PVR_ERROR CPVRClients::DeleteTimer(const CPVRTimerInfoTag &timer, bool bForce)
429 {
430   PVR_ERROR error(PVR_ERROR_UNKNOWN);
431   PVR_CLIENT client;
432
433   if (GetConnectedClient(timer.m_iClientId, client))
434     error = client->DeleteTimer(timer, bForce);
435
436   return error;
437 }
438
439 PVR_ERROR CPVRClients::RenameTimer(const CPVRTimerInfoTag &timer, const CStdString &strNewName)
440 {
441   PVR_ERROR error(PVR_ERROR_UNKNOWN);
442
443   PVR_CLIENT client;
444   if (GetConnectedClient(timer.m_iClientId, client))
445     error = client->RenameTimer(timer, strNewName);
446
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));
449
450   return error;
451 }
452
453 PVR_ERROR CPVRClients::GetRecordings(CPVRRecordings *recordings)
454 {
455   PVR_ERROR error(PVR_ERROR_NO_ERROR);
456   PVR_CLIENTMAP clients;
457   GetConnectedClients(clients);
458
459   for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
460   {
461     PVR_ERROR currentError = (*itrClients).second->GetRecordings(recordings);
462     if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
463         currentError != PVR_ERROR_NO_ERROR)
464     {
465       CLog::Log(LOGERROR, "PVR - %s - cannot get recordings from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(currentError));
466       error = currentError;
467     }
468   }
469
470   return error;
471 }
472
473 PVR_ERROR CPVRClients::RenameRecording(const CPVRRecording &recording)
474 {
475   PVR_ERROR error(PVR_ERROR_UNKNOWN);
476
477   PVR_CLIENT client;
478   if (GetConnectedClient(recording.m_iClientId, client))
479     error = client->RenameRecording(recording);
480
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));
483
484   return error;
485 }
486
487 PVR_ERROR CPVRClients::DeleteRecording(const CPVRRecording &recording)
488 {
489   PVR_ERROR error(PVR_ERROR_UNKNOWN);
490
491   PVR_CLIENT client;
492   if (GetConnectedClient(recording.m_iClientId, client))
493     error = client->DeleteRecording(recording);
494
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));
497
498   return error;
499 }
500
501 bool CPVRClients::SetRecordingLastPlayedPosition(const CPVRRecording &recording, int lastplayedposition, PVR_ERROR *error)
502 {
503   *error = PVR_ERROR_UNKNOWN;
504   PVR_CLIENT client;
505   if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
506     *error = client->SetRecordingLastPlayedPosition(recording, lastplayedposition);
507   else
508     CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
509
510   return *error == PVR_ERROR_NO_ERROR;
511 }
512
513 int CPVRClients::GetRecordingLastPlayedPosition(const CPVRRecording &recording)
514 {
515   int rc = 0;
516
517   PVR_CLIENT client;
518   if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordings())
519     rc = client->GetRecordingLastPlayedPosition(recording);
520   else
521     CLog::Log(LOGERROR, "PVR - %s - client %d does not support recordings",__FUNCTION__, recording.m_iClientId);
522
523   return rc;
524 }
525
526 bool CPVRClients::SetRecordingPlayCount(const CPVRRecording &recording, int count, PVR_ERROR *error)
527 {
528   *error = PVR_ERROR_UNKNOWN;
529   PVR_CLIENT client;
530   if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingPlayCount())
531     *error = client->SetRecordingPlayCount(recording, count);
532   else
533     CLog::Log(LOGERROR, "PVR - %s - client %d does not support setting recording's play count",__FUNCTION__, recording.m_iClientId);
534
535   return *error == PVR_ERROR_NO_ERROR;
536 }
537
538 std::vector<PVR_EDL_ENTRY> CPVRClients::GetRecordingEdl(const CPVRRecording &recording)
539 {
540   PVR_CLIENT client;
541   if (GetConnectedClient(recording.m_iClientId, client) && client->SupportsRecordingEdl())
542     return client->GetRecordingEdl(recording);
543   else
544     CLog::Log(LOGERROR, "PVR - %s - client %d does not support getting Edl", __FUNCTION__, recording.m_iClientId);
545
546   return std::vector<PVR_EDL_ENTRY>();
547 }
548
549 bool CPVRClients::IsRecordingOnPlayingChannel(void) const
550 {
551   CPVRChannelPtr currentChannel;
552   return GetPlayingChannel(currentChannel) &&
553       currentChannel->IsRecording();
554 }
555
556 bool CPVRClients::CanRecordInstantly(void)
557 {
558   CPVRChannelPtr currentChannel;
559   return GetPlayingChannel(currentChannel) &&
560       currentChannel->CanRecord();
561 }
562
563 bool CPVRClients::CanPauseStream(void) const
564 {
565   PVR_CLIENT client;
566
567   if (GetPlayingClient(client))
568   {
569     return m_bIsPlayingRecording || client->CanPauseStream();
570   }
571
572   return false;
573 }
574
575 bool CPVRClients::CanSeekStream(void) const
576 {
577   PVR_CLIENT client;
578
579   if (GetPlayingClient(client))
580   {
581     return m_bIsPlayingRecording || client->CanSeekStream();
582   }
583
584   return false;
585 }
586
587 PVR_ERROR CPVRClients::GetEPGForChannel(const CPVRChannel &channel, CEpg *epg, time_t start, time_t end)
588 {
589   PVR_ERROR error(PVR_ERROR_UNKNOWN);
590   PVR_CLIENT client;
591   if (GetConnectedClient(channel.ClientID(), client))
592     error = client->GetEPGForChannel(channel, epg, start, end);
593
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));
596
597   return error;
598 }
599
600 PVR_ERROR CPVRClients::GetChannels(CPVRChannelGroupInternal *group)
601 {
602   PVR_ERROR error(PVR_ERROR_NO_ERROR);
603   PVR_CLIENTMAP clients;
604   GetConnectedClients(clients);
605
606   /* get the channel list from each client */
607   for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
608   {
609     PVR_ERROR currentError = (*itrClients).second->GetChannels(*group, group->IsRadio());
610     if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
611         currentError != PVR_ERROR_NO_ERROR)
612     {
613       error = currentError;
614       CLog::Log(LOGERROR, "PVR - %s - cannot get channels from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
615     }
616   }
617
618   return error;
619 }
620
621 PVR_ERROR CPVRClients::GetChannelGroups(CPVRChannelGroups *groups)
622 {
623   PVR_ERROR error(PVR_ERROR_NO_ERROR);
624   PVR_CLIENTMAP clients;
625   GetConnectedClients(clients);
626
627   for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
628   {
629     PVR_ERROR currentError = (*itrClients).second->GetChannelGroups(groups);
630     if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
631         currentError != PVR_ERROR_NO_ERROR)
632     {
633       error = currentError;
634       CLog::Log(LOGERROR, "PVR - %s - cannot get groups from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
635     }
636   }
637
638   return error;
639 }
640
641 PVR_ERROR CPVRClients::GetChannelGroupMembers(CPVRChannelGroup *group)
642 {
643   PVR_ERROR error(PVR_ERROR_NO_ERROR);
644   PVR_CLIENTMAP clients;
645   GetConnectedClients(clients);
646
647   /* get the member list from each client */
648   for (PVR_CLIENTMAP_CITR itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
649   {
650     PVR_ERROR currentError = (*itrClients).second->GetChannelGroupMembers(group);
651     if (currentError != PVR_ERROR_NOT_IMPLEMENTED &&
652         currentError != PVR_ERROR_NO_ERROR)
653     {
654       error = currentError;
655       CLog::Log(LOGERROR, "PVR - %s - cannot get group members from client '%d': %s",__FUNCTION__, (*itrClients).first, CPVRClient::ToString(error));
656     }
657   }
658
659   return error;
660 }
661
662 bool CPVRClients::HasMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat)
663 {
664   if (iClientID < 0)
665     iClientID = GetPlayingClientID();
666
667   PVR_CLIENT client;
668   return (GetConnectedClient(iClientID, client) &&
669       client->HaveMenuHooks(cat));
670 }
671
672 bool CPVRClients::GetMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, PVR_MENUHOOKS *hooks)
673 {
674   bool bReturn(false);
675
676   if (iClientID < 0)
677     iClientID = GetPlayingClientID();
678
679   PVR_CLIENT client;
680   if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
681   {
682     *hooks = *(client->GetMenuHooks());
683     bReturn = true;
684   }
685
686   return bReturn;
687 }
688
689 void CPVRClients::ProcessMenuHooks(int iClientID, PVR_MENUHOOK_CAT cat, const CFileItem *item)
690 {
691   PVR_MENUHOOKS *hooks = NULL;
692
693   // get client id
694   if (iClientID < 0 && cat == PVR_MENUHOOK_SETTING)
695   {
696     PVR_CLIENTMAP clients;
697     GetConnectedClients(clients);
698
699     if (clients.size() == 1)
700     {
701       iClientID = clients.begin()->first;
702     }
703     else if (clients.size() > 1)
704     {
705       // have user select client
706       CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
707       pDialog->Reset();
708       pDialog->SetHeading(19196);
709
710       PVR_CLIENTMAP_CITR itrClients;
711       for (itrClients = clients.begin(); itrClients != clients.end(); itrClients++)
712       {
713         pDialog->Add(itrClients->second->GetBackendName());
714       }
715       pDialog->DoModal();
716
717       int selection = pDialog->GetSelectedLabel();
718       if (selection >= 0)
719       {
720         itrClients = clients.begin();
721         for (int i = 0; i < selection; i++)
722           itrClients++;
723         iClientID = itrClients->first;
724       }
725     }
726   }
727
728   if (iClientID < 0)
729     iClientID = GetPlayingClientID();
730
731   PVR_CLIENT client;
732   if (GetConnectedClient(iClientID, client) && client->HaveMenuHooks(cat))
733   {
734     hooks = client->GetMenuHooks();
735     std::vector<int> hookIDs;
736
737     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
738     pDialog->Reset();
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)
742       {
743         pDialog->Add(client->GetString(hooks->at(i).iLocalizedStringId));
744         hookIDs.push_back(i);
745       }
746     pDialog->DoModal();
747
748     int selection = pDialog->GetSelectedLabel();
749     if (selection >= 0)
750       client->CallMenuHook(hooks->at(hookIDs.at(selection)), item);
751   }
752 }
753
754 bool CPVRClients::IsRunningChannelScan(void) const
755 {
756   CSingleLock lock(m_critSection);
757   return m_bChannelScanRunning;
758 }
759
760 vector<PVR_CLIENT> CPVRClients::GetClientsSupportingChannelScan(void) const
761 {
762   vector<PVR_CLIENT> possibleScanClients;
763   CSingleLock lock(m_critSection);
764
765   /* get clients that support channel scanning */
766   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
767   {
768     if (itr->second->ReadyToUse() && itr->second->SupportsChannelScan())
769       possibleScanClients.push_back(itr->second);
770   }
771
772   return possibleScanClients;
773 }
774
775 void CPVRClients::StartChannelScan(void)
776 {
777   PVR_CLIENT scanClient;
778   CSingleLock lock(m_critSection);
779   vector<PVR_CLIENT> possibleScanClients = GetClientsSupportingChannelScan();
780   m_bChannelScanRunning = true;
781
782   /* multiple clients found */
783   if (possibleScanClients.size() > 1)
784   {
785     CGUIDialogSelect* pDialog= (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
786
787     pDialog->Reset();
788     pDialog->SetHeading(19119);
789
790     for (unsigned int i = 0; i < possibleScanClients.size(); i++)
791       pDialog->Add(possibleScanClients[i]->GetFriendlyName());
792
793     pDialog->DoModal();
794
795     int selection = pDialog->GetSelectedLabel();
796     if (selection >= 0)
797       scanClient = possibleScanClients[selection];
798   }
799   /* one client found */
800   else if (possibleScanClients.size() == 1)
801   {
802     scanClient = possibleScanClients[0];
803   }
804   /* no clients found */
805   else if (!scanClient)
806   {
807     CGUIDialogOK::ShowAndGetInput(19033,0,19192,0);
808     return;
809   }
810
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();
815
816   /* stop the supervisor thread */
817   g_PVRManager.StopUpdateThreads();
818
819   /* do the scan */
820   if (scanClient->StartChannelScan() != PVR_ERROR_NO_ERROR)
821     /* an error occured */
822     CGUIDialogOK::ShowAndGetInput(19111,0,19193,0);
823
824   /* restart the supervisor thread */
825   g_PVRManager.StartUpdateThreads();
826
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;
830 }
831
832 bool CPVRClients::IsKnownClient(const AddonPtr client) const
833 {
834   // database IDs start at 1
835   return GetClientId(client) > 0;
836 }
837
838 int CPVRClients::RegisterClient(AddonPtr client)
839 {
840   int iClientId(-1);
841   if (!client->Enabled())
842     return -1;
843
844   CLog::Log(LOGDEBUG, "%s - registering add-on '%s'", __FUNCTION__, client->Name().c_str());
845
846   CPVRDatabase *database = GetPVRDatabase();
847   if (!database)
848     return -1;
849
850   // check whether we already know this client
851   iClientId = database->GetClientId(client->ID());
852
853   // try to register the new client in the db
854   if (iClientId < 0 && (iClientId = database->Persist(client)) < 0)
855   {
856     CLog::Log(LOGERROR, "PVR - %s - can't add client '%s' to the database", __FUNCTION__, client->Name().c_str());
857     return -1;
858   }
859
860   PVR_CLIENT addon;
861   // load and initialise the client libraries
862   {
863     CSingleLock lock(m_critSection);
864     PVR_CLIENTMAP_CITR existingClient = m_clientMap.find(iClientId);
865     if (existingClient != m_clientMap.end())
866     {
867       // return existing client
868       addon = existingClient->second;
869     }
870     else
871     {
872       // create a new client instance
873       addon = boost::dynamic_pointer_cast<CPVRClient>(client);
874       m_clientMap.insert(std::make_pair(iClientId, addon));
875     }
876   }
877
878   if (iClientId < 0)
879     CLog::Log(LOGERROR, "PVR - %s - can't register add-on '%s'", __FUNCTION__, client->Name().c_str());
880
881   return iClientId;
882 }
883
884 bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */)
885 {
886   bool bReturn(true);
887   VECADDONS map;
888   VECADDONS disableAddons;
889   {
890     CSingleLock lock(m_critSection);
891     map = m_addons;
892   }
893
894   if (map.size() == 0)
895     return false;
896
897   for (unsigned iClientPtr = 0; iClientPtr < map.size(); iClientPtr++)
898   {
899     const AddonPtr clientAddon = map.at(iClientPtr);
900     bool bEnabled = clientAddon->Enabled() &&
901         !CAddonMgr::Get().IsAddonDisabled(clientAddon->ID());
902
903     if (!bEnabled && IsKnownClient(clientAddon))
904     {
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);
911
912     }
913     else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(clientAddon) || !IsConnectedClient(clientAddon)))
914     {
915       bool bDisabled(false);
916
917       // register the add-on in the pvr db, and create the CPVRClient instance
918       int iClientId = RegisterClient(clientAddon);
919       if (iClientId < 0)
920       {
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);
924         bDisabled = true;
925       }
926       else
927       {
928         ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
929         PVR_CLIENT addon;
930         {
931           CSingleLock lock(m_critSection);
932           if (!GetClient(iClientId, addon))
933           {
934             CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, clientAddon->Name().c_str());
935             disableAddons.push_back(clientAddon);
936             bDisabled = true;
937           }
938         }
939
940         // throttle connection attempts, no more than 1 attempt per 5 seconds
941         if (!bDisabled && addon->Enabled())
942         {
943           time_t now;
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)
947             continue;
948           m_connectionAttempts[iClientId] = now + 5;
949         }
950
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)
953         {
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)
956           {
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);
960             bDisabled = true;
961           }
962         }
963       }
964
965       if (bDisabled && (g_PVRManager.IsStarted() || g_PVRManager.IsInitialising()))
966         CGUIDialogOK::ShowAndGetInput(24070, 24071, 16029, 0);
967     }
968   }
969
970   // disable add-ons that failed to initialise
971   if (disableAddons.size() > 0)
972   {
973     CSingleLock lock(m_critSection);
974     for (VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); it++)
975     {
976       // disable in the add-on db
977       CAddonMgr::Get().DisableAddon((*it)->ID(), true);
978
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);
983     }
984   }
985
986   return bReturn;
987 }
988
989 void CPVRClients::Process(void)
990 {
991   bool bCheckedEnabledClientsOnStartup(false);
992
993   CAddonMgr::Get().RegisterAddonMgrCallback(ADDON_PVRDLL, this);
994   CAddonMgr::Get().RegisterObserver(this);
995
996   UpdateAddons();
997
998   while (!g_application.m_bStop && !m_bStop)
999   {
1000     UpdateAndInitialiseClients();
1001
1002     if (!bCheckedEnabledClientsOnStartup)
1003     {
1004       bCheckedEnabledClientsOnStartup = true;
1005       if (!HasEnabledClients() && !m_bNoAddonWarningDisplayed)
1006         ShowDialogNoClientsEnabled();
1007     }
1008
1009     PVR_CLIENT client;
1010     if (GetPlayingClient(client))
1011       client->UpdateCharInfoSignalStatus();
1012     Sleep(1000);
1013   }
1014 }
1015
1016 void CPVRClients::ShowDialogNoClientsEnabled(void)
1017 {
1018   if (!g_PVRManager.IsStarted() && !g_PVRManager.IsInitialising())
1019     return;
1020
1021   CGUIDialogOK::ShowAndGetInput(19240, 19241, 19242, 19243);
1022
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);
1027 }
1028
1029 void CPVRClients::SaveCurrentChannelSettings(void)
1030 {
1031   CPVRChannelPtr channel;
1032   {
1033     CSingleLock lock(m_critSection);
1034     if (!GetPlayingChannel(channel) || !m_bIsValidChannelSettings)
1035       return;
1036   }
1037
1038   CPVRDatabase *database = GetPVRDatabase();
1039   if (!database)
1040     return;
1041
1042   if (CMediaSettings::Get().GetCurrentVideoSettings() != CMediaSettings::Get().GetDefaultVideoSettings())
1043   {
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());
1047   }
1048   else
1049   {
1050     CLog::Log(LOGDEBUG, "PVR - %s - no custom channel settings for channel '%s'",
1051         __FUNCTION__, channel->ChannelName().c_str());
1052     database->DeleteChannelSettings(*channel);
1053   }
1054 }
1055
1056 void CPVRClients::LoadCurrentChannelSettings(void)
1057 {
1058   CPVRChannelPtr channel;
1059   {
1060     CSingleLock lock(m_critSection);
1061     if (!GetPlayingChannel(channel))
1062       return;
1063   }
1064
1065   CPVRDatabase *database = GetPVRDatabase();
1066   if (!database)
1067     return;
1068
1069   if (g_application.m_pPlayer->HasPlayer())
1070   {
1071     /* store the current settings so we can compare if anything has changed */
1072     CVideoSettings previousSettings = CMediaSettings::Get().GetCurrentVideoSettings();
1073
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;
1078
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);
1082
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);
1086
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);
1090
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);
1095
1096     /* settings can be saved on next channel switch */
1097     m_bIsValidChannelSettings = true;
1098   }
1099 }
1100
1101 bool CPVRClients::UpdateAddons(void)
1102 {
1103   VECADDONS addons;
1104   bool bReturn(CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true));
1105
1106   if (bReturn)
1107   {
1108     CSingleLock lock(m_critSection);
1109     m_addons = addons;
1110   }
1111   
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++)
1114   {
1115     const AddonPtr clientAddon = m_addons.at(iClientPtr);
1116   
1117     if (!m_addonDb.HasAddon(clientAddon->ID()))
1118     {
1119       m_addonDb.AddAddon(clientAddon, -1);
1120     }
1121   }
1122
1123   if ((!bReturn || addons.size() == 0) && !m_bNoAddonWarningDisplayed &&
1124       !CAddonMgr::Get().HasAddons(ADDON_PVRDLL, false) &&
1125       (g_PVRManager.IsStarted() || g_PVRManager.IsInitialising()))
1126   {
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);
1135   }
1136
1137   return bReturn;
1138 }
1139
1140 void CPVRClients::Notify(const Observable &obs, const ObservableMessage msg)
1141 {
1142   if (msg == ObservableMessageAddons)
1143     UpdateAddons();
1144 }
1145
1146 bool CPVRClients::GetClient(const CStdString &strId, AddonPtr &addon) const
1147 {
1148   CSingleLock lock(m_critSection);
1149   for (PVR_CLIENTMAP_CITR itr = m_clientMap.begin(); itr != m_clientMap.end(); itr++)
1150   {
1151     if (itr->second->ID() == strId)
1152     {
1153       addon = itr->second;
1154       return true;
1155     }
1156   }
1157   return false;
1158 }
1159
1160 bool CPVRClients::SupportsChannelGroups(int iClientId) const
1161 {
1162   PVR_CLIENT client;
1163   return GetConnectedClient(iClientId, client) && client->SupportsChannelGroups();
1164 }
1165
1166 bool CPVRClients::SupportsChannelScan(int iClientId) const
1167 {
1168   PVR_CLIENT client;
1169   return GetConnectedClient(iClientId, client) && client->SupportsChannelScan();
1170 }
1171
1172 bool CPVRClients::SupportsEPG(int iClientId) const
1173 {
1174   PVR_CLIENT client;
1175   return GetConnectedClient(iClientId, client) && client->SupportsEPG();
1176 }
1177
1178 bool CPVRClients::SupportsLastPlayedPosition(int iClientId) const
1179 {
1180   PVR_CLIENT client;
1181   return GetConnectedClient(iClientId, client) && client->SupportsLastPlayedPosition();
1182 }
1183
1184 bool CPVRClients::SupportsRadio(int iClientId) const
1185 {
1186   PVR_CLIENT client;
1187   return GetConnectedClient(iClientId, client) && client->SupportsRadio();
1188 }
1189
1190 bool CPVRClients::SupportsRecordings(int iClientId) const
1191 {
1192   PVR_CLIENT client;
1193   return GetConnectedClient(iClientId, client) && client->SupportsRecordings();
1194 }
1195
1196 bool CPVRClients::SupportsRecordingFolders(int iClientId) const
1197 {
1198   PVR_CLIENT client;
1199   return GetConnectedClient(iClientId, client) && client->SupportsRecordingFolders();
1200 }
1201
1202 bool CPVRClients::SupportsRecordingPlayCount(int iClientId) const
1203 {
1204   PVR_CLIENT client;
1205   return GetConnectedClient(iClientId, client) && client->SupportsRecordingPlayCount();
1206 }
1207
1208 bool CPVRClients::SupportsRecordingEdl(int iClientId) const
1209 {
1210   PVR_CLIENT client;
1211   return GetConnectedClient(iClientId, client) && client->SupportsRecordingEdl();
1212 }
1213
1214 bool CPVRClients::SupportsTimers(int iClientId) const
1215 {
1216   PVR_CLIENT client;
1217   return GetConnectedClient(iClientId, client) && client->SupportsTimers();
1218 }
1219
1220 bool CPVRClients::SupportsTV(int iClientId) const
1221 {
1222   PVR_CLIENT client;
1223   return GetConnectedClient(iClientId, client) && client->SupportsTV();
1224 }
1225
1226 bool CPVRClients::HandlesDemuxing(int iClientId) const
1227 {
1228   PVR_CLIENT client;
1229   return GetConnectedClient(iClientId, client) && client->HandlesDemuxing();
1230 }
1231
1232 bool CPVRClients::HandlesInputStream(int iClientId) const
1233 {
1234   PVR_CLIENT client;
1235   return GetConnectedClient(iClientId, client) && client->HandlesInputStream();
1236 }
1237
1238 bool CPVRClients::GetPlayingClient(PVR_CLIENT &client) const
1239 {
1240   return GetConnectedClient(GetPlayingClientID(), client);
1241 }
1242
1243 bool CPVRClients::OpenStream(const CPVRChannel &tag, bool bIsSwitchingChannel)
1244 {
1245   bool bReturn(false);
1246   CloseStream();
1247
1248   /* try to open the stream on the client */
1249   PVR_CLIENT client;
1250   if (GetConnectedClient(tag.ClientID(), client) &&
1251       client->OpenStream(tag, bIsSwitchingChannel))
1252   {
1253     CSingleLock lock(m_critSection);
1254     m_playingClientId = tag.ClientID();
1255     m_bIsPlayingLiveTV = true;
1256
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();
1261     else
1262       m_strPlayingClientName = g_localizeStrings.Get(13205);
1263
1264     bReturn = true;
1265   }
1266
1267   return bReturn;
1268 }
1269
1270 bool CPVRClients::OpenStream(const CPVRRecording &tag)
1271 {
1272   bool bReturn(false);
1273   CloseStream();
1274
1275   /* try to open the recording stream on the client */
1276   PVR_CLIENT client;
1277   if (GetConnectedClient(tag.m_iClientId, client) &&
1278       client->OpenStream(tag))
1279   {
1280     CSingleLock lock(m_critSection);
1281     m_playingClientId = tag.m_iClientId;
1282     m_bIsPlayingRecording = true;
1283     m_strPlayingClientName = client->GetFriendlyName();
1284     bReturn = true;
1285   }
1286
1287   return bReturn;
1288 }
1289
1290 void CPVRClients::CloseStream(void)
1291 {
1292   PVR_CLIENT playingClient;
1293   if (GetPlayingClient(playingClient))
1294     playingClient->CloseStream();
1295
1296   CSingleLock lock(m_critSection);
1297   m_bIsPlayingLiveTV     = false;
1298   m_bIsPlayingRecording  = false;
1299   m_playingClientId      = PVR_INVALID_CLIENT_ID;
1300   m_strPlayingClientName = "";
1301 }
1302
1303 int CPVRClients::ReadStream(void* lpBuf, int64_t uiBufSize)
1304 {
1305   PVR_CLIENT client;
1306   if (GetPlayingClient(client))
1307     return client->ReadStream(lpBuf, uiBufSize);
1308   return -EINVAL;
1309 }
1310
1311 int64_t CPVRClients::GetStreamLength(void)
1312 {
1313   PVR_CLIENT client;
1314   if (GetPlayingClient(client))
1315     return client->GetStreamLength();
1316   return -EINVAL;
1317 }
1318
1319 int64_t CPVRClients::SeekStream(int64_t iFilePosition, int iWhence/* = SEEK_SET*/)
1320 {
1321   PVR_CLIENT client;
1322   if (GetPlayingClient(client))
1323     return client->SeekStream(iFilePosition, iWhence);
1324   return -EINVAL;
1325 }
1326
1327 int64_t CPVRClients::GetStreamPosition(void)
1328 {
1329   PVR_CLIENT client;
1330   if (GetPlayingClient(client))
1331     return client->GetStreamPosition();
1332   return -EINVAL;
1333 }
1334
1335 void CPVRClients::PauseStream(bool bPaused)
1336 {
1337   PVR_CLIENT client;
1338   if (GetPlayingClient(client))
1339     client->PauseStream(bPaused);
1340 }
1341
1342 CStdString CPVRClients::GetCurrentInputFormat(void) const
1343 {
1344   CStdString strReturn;
1345   CPVRChannelPtr currentChannel;
1346   if (GetPlayingChannel(currentChannel))
1347     strReturn = currentChannel->InputFormat();
1348
1349   return strReturn;
1350 }
1351
1352 PVR_STREAM_PROPERTIES CPVRClients::GetCurrentStreamProperties(void)
1353 {
1354   PVR_STREAM_PROPERTIES props;
1355   PVR_CLIENT client;
1356   
1357   memset(&props, 0, sizeof(props));
1358   if (GetPlayingClient(client))
1359     client->GetStreamProperties(&props);
1360
1361   return props;
1362 }
1363
1364 bool CPVRClients::IsPlaying(void) const
1365 {
1366   CSingleLock lock(m_critSection);
1367   return m_bIsPlayingRecording || m_bIsPlayingLiveTV;
1368 }
1369
1370 bool CPVRClients::IsPlayingRadio(void) const
1371 {
1372   PVR_CLIENT client;
1373   if (GetPlayingClient(client))
1374     return client->IsPlayingLiveRadio();
1375   return false;
1376 }
1377
1378 bool CPVRClients::IsPlayingTV(void) const
1379 {
1380   PVR_CLIENT client;
1381   if (GetPlayingClient(client))
1382     return client->IsPlayingLiveTV();
1383   return false;
1384 }
1385
1386 bool CPVRClients::IsPlayingRecording(void) const
1387 {
1388   CSingleLock lock(m_critSection);
1389   return m_bIsPlayingRecording;
1390 }
1391
1392 bool CPVRClients::IsReadingLiveStream(void) const
1393 {
1394   CSingleLock lock(m_critSection);
1395   return m_bIsPlayingLiveTV;
1396 }
1397
1398 bool CPVRClients::IsEncrypted(void) const
1399 {
1400   PVR_CLIENT client;
1401   if (GetPlayingClient(client))
1402     return client->IsPlayingEncryptedChannel();
1403   return false;
1404 }
1405
1406 time_t CPVRClients::GetPlayingTime() const
1407 {
1408   PVR_CLIENT client;
1409   time_t time = 0;
1410
1411   if (GetPlayingClient(client))
1412   {
1413      time = client->GetPlayingTime();
1414   }
1415
1416   return time;
1417 }
1418
1419 time_t CPVRClients::GetBufferTimeStart() const
1420 {
1421   PVR_CLIENT client;
1422   time_t time = 0;
1423
1424   if (GetPlayingClient(client))
1425   {
1426     time = client->GetBufferTimeStart();
1427   }
1428
1429   return time;
1430 }
1431
1432 time_t CPVRClients::GetBufferTimeEnd() const
1433 {
1434   PVR_CLIENT client;
1435   time_t time = 0;
1436
1437   if (GetPlayingClient(client))
1438   {
1439     time = client->GetBufferTimeEnd();
1440   }
1441
1442   return time;
1443 }