40
44
CPVRClient::CPVRClient(const AddonProps& props) :
41
45
CAddonDll<DllPVRClient, PVRClient, PVR_PROPERTIES>(props),
46
m_apiVersion("0.0.0"),
47
m_bAvahiServiceAdded(false)
47
52
CPVRClient::CPVRClient(const cp_extension_t *ext) :
48
53
CAddonDll<DllPVRClient, PVRClient, PVR_PROPERTIES>(ext),
54
m_apiVersion("0.0.0"),
55
m_bAvahiServiceAdded(false)
59
m_strAvahiType = CAddonMgr::Get().GetExtValue(ext->configuration, "@avahi_type");
60
m_strAvahiIpSetting = CAddonMgr::Get().GetExtValue(ext->configuration, "@avahi_ip_setting");
61
m_strAvahiPortSetting = CAddonMgr::Get().GetExtValue(ext->configuration, "@avahi_port_setting");
62
m_bNeedsConfiguration = !(CAddonMgr::Get().GetExtValue(ext->configuration, "@needs_configuration") == "false");
54
65
CPVRClient::~CPVRClient(void)
67
if (m_bAvahiServiceAdded)
68
CZeroconfBrowser::GetInstance()->RemoveServiceType(m_strAvahiType);
57
70
SAFE_DELETE(m_pInfo);
60
73
void CPVRClient::OnDisabled()
62
75
// restart the PVR manager if we're disabling a client
63
if (CPVRManager::Get().IsStarted())
76
if (CPVRManager::Get().IsStarted() && CPVRManager::Get().RestartManagerOnAddonDisabled())
64
77
CPVRManager::Get().Start(true);
67
80
void CPVRClient::OnEnabled()
69
82
// restart the PVR manager if we're enabling a client
70
CPVRManager::Get().Start(true);
83
if (CPVRManager::Get().RestartManagerOnAddonDisabled())
84
CPVRManager::Get().Start(true);
73
87
AddonPtr CPVRClient::GetRunningInstance() const
81
95
return CAddon::GetRunningInstance();
84
bool CPVRClient::OnPreInstall()
98
void CPVRClient::OnPreInstall()
86
100
// stop the pvr manager, so running pvr add-ons are stopped and closed
87
101
PVR::CPVRManager::Get().Stop();
91
void CPVRClient::OnPostInstall(bool restart, bool update)
104
void CPVRClient::OnPostInstall(bool update, bool modal)
93
106
// (re)start the pvr manager
94
107
PVR::CPVRManager::Get().Start(true);
132
145
m_strConnectionString = DEFAULT_INFO_STRING_VALUE;
133
146
m_strFriendlyName = DEFAULT_INFO_STRING_VALUE;
134
147
m_strBackendName = DEFAULT_INFO_STRING_VALUE;
148
m_strBackendHostname.clear();
135
149
m_bIsPlayingTV = false;
136
150
m_bIsPlayingRecording = false;
137
151
memset(&m_addonCapabilities, 0, sizeof(m_addonCapabilities));
138
ResetQualityData(m_qualityInfo);
139
152
m_apiVersion = AddonVersion("0.0.0");
142
155
ADDON_STATUS CPVRClient::Create(int iClientId)
144
157
ADDON_STATUS status(ADDON_STATUS_UNKNOWN);
145
if (iClientId <= PVR_INVALID_CLIENT_ID || iClientId == PVR_VIRTUAL_CLIENT_ID)
158
if (iClientId <= PVR_INVALID_CLIENT_ID)
148
161
/* ensure that a previous instance is destroyed */
246
259
addonRecording.iLifetime = xbmcRecording.m_iLifetime;
247
260
addonRecording.iPlayCount = xbmcRecording.m_playCount;
248
261
addonRecording.iLastPlayedPosition = (int)xbmcRecording.m_resumePoint.timeInSeconds;
262
addonRecording.bIsDeleted = xbmcRecording.IsDeleted();
249
263
strncpy(addonRecording.strDirectory, xbmcRecording.m_strDirectory.c_str(), sizeof(addonRecording.strDirectory) - 1);
250
264
strncpy(addonRecording.strStreamURL, xbmcRecording.m_strStreamURL.c_str(), sizeof(addonRecording.strStreamURL) - 1);
251
265
strncpy(addonRecording.strIconPath, xbmcRecording.m_strIconPath.c_str(), sizeof(addonRecording.strIconPath) - 1);
294
308
* @param xbmcChannel The channel on XBMC's side.
295
309
* @param addonChannel The channel on the addon's side.
297
void CPVRClient::WriteClientChannelInfo(const CPVRChannel &xbmcChannel, PVR_CHANNEL &addonChannel)
311
void CPVRClient::WriteClientChannelInfo(const CPVRChannelPtr &xbmcChannel, PVR_CHANNEL &addonChannel)
313
assert(xbmcChannel.get());
299
315
memset(&addonChannel, 0, sizeof(addonChannel));
301
addonChannel.iUniqueId = xbmcChannel.UniqueID();
302
addonChannel.iChannelNumber = xbmcChannel.ClientChannelNumber();
303
addonChannel.iSubChannelNumber = xbmcChannel.ClientSubChannelNumber();
304
strncpy(addonChannel.strChannelName, xbmcChannel.ClientChannelName().c_str(), sizeof(addonChannel.strChannelName) - 1);
305
strncpy(addonChannel.strIconPath, xbmcChannel.IconPath().c_str(), sizeof(addonChannel.strIconPath) - 1);
306
addonChannel.iEncryptionSystem = xbmcChannel.EncryptionSystem();
307
addonChannel.bIsRadio = xbmcChannel.IsRadio();
308
addonChannel.bIsHidden = xbmcChannel.IsHidden();
309
strncpy(addonChannel.strInputFormat, xbmcChannel.InputFormat().c_str(), sizeof(addonChannel.strInputFormat) - 1);
310
strncpy(addonChannel.strStreamURL, xbmcChannel.StreamURL().c_str(), sizeof(addonChannel.strStreamURL) - 1);
317
addonChannel.iUniqueId = xbmcChannel->UniqueID();
318
addonChannel.iChannelNumber = xbmcChannel->ClientChannelNumber();
319
addonChannel.iSubChannelNumber = xbmcChannel->ClientSubChannelNumber();
320
strncpy(addonChannel.strChannelName, xbmcChannel->ClientChannelName().c_str(), sizeof(addonChannel.strChannelName) - 1);
321
strncpy(addonChannel.strIconPath, xbmcChannel->IconPath().c_str(), sizeof(addonChannel.strIconPath) - 1);
322
addonChannel.iEncryptionSystem = xbmcChannel->EncryptionSystem();
323
addonChannel.bIsRadio = xbmcChannel->IsRadio();
324
addonChannel.bIsHidden = xbmcChannel->IsHidden();
325
strncpy(addonChannel.strInputFormat, xbmcChannel->InputFormat().c_str(), sizeof(addonChannel.strInputFormat) - 1);
326
strncpy(addonChannel.strStreamURL, xbmcChannel->StreamURL().c_str(), sizeof(addonChannel.strStreamURL) - 1);
313
329
bool CPVRClient::IsCompatibleAPIVersion(const ADDON::AddonVersion &minVersion, const ADDON::AddonVersion &version)
355
371
bool CPVRClient::GetAddonProperties(void)
357
std::string strBackendName, strConnectionString, strFriendlyName, strBackendVersion;
373
std::string strBackendName, strConnectionString, strFriendlyName, strBackendVersion, strBackendHostname;
358
374
PVR_ADDON_CAPABILITIES addonCapabilities;
360
376
/* get the capabilities */
385
401
try { strBackendVersion = m_pStruct->GetBackendVersion(); }
386
402
catch (std::exception &e) { LogException(e, "GetBackendVersion()"); return false; }
404
/* backend hostname */
405
try { strBackendHostname = m_pStruct->GetBackendHostname(); }
406
catch (std::exception &e) { LogException(e, "GetBackendHostname()"); return false; }
388
408
/* update the members */
389
409
m_strBackendName = strBackendName;
390
410
m_strConnectionString = strConnectionString;
391
411
m_strFriendlyName = strFriendlyName;
392
412
m_strBackendVersion = strBackendVersion;
393
413
m_addonCapabilities = addonCapabilities;
414
m_strBackendHostname = strBackendHostname;
444
470
if (!m_addonCapabilities.bSupportsChannelScan)
445
471
return PVR_ERROR_NOT_IMPLEMENTED;
447
try { return m_pStruct->DialogChannelScan(); }
473
try { return m_pStruct->OpenDialogChannelScan(); }
448
474
catch (std::exception &e) { LogException(e, __FUNCTION__); }
450
476
return PVR_ERROR_UNKNOWN;
479
PVR_ERROR CPVRClient::OpenDialogChannelAdd(const CPVRChannelPtr &channel)
482
return PVR_ERROR_REJECTED;
484
if (!m_addonCapabilities.bSupportsChannelSettings)
485
return PVR_ERROR_NOT_IMPLEMENTED;
487
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
490
PVR_CHANNEL addonChannel;
491
WriteClientChannelInfo(channel, addonChannel);
493
retVal = m_pStruct->OpenDialogChannelAdd(addonChannel);
494
LogError(retVal, __FUNCTION__);
496
catch (std::exception &e)
498
LogException(e, __FUNCTION__);
504
PVR_ERROR CPVRClient::OpenDialogChannelSettings(const CPVRChannelPtr &channel)
507
return PVR_ERROR_REJECTED;
509
if (!m_addonCapabilities.bSupportsChannelSettings)
510
return PVR_ERROR_NOT_IMPLEMENTED;
512
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
515
PVR_CHANNEL addonChannel;
516
WriteClientChannelInfo(channel, addonChannel);
518
retVal = m_pStruct->OpenDialogChannelSettings(addonChannel);
519
LogError(retVal, __FUNCTION__);
521
catch (std::exception &e)
523
LogException(e, __FUNCTION__);
529
PVR_ERROR CPVRClient::DeleteChannel(const CPVRChannelPtr &channel)
532
return PVR_ERROR_REJECTED;
534
if (!m_addonCapabilities.bSupportsChannelSettings)
535
return PVR_ERROR_NOT_IMPLEMENTED;
537
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
540
PVR_CHANNEL addonChannel;
541
WriteClientChannelInfo(channel, addonChannel);
543
retVal = m_pStruct->DeleteChannel(addonChannel);
544
LogError(retVal, __FUNCTION__);
546
catch (std::exception &e)
548
LogException(e, __FUNCTION__);
554
PVR_ERROR CPVRClient::RenameChannel(const CPVRChannelPtr &channel)
557
return PVR_ERROR_REJECTED;
559
if (!m_addonCapabilities.bSupportsChannelSettings)
560
return PVR_ERROR_NOT_IMPLEMENTED;
562
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
565
PVR_CHANNEL addonChannel;
566
WriteClientChannelInfo(channel, addonChannel);
568
retVal = m_pStruct->RenameChannel(addonChannel);
569
LogError(retVal, __FUNCTION__);
571
catch (std::exception &e)
573
LogException(e, __FUNCTION__);
453
579
void CPVRClient::CallMenuHook(const PVR_MENUHOOK &hook, const CFileItem *item)
455
581
if (!m_bReadyToUse)
469
595
else if (item->IsPVRChannel())
471
597
hookData.cat = PVR_MENUHOOK_CHANNEL;
472
WriteClientChannelInfo(*item->GetPVRChannelInfoTag(), hookData.data.channel);
598
WriteClientChannelInfo(item->GetPVRChannelInfoTag(), hookData.data.channel);
474
else if (item->IsPVRRecording())
600
else if (item->IsUsablePVRRecording())
476
602
hookData.cat = PVR_MENUHOOK_RECORDING;
477
603
WriteClientRecordingInfo(*item->GetPVRRecordingInfoTag(), hookData.data.recording);
605
else if (item->IsDeletedPVRRecording())
607
hookData.cat = PVR_MENUHOOK_DELETED_RECORDING;
608
WriteClientRecordingInfo(*item->GetPVRRecordingInfoTag(), hookData.data.recording);
479
610
else if (item->IsPVRTimer())
481
612
hookData.cat = PVR_MENUHOOK_TIMER;
488
619
catch (std::exception &e) { LogException(e, __FUNCTION__); }
491
PVR_ERROR CPVRClient::GetEPGForChannel(const CPVRChannel &channel, CEpg *epg, time_t start /* = 0 */, time_t end /* = 0 */, bool bSaveInDb /* = false*/)
622
PVR_ERROR CPVRClient::GetEPGForChannel(const CPVRChannelPtr &channel, CEpg *epg, time_t start /* = 0 */, time_t end /* = 0 */, bool bSaveInDb /* = false*/)
493
624
if (!m_bReadyToUse)
494
625
return PVR_ERROR_REJECTED;
638
int CPVRClient::GetRecordingsAmount(void)
769
int CPVRClient::GetRecordingsAmount(bool deleted)
640
771
int iReturn(-EINVAL);
642
if (m_addonCapabilities.bSupportsRecordings)
644
try { iReturn = m_pStruct->GetRecordingsAmount(); }
645
catch (std::exception &e) { LogException(e, __FUNCTION__); }
773
if (!m_addonCapabilities.bSupportsRecordings || (deleted && !m_addonCapabilities.bSupportsRecordingsUndelete))
778
iReturn = m_pStruct->GetRecordingsAmount(deleted);
780
catch (std::exception &e)
782
LogException(e, __FUNCTION__);
651
PVR_ERROR CPVRClient::GetRecordings(CPVRRecordings *results)
788
PVR_ERROR CPVRClient::GetRecordings(CPVRRecordings *results, bool deleted)
653
790
if (!m_bReadyToUse)
654
791
return PVR_ERROR_REJECTED;
656
if (!m_addonCapabilities.bSupportsRecordings)
793
if (!m_addonCapabilities.bSupportsRecordings || (deleted && !m_addonCapabilities.bSupportsRecordingsUndelete))
657
794
return PVR_ERROR_NOT_IMPLEMENTED;
659
796
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
840
PVR_ERROR CPVRClient::UndeleteRecording(const CPVRRecording &recording)
843
return PVR_ERROR_REJECTED;
845
if (!m_addonCapabilities.bSupportsRecordingsUndelete)
846
return PVR_ERROR_NOT_IMPLEMENTED;
848
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
852
WriteClientRecordingInfo(recording, tag);
854
retVal = m_pStruct->UndeleteRecording(tag);
856
LogError(retVal, __FUNCTION__);
858
catch (std::exception &e)
860
LogException(e, __FUNCTION__);
866
PVR_ERROR CPVRClient::DeleteAllRecordingsFromTrash()
869
return PVR_ERROR_REJECTED;
871
if (!m_addonCapabilities.bSupportsRecordingsUndelete)
872
return PVR_ERROR_NOT_IMPLEMENTED;
874
PVR_ERROR retVal(PVR_ERROR_UNKNOWN);
877
retVal = m_pStruct->DeleteAllRecordingsFromTrash();
879
LogError(retVal, __FUNCTION__);
881
catch (std::exception &e)
883
LogException(e, __FUNCTION__);
703
889
PVR_ERROR CPVRClient::RenameRecording(const CPVRRecording &recording)
705
891
if (!m_bReadyToUse)
1238
1423
CLog::Log(LOGERROR, "PVR - exception '%s' caught while trying to call '%s' on add-on '%s'. Please contact the developer of this add-on: %s", e.what(), strFunctionName, GetFriendlyName().c_str(), Author().c_str());
1241
bool CPVRClient::CanPlayChannel(const CPVRChannel &channel) const
1426
bool CPVRClient::CanPlayChannel(const CPVRChannelPtr &channel) const
1428
assert(channel.get());
1243
1430
return (m_bReadyToUse &&
1244
((m_addonCapabilities.bSupportsTV && !channel.IsRadio()) ||
1245
(m_addonCapabilities.bSupportsRadio && channel.IsRadio())));
1431
((m_addonCapabilities.bSupportsTV && !channel->IsRadio()) ||
1432
(m_addonCapabilities.bSupportsRadio && channel->IsRadio())));
1248
1435
bool CPVRClient::SupportsChannelGroups(void) const
1346
1543
IsPlayingRecording();
1349
bool CPVRClient::GetPlayingChannel(CPVRChannelPtr &channel) const
1546
CPVRChannelPtr CPVRClient::GetPlayingChannel() const
1351
1548
CSingleLock lock(m_critSection);
1352
1549
if (m_bReadyToUse && m_bIsPlayingTV)
1354
channel = m_playingChannel;
1550
return m_playingChannel;
1552
return CPVRChannelPtr();
1360
bool CPVRClient::GetPlayingRecording(CPVRRecording &recording) const
1555
CPVRRecordingPtr CPVRClient::GetPlayingRecording(void) const
1362
1557
CSingleLock lock(m_critSection);
1363
1558
if (m_bReadyToUse && m_bIsPlayingRecording)
1365
recording = m_playingRecording;
1559
return m_playingRecording;
1561
return CPVRRecordingPtr();
1371
bool CPVRClient::OpenStream(const CPVRChannel &channel, bool bIsSwitchingChannel)
1564
bool CPVRClient::OpenStream(const CPVRChannelPtr &channel, bool bIsSwitchingChannel)
1373
1566
bool bReturn(false);
1376
1569
if(!CanPlayChannel(channel))
1378
CLog::Log(LOGDEBUG, "add-on '%s' can not play channel '%s'", GetFriendlyName().c_str(), channel.ChannelName().c_str());
1571
CLog::Log(LOGDEBUG, "add-on '%s' can not play channel '%s'", GetFriendlyName().c_str(), channel->ChannelName().c_str());
1380
else if (!channel.StreamURL().empty())
1573
else if (!channel->StreamURL().empty())
1382
CLog::Log(LOGDEBUG, "opening live stream on url '%s'", channel.StreamURL().c_str());
1575
CLog::Log(LOGDEBUG, "opening live stream on url '%s'", channel->StreamURL().c_str());
1383
1576
bReturn = true;
1385
1578
// the Njoy N7 sometimes doesn't switch channels, but opens a stream to the previous channel
1513
1706
return bReturn;
1516
void CPVRClient::ResetQualityData(PVR_SIGNAL_STATUS &qualityInfo)
1518
memset(&qualityInfo, 0, sizeof(qualityInfo));
1519
if (CSettings::Get().GetBool("pvrplayback.signalquality"))
1521
strncpy(qualityInfo.strAdapterName, g_localizeStrings.Get(13205).c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
1522
strncpy(qualityInfo.strAdapterStatus, g_localizeStrings.Get(13205).c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
1526
strncpy(qualityInfo.strAdapterName, g_localizeStrings.Get(13106).c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
1527
strncpy(qualityInfo.strAdapterStatus, g_localizeStrings.Get(13106).c_str(), PVR_ADDON_NAME_STRING_LENGTH - 1);
1531
void CPVRClient::GetQualityData(PVR_SIGNAL_STATUS *status) const
1533
CSingleLock lock(m_critSection);
1534
*status = m_qualityInfo;
1537
int CPVRClient::GetSignalLevel(void) const
1539
CSingleLock lock(m_critSection);
1540
return (int) ((float) m_qualityInfo.iSignal / 0xFFFF * 100);
1543
int CPVRClient::GetSNR(void) const
1545
CSingleLock lock(m_critSection);
1546
return (int) ((float) m_qualityInfo.iSNR / 0xFFFF * 100);
1549
void CPVRClient::UpdateCharInfoSignalStatus(void)
1551
PVR_SIGNAL_STATUS qualityInfo;
1552
ResetQualityData(qualityInfo);
1554
if (CSettings::Get().GetBool("pvrplayback.signalquality"))
1555
SignalQuality(qualityInfo);
1557
CSingleLock lock(m_critSection);
1558
m_qualityInfo = qualityInfo;
1561
1709
time_t CPVRClient::GetPlayingTime(void) const
1563
1711
time_t time = 0;
1756
bool CPVRClient::CanAutoconfigure(void) const
1758
/** can only auto-configure when avahi details are provided in addon.xml */
1759
return !m_strAvahiType.empty() &&
1760
!m_strAvahiIpSetting.empty() &&
1761
!m_strAvahiPortSetting.empty();
1764
bool CPVRClient::AutoconfigureRegisterType(void)
1766
if (!m_strAvahiType.empty())
1768
// AddServiceType() returns false when already registered
1769
m_bAvahiServiceAdded |= CZeroconfBrowser::GetInstance()->AddServiceType(m_strAvahiType);
1776
bool CPVRClient::Autoconfigure(void)
1778
bool bReturn(false);
1780
if (!CanAutoconfigure())
1783
std::string strHostPort;
1784
std::vector<CZeroconfBrowser::ZeroconfService> found_services = CZeroconfBrowser::GetInstance()->GetFoundServices();
1785
for(std::vector<CZeroconfBrowser::ZeroconfService>::iterator it = found_services.begin(); !bReturn && it != found_services.end(); ++it)
1787
/** found the type that we are looking for */
1788
if ((*it).GetType() == m_strAvahiType && std::find(m_rejectedAvahiHosts.begin(), m_rejectedAvahiHosts.end(), *it) == m_rejectedAvahiHosts.end())
1790
/** try to resolve */
1791
if(!CZeroconfBrowser::GetInstance()->ResolveService((*it)))
1793
CLog::Log(LOGWARNING, "%s - %s service found but the host name couldn't be resolved", __FUNCTION__, (*it).GetName().c_str());
1797
// %s service found at %s
1798
std::string strLogLine(StringUtils::Format(g_localizeStrings.Get(19689).c_str(), (*it).GetName().c_str(), (*it).GetIP().c_str()));
1799
CLog::Log(LOGDEBUG, "%s - %s", __FUNCTION__, strLogLine.c_str());
1801
if (!CGUIDialogYesNo::ShowAndGetInput(19688, // Scanning for PVR services
1803
19690, // Do you want to use this service?
1806
CLog::Log(LOGDEBUG, "%s - %s service found but not enabled by the user", __FUNCTION__, (*it).GetName().c_str());
1807
m_rejectedAvahiHosts.push_back(*it);
1811
/** update the settings and return */
1812
std::string strPort(StringUtils::Format("%d", (*it).GetPort()));
1813
UpdateSetting(m_strAvahiIpSetting, (*it).GetIP());
1814
UpdateSetting(m_strAvahiPortSetting, strPort);
1816
CLog::Log(LOGNOTICE, "%s - auto-configured %s using host '%s' and port '%d'", __FUNCTION__, (*it).GetName().c_str(), (*it).GetIP().c_str(), (*it).GetPort());