2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
11 #include "ServiceBroker.h"
12 #include "addons/AddonManager.h"
13 #include "addons/binary-addons/AddonDll.h"
14 #include "cores/EdlEdit.h"
15 #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h"
16 #include "dialogs/GUIDialogKaiToast.h" //! @todo get rid of GUI in core
17 #include "events/EventLog.h"
18 #include "events/NotificationEvent.h"
19 #include "filesystem/SpecialProtocol.h"
20 #include "guilib/LocalizeStrings.h"
21 #include "pvr/PVRConstants.h" // PVR_CLIENT_INVALID_UID
22 #include "pvr/PVRDatabase.h"
23 #include "pvr/PVRDescrambleInfo.h"
24 #include "pvr/PVRManager.h"
25 #include "pvr/PVRSignalStatus.h"
26 #include "pvr/PVRStreamProperties.h"
27 #include "pvr/addons/PVRClientMenuHooks.h"
28 #include "pvr/addons/PVRClients.h"
29 #include "pvr/channels/PVRChannel.h"
30 #include "pvr/channels/PVRChannelGroup.h"
31 #include "pvr/channels/PVRChannelGroupFactory.h"
32 #include "pvr/channels/PVRChannelGroupMember.h"
33 #include "pvr/channels/PVRChannelGroups.h"
34 #include "pvr/channels/PVRChannelGroupsContainer.h"
35 #include "pvr/epg/Epg.h"
36 #include "pvr/epg/EpgContainer.h"
37 #include "pvr/epg/EpgInfoTag.h"
38 #include "pvr/providers/PVRProvider.h"
39 #include "pvr/providers/PVRProviders.h"
40 #include "pvr/recordings/PVRRecording.h"
41 #include "pvr/recordings/PVRRecordings.h"
42 #include "pvr/timers/PVRTimerInfoTag.h"
43 #include "pvr/timers/PVRTimerType.h"
44 #include "pvr/timers/PVRTimers.h"
45 #include "settings/AdvancedSettings.h"
46 #include "settings/SettingsComponent.h"
47 #include "utils/StringUtils.h"
48 #include "utils/log.h"
59 #include <libavcodec/avcodec.h>
62 using namespace ADDON
;
67 class CAddonChannelGroup
: public PVR_CHANNEL_GROUP
70 explicit CAddonChannelGroup(const CPVRChannelGroup
& group
) : m_groupName(group
.ClientGroupName())
72 // zero-init base struct members
73 PVR_CHANNEL_GROUP
* base
= static_cast<PVR_CHANNEL_GROUP
*>(this);
76 bIsRadio
= group
.IsRadio();
77 strGroupName
= m_groupName
.c_str();
78 iPosition
= group
.GetClientPosition();
80 virtual ~CAddonChannelGroup() = default;
83 const std::string m_groupName
;
86 class CAddonChannel
: public PVR_CHANNEL
89 explicit CAddonChannel(const CPVRChannel
& channel
, const std::string
& newChannelName
= "")
90 : m_channelName(newChannelName
.empty() ? channel
.ClientChannelName() : newChannelName
),
91 m_mimeType(channel
.MimeType()),
92 m_iconPath(channel
.ClientIconPath())
94 // zero-init base struct members
95 PVR_CHANNEL
* base
= static_cast<PVR_CHANNEL
*>(this);
98 iUniqueId
= channel
.UniqueID();
99 iChannelNumber
= channel
.ClientChannelNumber().GetChannelNumber();
100 iSubChannelNumber
= channel
.ClientChannelNumber().GetSubChannelNumber();
101 strChannelName
= m_channelName
.c_str();
102 strIconPath
= m_iconPath
.c_str();
103 iEncryptionSystem
= channel
.EncryptionSystem();
104 bIsRadio
= channel
.IsRadio();
105 bIsHidden
= channel
.IsHidden();
106 strMimeType
= m_mimeType
.c_str();
107 iClientProviderUid
= channel
.ClientProviderUid();
108 bHasArchive
= channel
.HasArchive();
110 virtual ~CAddonChannel() = default;
113 const std::string m_channelName
;
114 const std::string m_mimeType
;
115 const std::string m_iconPath
;
118 class CAddonRecording
: public PVR_RECORDING
121 explicit CAddonRecording(const CPVRRecording
& recording
)
122 : m_recordingId(recording
.ClientRecordingID()),
123 m_title(recording
.m_strTitle
),
124 m_titleExtraInfo(recording
.TitleExtraInfo()),
125 m_episodeName(recording
.m_strShowTitle
),
126 m_directory(recording
.Directory()),
127 m_plotOutline(recording
.m_strPlotOutline
),
128 m_plot(recording
.m_strPlot
),
129 m_genreDescription(recording
.GetGenresLabel()),
130 m_channelName(recording
.ChannelName()),
131 m_iconPath(recording
.ClientIconPath()),
132 m_thumbnailPath(recording
.ClientThumbnailPath()),
133 m_fanartPath(recording
.ClientFanartPath()),
134 m_firstAired(recording
.FirstAired().IsValid() ? recording
.FirstAired().GetAsW3CDate() : ""),
135 m_providerName(recording
.ProviderName()),
136 m_parentalRatingCode(recording
.GetParentalRatingCode()),
137 m_parentalRatingIcon(recording
.ClientParentalRatingIconPath()),
138 m_parentalRatingSource(recording
.GetParentalRatingSource())
140 // zero-init base struct members
141 PVR_RECORDING
* base
= static_cast<PVR_RECORDING
*>(this);
145 recording
.RecordingTimeAsUTC().GetAsTime(recTime
);
147 strRecordingId
= m_recordingId
.c_str();
148 strTitle
= m_title
.c_str();
149 strTitleExtraInfo
= m_titleExtraInfo
.c_str();
150 strEpisodeName
= m_episodeName
.c_str();
151 iSeriesNumber
= recording
.m_iSeason
;
152 iEpisodeNumber
= recording
.m_iEpisode
;
153 iEpisodePartNumber
= recording
.EpisodePart();
154 iYear
= recording
.GetYear();
155 strDirectory
= m_directory
.c_str();
156 strPlotOutline
= m_plotOutline
.c_str();
157 strPlot
= m_plot
.c_str();
158 strGenreDescription
= m_genreDescription
.c_str();
159 strChannelName
= m_channelName
.c_str();
160 strIconPath
= m_iconPath
.c_str();
161 strThumbnailPath
= m_thumbnailPath
.c_str();
162 strFanartPath
= m_fanartPath
.c_str();
165 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection
;
166 iDuration
= recording
.GetDuration();
167 iPriority
= recording
.Priority();
168 iLifetime
= recording
.LifeTime();
169 iGenreType
= recording
.GenreType();
170 iGenreSubType
= recording
.GenreSubType();
171 iPlayCount
= recording
.GetLocalPlayCount();
172 iLastPlayedPosition
=
173 static_cast<int>(std::lrint(recording
.GetLocalResumePoint().timeInSeconds
));
174 bIsDeleted
= recording
.IsDeleted();
175 iEpgEventId
= recording
.BroadcastUid();
176 iChannelUid
= recording
.ChannelUid();
178 recording
.IsRadio() ? PVR_RECORDING_CHANNEL_TYPE_RADIO
: PVR_RECORDING_CHANNEL_TYPE_TV
;
179 strFirstAired
= m_firstAired
.c_str();
180 iFlags
= recording
.Flags();
181 sizeInBytes
= recording
.GetSizeInBytes();
182 strProviderName
= m_providerName
.c_str();
183 iClientProviderUid
= recording
.ClientProviderUid();
184 strParentalRatingCode
= m_parentalRatingCode
.c_str();
185 strParentalRatingIcon
= m_parentalRatingIcon
.c_str();
186 strParentalRatingSource
= m_parentalRatingSource
.c_str();
188 virtual ~CAddonRecording() = default;
191 const std::string m_recordingId
;
192 const std::string m_title
;
193 const std::string m_titleExtraInfo
;
194 const std::string m_episodeName
;
195 const std::string m_directory
;
196 const std::string m_plotOutline
;
197 const std::string m_plot
;
198 const std::string m_genreDescription
;
199 const std::string m_channelName
;
200 const std::string m_iconPath
;
201 const std::string m_thumbnailPath
;
202 const std::string m_fanartPath
;
203 const std::string m_firstAired
;
204 const std::string m_providerName
;
205 const std::string m_parentalRatingCode
;
206 const std::string m_parentalRatingIcon
;
207 const std::string m_parentalRatingSource
;
210 class CAddonTimer
: public PVR_TIMER
213 explicit CAddonTimer(const CPVRTimerInfoTag
& timer
)
214 : m_title(timer
.Title()),
215 m_epgSearchString(timer
.EpgSearchString()),
216 m_directory(timer
.Directory()),
217 m_summary(timer
.Summary()),
218 m_seriesLink(timer
.SeriesLink())
220 // zero-init base struct members
221 PVR_TIMER
* base
= static_cast<PVR_TIMER
*>(this);
225 timer
.StartAsUTC().GetAsTime(start
);
227 timer
.EndAsUTC().GetAsTime(end
);
229 timer
.FirstDayAsUTC().GetAsTime(first
);
230 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag
{timer
.GetEpgInfoTag()};
231 const int timeCorrection
{
232 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection
};
234 iClientIndex
= timer
.ClientIndex();
235 iParentClientIndex
= timer
.ParentClientIndex();
236 state
= timer
.State();
237 iTimerType
= timer
.GetTimerType()->GetTypeId();
238 iClientChannelUid
= timer
.ClientChannelUID();
239 strTitle
= m_title
.c_str();
240 strEpgSearchString
= m_epgSearchString
.c_str();
241 bFullTextEpgSearch
= timer
.IsFullTextEpgSearch();
242 strDirectory
= m_directory
.c_str();
243 iPriority
= timer
.Priority();
244 iLifetime
= timer
.Lifetime();
245 iMaxRecordings
= timer
.MaxRecordings();
246 iPreventDuplicateEpisodes
= timer
.PreventDupEpisodesPolicy();
247 iRecordingGroup
= timer
.RecordingGroup();
248 iWeekdays
= timer
.WeekDays();
249 startTime
= start
- timeCorrection
;
250 endTime
= end
- timeCorrection
;
251 bStartAnyTime
= timer
.IsStartAnyTime();
252 bEndAnyTime
= timer
.IsEndAnyTime();
253 firstDay
= first
- timeCorrection
;
254 iEpgUid
= epgTag
? epgTag
->UniqueBroadcastID() : PVR_TIMER_NO_EPG_UID
;
255 strSummary
= m_summary
.c_str();
256 iMarginStart
= timer
.MarginStart();
257 iMarginEnd
= timer
.MarginEnd();
258 iGenreType
= epgTag
? epgTag
->GenreType() : 0;
259 iGenreSubType
= epgTag
? epgTag
->GenreSubType() : 0;
260 strSeriesLink
= m_seriesLink
.c_str();
262 const auto& props
{timer
.GetCustomProperties()};
263 iCustomPropsSize
= static_cast<unsigned int>(props
.size());
264 if (iCustomPropsSize
)
266 m_customProps
= std::make_unique
<PVR_SETTING_KEY_VALUE_PAIR
[]>(iCustomPropsSize
);
268 for (const auto& entry
: props
)
270 PVR_SETTING_KEY_VALUE_PAIR
& prop
{m_customProps
[idx
]};
271 prop
.iKey
= entry
.first
;
272 prop
.eType
= entry
.second
.type
;
273 prop
.iValue
= entry
.second
.value
.asInteger32();
274 m_customPropStringValues
.emplace_back(entry
.second
.value
.asString());
275 prop
.strValue
= m_customPropStringValues
.back().c_str();
278 customProps
= m_customProps
.get();
281 virtual ~CAddonTimer() = default;
284 const std::string m_title
;
285 const std::string m_epgSearchString
;
286 const std::string m_directory
;
287 const std::string m_summary
;
288 const std::string m_seriesLink
;
289 std::vector
<std::string
> m_customPropStringValues
;
290 std::unique_ptr
<PVR_SETTING_KEY_VALUE_PAIR
[]> m_customProps
;
293 class CAddonEpgTag
: public EPG_TAG
296 explicit CAddonEpgTag(const CPVREpgInfoTag
& tag
)
297 : m_title(tag
.Title()),
298 m_titleExtraInfo(tag
.TitleExtraInfo()),
299 m_plotOutline(tag
.PlotOutline()),
301 m_originalTitle(tag
.OriginalTitle()),
302 m_cast(tag
.DeTokenize(tag
.Cast())),
303 m_director(tag
.DeTokenize(tag
.Directors())),
304 m_writer(tag
.DeTokenize(tag
.Writers())),
305 m_IMDBNumber(tag
.IMDBNumber()),
306 m_episodeName(tag
.EpisodeName()),
307 m_iconPath(tag
.ClientIconPath()),
308 m_seriesLink(tag
.SeriesLink()),
309 m_genreDescription(tag
.GenreDescription()),
310 m_firstAired(GetFirstAired(tag
)),
311 m_parentalRatingCode(tag
.ParentalRatingCode()),
312 m_parentalRatingIcon(tag
.ClientParentalRatingIconPath()),
313 m_parentalRatingSource(tag
.ParentalRatingSource())
315 // zero-init base struct members
316 EPG_TAG
* base
= static_cast<EPG_TAG
*>(this);
320 tag
.StartAsUTC().GetAsTime(t
);
322 tag
.EndAsUTC().GetAsTime(t
);
325 iUniqueBroadcastId
= tag
.UniqueBroadcastID();
326 iUniqueChannelId
= tag
.UniqueChannelID();
327 iParentalRating
= tag
.ParentalRating();
328 iSeriesNumber
= tag
.SeriesNumber();
329 iEpisodeNumber
= tag
.EpisodeNumber();
330 iEpisodePartNumber
= tag
.EpisodePart();
331 iStarRating
= tag
.StarRating();
333 iFlags
= tag
.Flags();
334 iGenreType
= tag
.GenreType();
335 iGenreSubType
= tag
.GenreSubType();
336 strTitle
= m_title
.c_str();
337 strTitleExtraInfo
= m_titleExtraInfo
.c_str();
338 strPlotOutline
= m_plotOutline
.c_str();
339 strPlot
= m_plot
.c_str();
340 strOriginalTitle
= m_originalTitle
.c_str();
341 strCast
= m_cast
.c_str();
342 strDirector
= m_director
.c_str();
343 strWriter
= m_writer
.c_str();
344 strIMDBNumber
= m_IMDBNumber
.c_str();
345 strEpisodeName
= m_episodeName
.c_str();
346 strIconPath
= m_iconPath
.c_str();
347 strSeriesLink
= m_seriesLink
.c_str();
348 strGenreDescription
= m_genreDescription
.c_str();
349 strFirstAired
= m_firstAired
.c_str();
350 strParentalRatingCode
= m_parentalRatingCode
.c_str();
351 strParentalRatingIcon
= m_parentalRatingIcon
.c_str();
352 strParentalRatingSource
= m_parentalRatingSource
.c_str();
355 virtual ~CAddonEpgTag() = default;
358 static std::string
GetFirstAired(const CPVREpgInfoTag
& tag
)
360 const CDateTime firstAired
{tag
.FirstAired()};
361 if (firstAired
.IsValid())
362 return firstAired
.GetAsW3CDate();
366 const std::string m_title
;
367 const std::string m_titleExtraInfo
;
368 const std::string m_plotOutline
;
369 const std::string m_plot
;
370 const std::string m_originalTitle
;
371 const std::string m_cast
;
372 const std::string m_director
;
373 const std::string m_writer
;
374 const std::string m_IMDBNumber
;
375 const std::string m_episodeName
;
376 const std::string m_iconPath
;
377 const std::string m_seriesLink
;
378 const std::string m_genreDescription
;
379 const std::string m_firstAired
;
380 const std::string m_parentalRatingCode
;
381 const std::string m_parentalRatingIcon
;
382 const std::string m_parentalRatingSource
;
385 EDL::Edit
ConvertAddonEdl(const PVR_EDL_ENTRY
& entry
)
388 edit
.start
= std::chrono::milliseconds(entry
.start
);
389 edit
.end
= std::chrono::milliseconds(entry
.end
);
393 case PVR_EDL_TYPE_CUT
:
394 edit
.action
= EDL::Action::CUT
;
396 case PVR_EDL_TYPE_MUTE
:
397 edit
.action
= EDL::Action::MUTE
;
399 case PVR_EDL_TYPE_SCENE
:
400 edit
.action
= EDL::Action::SCENE
;
402 case PVR_EDL_TYPE_COMBREAK
:
403 edit
.action
= EDL::Action::COMM_BREAK
;
406 CLog::LogF(LOGWARNING
, "Ignoring entry of unknown EDL type: {}", entry
.type
);
412 } // unnamed namespace
417 #define DEFAULT_INFO_STRING_VALUE "unknown"
419 CPVRClient::CPVRClient(const ADDON::AddonInfoPtr
& addonInfo
,
420 ADDON::AddonInstanceId instanceId
,
422 : IAddonInstanceHandler(ADDON_INSTANCE_PVR
, addonInfo
, instanceId
), m_iClientId(clientId
)
424 // Create all interface parts independent to make API changes easier if
425 // something is added
426 m_ifc
.pvr
= new AddonInstance_PVR
;
427 m_ifc
.pvr
->props
= new AddonProperties_PVR();
428 m_ifc
.pvr
->toKodi
= new AddonToKodiFuncTable_PVR();
429 m_ifc
.pvr
->toAddon
= new KodiToAddonFuncTable_PVR();
434 CPVRClient::~CPVRClient()
440 delete m_ifc
.pvr
->props
;
441 delete m_ifc
.pvr
->toKodi
;
442 delete m_ifc
.pvr
->toAddon
;
447 void CPVRClient::StopRunningInstance()
449 // stop the pvr manager and stop and unload the running pvr addon. pvr manager will be restarted on demand.
450 CServiceBroker::GetPVRManager().Stop();
451 CServiceBroker::GetPVRManager().Clients()->StopClient(m_iClientId
, false);
454 void CPVRClient::OnPreInstall()
456 // note: this method is also called on update; thus stop and unload possibly running instance
457 StopRunningInstance();
460 void CPVRClient::OnPreUnInstall()
462 StopRunningInstance();
465 void CPVRClient::ResetProperties()
467 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
469 /* initialise members */
470 m_strUserPath
= CSpecialProtocol::TranslatePath(Profile());
471 m_strClientPath
= CSpecialProtocol::TranslatePath(Path());
472 m_bReadyToUse
= false;
473 m_bBlockAddonCalls
= false;
475 m_allAddonCallsFinished
.Set();
476 m_connectionState
= PVR_CONNECTION_STATE_UNKNOWN
;
477 m_prevConnectionState
= PVR_CONNECTION_STATE_UNKNOWN
;
478 m_ignoreClient
= false;
480 m_strBackendVersion
= DEFAULT_INFO_STRING_VALUE
;
481 m_strConnectionString
= DEFAULT_INFO_STRING_VALUE
;
482 m_strBackendName
= DEFAULT_INFO_STRING_VALUE
;
483 m_strBackendHostname
.clear();
485 m_timertypes
.clear();
486 m_clientCapabilities
.clear();
488 m_ifc
.pvr
->props
->strUserPath
= m_strUserPath
.c_str();
489 m_ifc
.pvr
->props
->strClientPath
= m_strClientPath
.c_str();
490 m_ifc
.pvr
->props
->iEpgMaxPastDays
=
491 CServiceBroker::GetPVRManager().EpgContainer().GetPastDaysToDisplay();
492 m_ifc
.pvr
->props
->iEpgMaxFutureDays
=
493 CServiceBroker::GetPVRManager().EpgContainer().GetFutureDaysToDisplay();
495 m_ifc
.pvr
->toKodi
->kodiInstance
= this;
496 m_ifc
.pvr
->toKodi
->TransferEpgEntry
= cb_transfer_epg_entry
;
497 m_ifc
.pvr
->toKodi
->TransferChannelEntry
= cb_transfer_channel_entry
;
498 m_ifc
.pvr
->toKodi
->TransferProviderEntry
= cb_transfer_provider_entry
;
499 m_ifc
.pvr
->toKodi
->TransferTimerEntry
= cb_transfer_timer_entry
;
500 m_ifc
.pvr
->toKodi
->TransferRecordingEntry
= cb_transfer_recording_entry
;
501 m_ifc
.pvr
->toKodi
->AddMenuHook
= cb_add_menu_hook
;
502 m_ifc
.pvr
->toKodi
->RecordingNotification
= cb_recording_notification
;
503 m_ifc
.pvr
->toKodi
->TriggerChannelUpdate
= cb_trigger_channel_update
;
504 m_ifc
.pvr
->toKodi
->TriggerProvidersUpdate
= cb_trigger_provider_update
;
505 m_ifc
.pvr
->toKodi
->TriggerChannelGroupsUpdate
= cb_trigger_channel_groups_update
;
506 m_ifc
.pvr
->toKodi
->TriggerTimerUpdate
= cb_trigger_timer_update
;
507 m_ifc
.pvr
->toKodi
->TriggerRecordingUpdate
= cb_trigger_recording_update
;
508 m_ifc
.pvr
->toKodi
->TriggerEpgUpdate
= cb_trigger_epg_update
;
509 m_ifc
.pvr
->toKodi
->FreeDemuxPacket
= cb_free_demux_packet
;
510 m_ifc
.pvr
->toKodi
->AllocateDemuxPacket
= cb_allocate_demux_packet
;
511 m_ifc
.pvr
->toKodi
->TransferChannelGroup
= cb_transfer_channel_group
;
512 m_ifc
.pvr
->toKodi
->TransferChannelGroupMember
= cb_transfer_channel_group_member
;
513 m_ifc
.pvr
->toKodi
->ConnectionStateChange
= cb_connection_state_change
;
514 m_ifc
.pvr
->toKodi
->EpgEventStateChange
= cb_epg_event_state_change
;
515 m_ifc
.pvr
->toKodi
->GetCodecByName
= cb_get_codec_by_name
;
517 // Clear function addresses to have NULL if not set by addon
518 memset(m_ifc
.pvr
->toAddon
, 0, sizeof(KodiToAddonFuncTable_PVR
));
521 ADDON_STATUS
CPVRClient::Create()
525 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Creating PVR add-on instance [{},{},{}]", ID(), InstanceId(),
528 const ADDON_STATUS status
= CreateInstance();
530 if (status
== ADDON_STATUS_OK
)
532 m_bReadyToUse
= GetAddonProperties();
534 CLog::LogFC(LOGDEBUG
, LOGPVR
,
535 "Created PVR add-on instance {}. readytouse={}, ignoreclient={}, "
536 "connectionstate={}",
537 GetID(), m_bReadyToUse
, IgnoreClient(), GetConnectionState());
541 m_bReadyToUse
= false;
543 CLog::LogF(LOGERROR
, "Failed to create PVR add-on instance {}. status={}", GetID(), status
);
549 void CPVRClient::Destroy()
554 m_bReadyToUse
= false;
556 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Destroying PVR add-on instance {}", GetID());
558 m_bBlockAddonCalls
= true;
559 m_allAddonCallsFinished
.Wait();
563 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Destroyed PVR add-on instance {}", GetID());
566 m_menuhooks
->Clear();
571 void CPVRClient::Stop()
573 m_bBlockAddonCalls
= true;
577 void CPVRClient::Continue()
579 m_bBlockAddonCalls
= false;
582 void CPVRClient::ReCreate()
588 bool CPVRClient::ReadyToUse() const
590 return m_bReadyToUse
;
593 PVR_CONNECTION_STATE
CPVRClient::GetConnectionState() const
595 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
596 return m_connectionState
;
599 void CPVRClient::SetConnectionState(PVR_CONNECTION_STATE state
)
601 if (state
== PVR_CONNECTION_STATE_CONNECTED
)
603 // update properties - some will only be available after add-on is connected to backend
604 if (!GetAddonProperties())
605 CLog::LogF(LOGERROR
, "Error reading PVR client properties");
609 if (!GetAddonNameStringProperties())
610 CLog::LogF(LOGERROR
, "Cannot read PVR client name string properties");
613 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
615 m_prevConnectionState
= m_connectionState
;
616 m_connectionState
= state
;
618 if (m_connectionState
== PVR_CONNECTION_STATE_CONNECTED
)
619 m_ignoreClient
= false;
620 else if (m_connectionState
== PVR_CONNECTION_STATE_CONNECTING
&&
621 m_prevConnectionState
== PVR_CONNECTION_STATE_UNKNOWN
)
622 m_ignoreClient
= true; // ignore until connected
625 PVR_CONNECTION_STATE
CPVRClient::GetPreviousConnectionState() const
627 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
628 return m_prevConnectionState
;
631 bool CPVRClient::IgnoreClient() const
633 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
634 return m_ignoreClient
;
637 bool CPVRClient::IsEnabled() const
639 if (InstanceId() == ADDON_SINGLETON_INSTANCE_ID
)
641 return !CServiceBroker::GetAddonMgr().IsAddonDisabled(ID());
645 bool instanceEnabled
{false};
646 Addon()->ReloadSettings(InstanceId());
647 Addon()->GetSettingBool(ADDON_SETTING_INSTANCE_ENABLED_VALUE
, instanceEnabled
, InstanceId());
648 return instanceEnabled
;
652 int CPVRClient::GetID() const
657 bool CPVRClient::GetAddonProperties()
659 if (!GetAddonNameStringProperties())
662 PVR_ADDON_CAPABILITIES addonCapabilities
= {};
664 /* get the capabilities */
665 PVR_ERROR retVal
= DoAddonCall(
667 [&addonCapabilities
](const AddonInstance
* addon
)
668 { return addon
->toAddon
->GetCapabilities(addon
, &addonCapabilities
); },
671 if (retVal
== PVR_ERROR_NO_ERROR
)
673 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
674 m_clientCapabilities
= addonCapabilities
;
677 /* free the resources of the capabilities instance */
680 [&addonCapabilities
](const AddonInstance
* addon
)
681 { return addon
->toAddon
->FreeCapabilities(addon
, &addonCapabilities
); },
684 return (retVal
== PVR_ERROR_NO_ERROR
);
687 bool CPVRClient::GetAddonNameStringProperties()
689 std::string backendName
;
690 std::string connectionString
;
691 std::string backendVersion
;
692 std::string backendHostname
;
694 /* get the name of the backend */
695 PVR_ERROR retVal
= DoAddonCall(
697 [&backendName
](const AddonInstance
* addon
)
699 char* strBackendName
{nullptr};
700 const PVR_ERROR error
{addon
->toAddon
->GetBackendName(addon
, &strBackendName
)};
701 if (error
== PVR_ERROR_NO_ERROR
&& strBackendName
!= nullptr)
702 backendName
= strBackendName
;
703 addon
->toAddon
->FreeString(addon
, strBackendName
);
708 if (retVal
!= PVR_ERROR_NO_ERROR
)
711 /* get the connection string */
712 retVal
= DoAddonCall(
714 [&connectionString
](const AddonInstance
* addon
)
716 char* strConnectionString
{nullptr};
717 const PVR_ERROR error
{addon
->toAddon
->GetConnectionString(addon
, &strConnectionString
)};
718 if (error
== PVR_ERROR_NO_ERROR
&& strConnectionString
!= nullptr)
719 connectionString
= strConnectionString
;
720 addon
->toAddon
->FreeString(addon
, strConnectionString
);
725 if (retVal
!= PVR_ERROR_NO_ERROR
&& retVal
!= PVR_ERROR_NOT_IMPLEMENTED
)
728 /* backend version number */
729 retVal
= DoAddonCall(
731 [&backendVersion
](const AddonInstance
* addon
)
733 char* strBackendVersion
{nullptr};
734 const PVR_ERROR error
{addon
->toAddon
->GetBackendVersion(addon
, &strBackendVersion
)};
735 if (error
== PVR_ERROR_NO_ERROR
&& strBackendVersion
!= nullptr)
736 backendVersion
= strBackendVersion
;
737 addon
->toAddon
->FreeString(addon
, strBackendVersion
);
742 if (retVal
!= PVR_ERROR_NO_ERROR
)
745 /* backend hostname */
746 retVal
= DoAddonCall(
748 [&backendHostname
](const AddonInstance
* addon
)
750 char* strBackendHostname
{nullptr};
751 const PVR_ERROR error
{addon
->toAddon
->GetBackendHostname(addon
, &strBackendHostname
)};
752 if (error
== PVR_ERROR_NO_ERROR
&& strBackendHostname
!= nullptr)
753 backendHostname
= strBackendHostname
;
754 addon
->toAddon
->FreeString(addon
, strBackendHostname
);
759 if (retVal
!= PVR_ERROR_NO_ERROR
&& retVal
!= PVR_ERROR_NOT_IMPLEMENTED
)
762 /* update the members */
763 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
764 m_strBackendName
= backendName
;
765 m_strConnectionString
= connectionString
;
766 m_strBackendVersion
= backendVersion
;
767 m_strBackendHostname
= backendHostname
;
772 const std::string
& CPVRClient::GetBackendName() const
774 return m_strBackendName
;
777 const std::string
& CPVRClient::GetBackendVersion() const
779 return m_strBackendVersion
;
782 const std::string
& CPVRClient::GetBackendHostname() const
784 return m_strBackendHostname
;
787 const std::string
& CPVRClient::GetConnectionString() const
789 return m_strConnectionString
;
792 std::string
CPVRClient::GetClientName() const
797 std::string
CPVRClient::GetInstanceName() const
799 std::string instanceName
;
800 if (Addon()->SupportsInstanceSettings())
801 Addon()->GetSettingString(ADDON_SETTING_INSTANCE_NAME_VALUE
, instanceName
, InstanceId());
806 std::string
CPVRClient::GetFullClientName() const
808 if (Addon()->SupportsInstanceSettings())
810 std::string instanceName
;
811 Addon()->GetSettingString(ADDON_SETTING_INSTANCE_NAME_VALUE
, instanceName
, InstanceId());
812 if (!instanceName
.empty())
813 return StringUtils::Format("{} ({})", Name(), instanceName
);
818 PVR_ERROR
CPVRClient::GetDriveSpace(uint64_t& iTotal
, uint64_t& iUsed
) const
820 /* default to 0 in case of error */
824 return DoAddonCall(__func__
,
825 [&iTotal
, &iUsed
](const AddonInstance
* addon
)
827 uint64_t iTotalSpace
= 0;
828 uint64_t iUsedSpace
= 0;
830 addon
->toAddon
->GetDriveSpace(addon
, &iTotalSpace
, &iUsedSpace
);
831 if (error
== PVR_ERROR_NO_ERROR
)
833 iTotal
= iTotalSpace
;
840 PVR_ERROR
CPVRClient::StartChannelScan()
844 [](const AddonInstance
* addon
) { return addon
->toAddon
->OpenDialogChannelScan(addon
); },
845 m_clientCapabilities
.SupportsChannelScan());
848 PVR_ERROR
CPVRClient::OpenDialogChannelAdd(const std::shared_ptr
<const CPVRChannel
>& channel
)
852 [channel
](const AddonInstance
* addon
)
854 const CAddonChannel addonChannel
{*channel
};
855 return addon
->toAddon
->OpenDialogChannelAdd(addon
, &addonChannel
);
857 m_clientCapabilities
.SupportsChannelSettings());
860 PVR_ERROR
CPVRClient::OpenDialogChannelSettings(const std::shared_ptr
<const CPVRChannel
>& channel
)
864 [channel
](const AddonInstance
* addon
)
866 const CAddonChannel addonChannel
{*channel
};
867 return addon
->toAddon
->OpenDialogChannelSettings(addon
, &addonChannel
);
869 m_clientCapabilities
.SupportsChannelSettings());
872 PVR_ERROR
CPVRClient::DeleteChannel(const std::shared_ptr
<const CPVRChannel
>& channel
)
876 [channel
](const AddonInstance
* addon
)
878 const CAddonChannel addonChannel
{*channel
};
879 return addon
->toAddon
->DeleteChannel(addon
, &addonChannel
);
881 m_clientCapabilities
.SupportsChannelSettings());
884 PVR_ERROR
CPVRClient::RenameChannel(const std::shared_ptr
<const CPVRChannel
>& channel
)
888 [channel
](const AddonInstance
* addon
)
890 const CAddonChannel addonChannel
{*channel
, channel
->ChannelName()};
891 return addon
->toAddon
->RenameChannel(addon
, &addonChannel
);
893 m_clientCapabilities
.SupportsChannelSettings());
896 PVR_ERROR
CPVRClient::GetEPGForChannel(int iChannelUid
,
903 [this, iChannelUid
, epg
, start
, end
](const AddonInstance
* addon
)
905 PVR_HANDLE_STRUCT handle
= {};
906 handle
.callerAddress
= this;
907 handle
.dataAddress
= epg
;
909 int iPVRTimeCorrection
=
910 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection
;
912 return addon
->toAddon
->GetEPGForChannel(addon
, &handle
, iChannelUid
,
913 start
? start
- iPVRTimeCorrection
: 0,
914 end
? end
- iPVRTimeCorrection
: 0);
916 m_clientCapabilities
.SupportsEPG());
919 PVR_ERROR
CPVRClient::SetEPGMaxPastDays(int iPastDays
)
923 [iPastDays
](const AddonInstance
* addon
)
924 { return addon
->toAddon
->SetEPGMaxPastDays(addon
, iPastDays
); },
925 m_clientCapabilities
.SupportsEPG());
928 PVR_ERROR
CPVRClient::SetEPGMaxFutureDays(int iFutureDays
)
932 [iFutureDays
](const AddonInstance
* addon
)
933 { return addon
->toAddon
->SetEPGMaxFutureDays(addon
, iFutureDays
); },
934 m_clientCapabilities
.SupportsEPG());
937 PVR_ERROR
CPVRClient::IsRecordable(const std::shared_ptr
<const CPVREpgInfoTag
>& tag
,
938 bool& bIsRecordable
) const
942 [tag
, &bIsRecordable
](const AddonInstance
* addon
)
944 CAddonEpgTag
addonTag(*tag
);
945 return addon
->toAddon
->IsEPGTagRecordable(addon
, &addonTag
, &bIsRecordable
);
947 m_clientCapabilities
.SupportsRecordings() && m_clientCapabilities
.SupportsEPG());
950 PVR_ERROR
CPVRClient::IsPlayable(const std::shared_ptr
<const CPVREpgInfoTag
>& tag
,
951 bool& bIsPlayable
) const
955 [tag
, &bIsPlayable
](const AddonInstance
* addon
)
957 CAddonEpgTag
addonTag(*tag
);
958 return addon
->toAddon
->IsEPGTagPlayable(addon
, &addonTag
, &bIsPlayable
);
960 m_clientCapabilities
.SupportsEPG());
963 void CPVRClient::WriteStreamProperties(PVR_NAMED_VALUE
** properties
,
964 unsigned int iPropertyCount
,
965 CPVRStreamProperties
& props
)
967 for (unsigned int i
= 0; i
< iPropertyCount
; ++i
)
969 const PVR_NAMED_VALUE
* prop
{properties
[i
]};
970 props
.emplace_back(std::make_pair(prop
->strName
, prop
->strValue
));
974 PVR_ERROR
CPVRClient::GetEpgTagStreamProperties(const std::shared_ptr
<const CPVREpgInfoTag
>& tag
,
975 CPVRStreamProperties
& props
) const
977 return DoAddonCall(__func__
,
978 [&tag
, &props
](const AddonInstance
* addon
)
980 CAddonEpgTag
addonTag(*tag
);
982 PVR_NAMED_VALUE
** property_array
{nullptr};
983 unsigned int size
{0};
984 const PVR_ERROR error
{addon
->toAddon
->GetEPGTagStreamProperties(
985 addon
, &addonTag
, &property_array
, &size
)};
986 if (error
== PVR_ERROR_NO_ERROR
)
987 WriteStreamProperties(property_array
, size
, props
);
989 addon
->toAddon
->FreeProperties(addon
, property_array
, size
);
994 PVR_ERROR
CPVRClient::GetEpgTagEdl(const std::shared_ptr
<const CPVREpgInfoTag
>& epgTag
,
995 std::vector
<EDL::Edit
>& edls
) const
1000 [&epgTag
, &edls
](const AddonInstance
* addon
)
1002 CAddonEpgTag
addonTag(*epgTag
);
1004 PVR_EDL_ENTRY
** edl_array
{nullptr};
1005 unsigned int size
{0};
1006 const PVR_ERROR error
{addon
->toAddon
->GetEPGTagEdl(addon
, &addonTag
, &edl_array
, &size
)};
1007 if (error
== PVR_ERROR_NO_ERROR
)
1010 for (unsigned int i
= 0; i
< size
; ++i
)
1011 edls
.emplace_back(ConvertAddonEdl(*edl_array
[i
]));
1013 addon
->toAddon
->FreeEdlEntries(addon
, edl_array
, size
);
1016 m_clientCapabilities
.SupportsEpgTagEdl());
1019 PVR_ERROR
CPVRClient::GetChannelGroupsAmount(int& iGroups
) const
1024 [&iGroups
](const AddonInstance
* addon
)
1025 { return addon
->toAddon
->GetChannelGroupsAmount(addon
, &iGroups
); },
1026 m_clientCapabilities
.SupportsChannelGroups());
1029 PVR_ERROR
CPVRClient::GetChannelGroups(CPVRChannelGroups
* groups
) const
1031 const bool radio
{groups
->IsRadio()};
1034 [this, groups
](const AddonInstance
* addon
)
1036 PVR_HANDLE_STRUCT handle
= {};
1037 handle
.callerAddress
= this;
1038 handle
.dataAddress
= groups
;
1039 return addon
->toAddon
->GetChannelGroups(addon
, &handle
, groups
->IsRadio());
1041 m_clientCapabilities
.SupportsChannelGroups() &&
1042 ((radio
&& m_clientCapabilities
.SupportsRadio()) ||
1043 (!radio
&& m_clientCapabilities
.SupportsTV())));
1046 PVR_ERROR
CPVRClient::GetChannelGroupMembers(
1047 CPVRChannelGroup
* group
,
1048 std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>>& groupMembers
) const
1050 const bool radio
{group
->IsRadio()};
1053 [this, group
, &groupMembers
](const AddonInstance
* addon
)
1055 PVR_HANDLE_STRUCT handle
= {};
1056 handle
.callerAddress
= this;
1057 handle
.dataAddress
= &groupMembers
;
1059 const CAddonChannelGroup addonGroup
{*group
};
1060 return addon
->toAddon
->GetChannelGroupMembers(addon
, &handle
, &addonGroup
);
1062 m_clientCapabilities
.SupportsChannelGroups() &&
1063 ((radio
&& m_clientCapabilities
.SupportsRadio()) ||
1064 (!radio
&& m_clientCapabilities
.SupportsTV())));
1067 PVR_ERROR
CPVRClient::GetProvidersAmount(int& iProviders
) const
1070 return DoAddonCall(__func__
, [&iProviders
](const AddonInstance
* addon
)
1071 { return addon
->toAddon
->GetProvidersAmount(addon
, &iProviders
); });
1074 PVR_ERROR
CPVRClient::GetProviders(CPVRProvidersContainer
& providers
) const
1078 [this, &providers
](const AddonInstance
* addon
)
1080 PVR_HANDLE_STRUCT handle
= {};
1081 handle
.callerAddress
= this;
1082 handle
.dataAddress
= &providers
;
1083 return addon
->toAddon
->GetProviders(addon
, &handle
);
1085 m_clientCapabilities
.SupportsProviders());
1088 PVR_ERROR
CPVRClient::GetChannelsAmount(int& iChannels
) const
1091 return DoAddonCall(__func__
, [&iChannels
](const AddonInstance
* addon
)
1092 { return addon
->toAddon
->GetChannelsAmount(addon
, &iChannels
); });
1095 PVR_ERROR
CPVRClient::GetChannels(bool radio
,
1096 std::vector
<std::shared_ptr
<CPVRChannel
>>& channels
) const
1100 [this, radio
, &channels
](const AddonInstance
* addon
)
1102 PVR_HANDLE_STRUCT handle
= {};
1103 handle
.callerAddress
= this;
1104 handle
.dataAddress
= &channels
;
1105 const PVR_ERROR error
{addon
->toAddon
->GetChannels(addon
, &handle
, radio
)};
1107 if (error
== PVR_ERROR_NO_ERROR
)
1109 const CDateTime
& dateTime
{GetDateTimeFirstChannelsAdded()};
1110 if (!dateTime
.IsValid())
1112 // Remember when first channels were added for this client.
1113 const_cast<CPVRClient
*>(this)->SetDateTimeFirstChannelsAdded(
1114 CDateTime::GetUTCDateTime());
1120 (radio
&& m_clientCapabilities
.SupportsRadio()) ||
1121 (!radio
&& m_clientCapabilities
.SupportsTV()));
1124 PVR_ERROR
CPVRClient::GetRecordingsAmount(bool deleted
, int& iRecordings
) const
1129 [deleted
, &iRecordings
](const AddonInstance
* addon
)
1130 { return addon
->toAddon
->GetRecordingsAmount(addon
, deleted
, &iRecordings
); },
1131 m_clientCapabilities
.SupportsRecordings() &&
1132 (!deleted
|| m_clientCapabilities
.SupportsRecordingsUndelete()));
1135 PVR_ERROR
CPVRClient::GetRecordings(CPVRRecordings
* results
, bool deleted
) const
1139 [this, results
, deleted
](const AddonInstance
* addon
)
1141 PVR_HANDLE_STRUCT handle
= {};
1142 handle
.callerAddress
= this;
1143 handle
.dataAddress
= results
;
1144 return addon
->toAddon
->GetRecordings(addon
, &handle
, deleted
);
1146 m_clientCapabilities
.SupportsRecordings() &&
1147 (!deleted
|| m_clientCapabilities
.SupportsRecordingsUndelete()));
1150 PVR_ERROR
CPVRClient::DeleteRecording(const CPVRRecording
& recording
)
1154 [&recording
](const AddonInstance
* addon
)
1156 const CAddonRecording tag
{recording
};
1157 return addon
->toAddon
->DeleteRecording(addon
, &tag
);
1159 m_clientCapabilities
.SupportsRecordings() && m_clientCapabilities
.SupportsRecordingsDelete());
1162 PVR_ERROR
CPVRClient::UndeleteRecording(const CPVRRecording
& recording
)
1166 [&recording
](const AddonInstance
* addon
)
1168 const CAddonRecording tag
{recording
};
1169 return addon
->toAddon
->UndeleteRecording(addon
, &tag
);
1171 m_clientCapabilities
.SupportsRecordingsUndelete());
1174 PVR_ERROR
CPVRClient::DeleteAllRecordingsFromTrash()
1178 [](const AddonInstance
* addon
)
1179 { return addon
->toAddon
->DeleteAllRecordingsFromTrash(addon
); },
1180 m_clientCapabilities
.SupportsRecordingsUndelete());
1183 PVR_ERROR
CPVRClient::RenameRecording(const CPVRRecording
& recording
)
1187 [&recording
](const AddonInstance
* addon
)
1189 const CAddonRecording tag
{recording
};
1190 return addon
->toAddon
->RenameRecording(addon
, &tag
);
1192 m_clientCapabilities
.SupportsRecordings());
1195 PVR_ERROR
CPVRClient::SetRecordingLifetime(const CPVRRecording
& recording
)
1199 [&recording
](const AddonInstance
* addon
)
1201 const CAddonRecording tag
{recording
};
1202 return addon
->toAddon
->SetRecordingLifetime(addon
, &tag
);
1204 m_clientCapabilities
.SupportsRecordingsLifetimeChange());
1207 PVR_ERROR
CPVRClient::SetRecordingPlayCount(const CPVRRecording
& recording
, int count
)
1211 [&recording
, count
](const AddonInstance
* addon
)
1213 const CAddonRecording tag
{recording
};
1214 return addon
->toAddon
->SetRecordingPlayCount(addon
, &tag
, count
);
1216 m_clientCapabilities
.SupportsRecordingsPlayCount());
1219 PVR_ERROR
CPVRClient::SetRecordingLastPlayedPosition(const CPVRRecording
& recording
,
1220 int lastplayedposition
)
1224 [&recording
, lastplayedposition
](const AddonInstance
* addon
)
1226 const CAddonRecording tag
{recording
};
1227 return addon
->toAddon
->SetRecordingLastPlayedPosition(addon
, &tag
, lastplayedposition
);
1229 m_clientCapabilities
.SupportsRecordingsLastPlayedPosition());
1232 PVR_ERROR
CPVRClient::GetRecordingLastPlayedPosition(const CPVRRecording
& recording
,
1233 int& iPosition
) const
1238 [&recording
, &iPosition
](const AddonInstance
* addon
)
1240 const CAddonRecording tag
{recording
};
1241 return addon
->toAddon
->GetRecordingLastPlayedPosition(addon
, &tag
, &iPosition
);
1243 m_clientCapabilities
.SupportsRecordingsLastPlayedPosition());
1246 PVR_ERROR
CPVRClient::GetRecordingEdl(const CPVRRecording
& recording
,
1247 std::vector
<EDL::Edit
>& edls
) const
1252 [&recording
, &edls
](const AddonInstance
* addon
)
1254 const CAddonRecording tag
{recording
};
1256 PVR_EDL_ENTRY
** edl_array
{nullptr};
1257 unsigned int size
{0};
1258 const PVR_ERROR error
{addon
->toAddon
->GetRecordingEdl(addon
, &tag
, &edl_array
, &size
)};
1259 if (error
== PVR_ERROR_NO_ERROR
)
1262 for (unsigned int i
= 0; i
< size
; ++i
)
1263 edls
.emplace_back(ConvertAddonEdl(*edl_array
[i
]));
1265 addon
->toAddon
->FreeEdlEntries(addon
, edl_array
, size
);
1268 m_clientCapabilities
.SupportsRecordingsEdl());
1271 PVR_ERROR
CPVRClient::GetRecordingSize(const CPVRRecording
& recording
, int64_t& sizeInBytes
) const
1275 [&recording
, &sizeInBytes
](const AddonInstance
* addon
)
1277 const CAddonRecording tag
{recording
};
1278 return addon
->toAddon
->GetRecordingSize(addon
, &tag
, &sizeInBytes
);
1280 m_clientCapabilities
.SupportsRecordingsSize());
1283 PVR_ERROR
CPVRClient::GetTimersAmount(int& iTimers
) const
1288 [&iTimers
](const AddonInstance
* addon
)
1289 { return addon
->toAddon
->GetTimersAmount(addon
, &iTimers
); },
1290 m_clientCapabilities
.SupportsTimers());
1293 PVR_ERROR
CPVRClient::GetTimers(CPVRTimersContainer
* results
) const
1297 [this, results
](const AddonInstance
* addon
)
1299 PVR_HANDLE_STRUCT handle
= {};
1300 handle
.callerAddress
= this;
1301 handle
.dataAddress
= results
;
1302 return addon
->toAddon
->GetTimers(addon
, &handle
);
1304 m_clientCapabilities
.SupportsTimers());
1307 PVR_ERROR
CPVRClient::AddTimer(const CPVRTimerInfoTag
& timer
)
1311 [&timer
](const AddonInstance
* addon
)
1313 const CAddonTimer tag
{timer
};
1314 return addon
->toAddon
->AddTimer(addon
, &tag
);
1316 m_clientCapabilities
.SupportsTimers());
1319 PVR_ERROR
CPVRClient::DeleteTimer(const CPVRTimerInfoTag
& timer
, bool bForce
/* = false */)
1323 [&timer
, bForce
](const AddonInstance
* addon
)
1325 const CAddonTimer tag
{timer
};
1326 return addon
->toAddon
->DeleteTimer(addon
, &tag
, bForce
);
1328 m_clientCapabilities
.SupportsTimers());
1331 PVR_ERROR
CPVRClient::UpdateTimer(const CPVRTimerInfoTag
& timer
)
1335 [&timer
](const AddonInstance
* addon
)
1337 const CAddonTimer tag
{timer
};
1338 return addon
->toAddon
->UpdateTimer(addon
, &tag
);
1340 m_clientCapabilities
.SupportsTimers());
1343 const std::vector
<std::shared_ptr
<CPVRTimerType
>>& CPVRClient::GetTimerTypes() const
1345 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
1346 return m_timertypes
;
1349 PVR_ERROR
CPVRClient::UpdateTimerTypes()
1351 std::vector
<std::shared_ptr
<CPVRTimerType
>> timerTypes
;
1353 PVR_ERROR retVal
= DoAddonCall(
1355 [this, &timerTypes
](const AddonInstance
* addon
)
1357 PVR_TIMER_TYPE
** types_array
{nullptr};
1358 unsigned int size
{0};
1359 PVR_ERROR retval
{addon
->toAddon
->GetTimerTypes(addon
, &types_array
, &size
)};
1361 const bool array_owner
{retval
== PVR_ERROR_NOT_IMPLEMENTED
};
1364 // begin compat section
1365 CLog::LogF(LOGWARNING
,
1366 "Add-on {} does not support timer types. It will work, but not benefit from "
1367 "the timer features introduced with PVR Addon API 2.0.0",
1370 // Create standard timer types (mostly) matching the timer functionality available in Isengard.
1371 // This is for migration only and does not make changes to the addons obsolete. Addons should
1372 // work and benefit from some UI changes (e.g. some of the timer settings dialog enhancements),
1373 // but all old problems/bugs due to static attributes and values will remain the same as in
1374 // Isengard. Also, new features (like epg search) are not available to addons automatically.
1375 // This code can be removed once all addons actually support the respective PVR Addon API version.
1378 if (m_clientCapabilities
.SupportsEPG())
1381 types_array
= new PVR_TIMER_TYPE
*[size
];
1384 types_array
[0] = new PVR_TIMER_TYPE
{};
1385 types_array
[0]->iId
= 1;
1386 types_array
[0]->iAttributes
=
1387 PVR_TIMER_TYPE_IS_MANUAL
| PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE
|
1388 PVR_TIMER_TYPE_SUPPORTS_CHANNELS
| PVR_TIMER_TYPE_SUPPORTS_START_TIME
|
1389 PVR_TIMER_TYPE_SUPPORTS_END_TIME
| PVR_TIMER_TYPE_SUPPORTS_PRIORITY
|
1390 PVR_TIMER_TYPE_SUPPORTS_LIFETIME
| PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS
;
1392 // manual timer rule
1393 types_array
[1] = new PVR_TIMER_TYPE
{};
1394 types_array
[1]->iId
= 2;
1395 types_array
[1]->iAttributes
=
1396 PVR_TIMER_TYPE_IS_MANUAL
| PVR_TIMER_TYPE_IS_REPEATING
|
1397 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE
| PVR_TIMER_TYPE_SUPPORTS_CHANNELS
|
1398 PVR_TIMER_TYPE_SUPPORTS_START_TIME
| PVR_TIMER_TYPE_SUPPORTS_END_TIME
|
1399 PVR_TIMER_TYPE_SUPPORTS_PRIORITY
| PVR_TIMER_TYPE_SUPPORTS_LIFETIME
|
1400 PVR_TIMER_TYPE_SUPPORTS_FIRST_DAY
| PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS
|
1401 PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS
;
1403 if (m_clientCapabilities
.SupportsEPG())
1405 // One-shot epg-based
1406 types_array
[2] = new PVR_TIMER_TYPE
{};
1407 types_array
[2]->iId
= 3;
1408 types_array
[2]->iAttributes
=
1409 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE
| PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE
|
1410 PVR_TIMER_TYPE_SUPPORTS_CHANNELS
| PVR_TIMER_TYPE_SUPPORTS_START_TIME
|
1411 PVR_TIMER_TYPE_SUPPORTS_END_TIME
| PVR_TIMER_TYPE_SUPPORTS_PRIORITY
|
1412 PVR_TIMER_TYPE_SUPPORTS_LIFETIME
| PVR_TIMER_TYPE_SUPPORTS_RECORDING_FOLDERS
;
1415 retval
= PVR_ERROR_NO_ERROR
;
1416 // end compat section
1419 if (retval
== PVR_ERROR_NO_ERROR
)
1421 timerTypes
.reserve(size
);
1422 for (unsigned int i
= 0; i
< size
; ++i
)
1424 if (types_array
[i
]->iId
== PVR_TIMER_TYPE_NONE
)
1426 CLog::LogF(LOGERROR
, "Invalid timer type supplied by add-on {}.", GetID());
1429 timerTypes
.emplace_back(
1430 std::make_shared
<CPVRTimerType
>(*(types_array
[i
]), m_iClientId
));
1434 /* free the resources of the timer types array */
1437 // begin compat section
1438 for (unsigned int i
= 0; i
< size
; ++i
)
1439 delete types_array
[i
];
1441 delete[] types_array
;
1442 // end compat section
1446 addon
->toAddon
->FreeTimerTypes(addon
, types_array
, size
);
1448 types_array
= nullptr;
1452 m_clientCapabilities
.SupportsTimers(), false);
1454 if (retVal
== PVR_ERROR_NO_ERROR
)
1456 std::vector
<std::shared_ptr
<CPVRTimerType
>> newTimerTypes
;
1457 newTimerTypes
.reserve(timerTypes
.size());
1459 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
1461 for (const auto& type
: timerTypes
)
1463 const auto it
= std::find_if(m_timertypes
.cbegin(), m_timertypes
.cend(),
1464 [&type
](const std::shared_ptr
<const CPVRTimerType
>& entry
)
1465 { return entry
->GetTypeId() == type
->GetTypeId(); });
1466 if (it
== m_timertypes
.cend())
1468 newTimerTypes
.emplace_back(type
);
1472 (*it
)->Update(*type
);
1473 newTimerTypes
.emplace_back(*it
);
1477 m_timertypes
= newTimerTypes
;
1482 PVR_ERROR
CPVRClient::GetStreamReadChunkSize(int& iChunkSize
) const
1486 [&iChunkSize
](const AddonInstance
* addon
)
1487 { return addon
->toAddon
->GetStreamReadChunkSize(addon
, &iChunkSize
); },
1488 m_clientCapabilities
.SupportsRecordings() || m_clientCapabilities
.HandlesInputStream());
1491 PVR_ERROR
CPVRClient::ReadLiveStream(void* lpBuf
, int64_t uiBufSize
, int& iRead
)
1494 return DoAddonCall(__func__
,
1495 [&lpBuf
, uiBufSize
, &iRead
](const AddonInstance
* addon
)
1497 iRead
= addon
->toAddon
->ReadLiveStream(
1498 addon
, static_cast<unsigned char*>(lpBuf
), static_cast<int>(uiBufSize
));
1499 return (iRead
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1503 PVR_ERROR
CPVRClient::ReadRecordedStream(int64_t streamId
,
1509 return DoAddonCall(__func__
,
1510 [streamId
, &lpBuf
, uiBufSize
, &iRead
](const AddonInstance
* addon
)
1512 iRead
= addon
->toAddon
->ReadRecordedStream(
1513 addon
, streamId
, static_cast<unsigned char*>(lpBuf
),
1514 static_cast<int>(uiBufSize
));
1515 return (iRead
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1519 PVR_ERROR
CPVRClient::SeekLiveStream(int64_t iFilePosition
, int iWhence
, int64_t& iPosition
)
1522 return DoAddonCall(__func__
,
1523 [iFilePosition
, iWhence
, &iPosition
](const AddonInstance
* addon
)
1525 iPosition
= addon
->toAddon
->SeekLiveStream(addon
, iFilePosition
, iWhence
);
1526 return (iPosition
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1530 PVR_ERROR
CPVRClient::SeekRecordedStream(int64_t streamId
,
1531 int64_t iFilePosition
,
1536 return DoAddonCall(__func__
,
1537 [streamId
, iFilePosition
, iWhence
, &iPosition
](const AddonInstance
* addon
)
1539 iPosition
= addon
->toAddon
->SeekRecordedStream(addon
, streamId
,
1540 iFilePosition
, iWhence
);
1541 return (iPosition
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1545 PVR_ERROR
CPVRClient::SeekTime(double time
, bool backwards
, double* startpts
)
1547 return DoAddonCall(__func__
,
1548 [time
, backwards
, &startpts
](const AddonInstance
* addon
)
1550 return addon
->toAddon
->SeekTime(addon
, time
, backwards
, startpts
)
1551 ? PVR_ERROR_NO_ERROR
1552 : PVR_ERROR_NOT_IMPLEMENTED
;
1556 PVR_ERROR
CPVRClient::GetLiveStreamLength(int64_t& iLength
) const
1559 return DoAddonCall(__func__
,
1560 [&iLength
](const AddonInstance
* addon
)
1562 iLength
= addon
->toAddon
->LengthLiveStream(addon
);
1563 return (iLength
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1567 PVR_ERROR
CPVRClient::GetRecordedStreamLength(int64_t streamId
, int64_t& iLength
) const
1570 return DoAddonCall(__func__
,
1571 [streamId
, &iLength
](const AddonInstance
* addon
)
1573 iLength
= addon
->toAddon
->LengthRecordedStream(addon
, streamId
);
1574 return (iLength
== -1) ? PVR_ERROR_NOT_IMPLEMENTED
: PVR_ERROR_NO_ERROR
;
1578 PVR_ERROR
CPVRClient::SignalQuality(int channelUid
, CPVRSignalStatus
& qualityinfo
) const
1580 return DoAddonCall(__func__
,
1581 [channelUid
, &qualityinfo
](const AddonInstance
* addon
)
1583 PVR_SIGNAL_STATUS info
{};
1584 const PVR_ERROR error
{
1585 addon
->toAddon
->GetSignalStatus(addon
, channelUid
, &info
)};
1586 if (error
== PVR_ERROR_NO_ERROR
)
1587 qualityinfo
= CPVRSignalStatus
{info
};
1589 addon
->toAddon
->FreeSignalStatus(addon
, &info
);
1594 PVR_ERROR
CPVRClient::GetDescrambleInfo(int channelUid
, CPVRDescrambleInfo
& descrambleinfo
) const
1598 [channelUid
, &descrambleinfo
](const AddonInstance
* addon
)
1600 PVR_DESCRAMBLE_INFO info
{};
1601 const PVR_ERROR error
{addon
->toAddon
->GetDescrambleInfo(addon
, channelUid
, &info
)};
1602 if (error
== PVR_ERROR_NO_ERROR
)
1603 descrambleinfo
= CPVRDescrambleInfo
{info
};
1605 addon
->toAddon
->FreeDescrambleInfo(addon
, &info
);
1608 m_clientCapabilities
.SupportsDescrambleInfo());
1611 PVR_ERROR
CPVRClient::GetChannelStreamProperties(const std::shared_ptr
<const CPVRChannel
>& channel
,
1613 CPVRStreamProperties
& props
) const
1617 [this, &channel
, source
, &props
](const AddonInstance
* addon
)
1619 if (!CanPlayChannel(channel
))
1620 return PVR_ERROR_NO_ERROR
; // no error, but no need to obtain the values from the addon
1622 const CAddonChannel addonChannel
{*channel
};
1624 PVR_NAMED_VALUE
** property_array
{nullptr};
1625 unsigned int size
{0};
1626 const PVR_ERROR error
{addon
->toAddon
->GetChannelStreamProperties(
1627 addon
, &addonChannel
, source
, &property_array
, &size
)};
1628 if (error
== PVR_ERROR_NO_ERROR
)
1629 WriteStreamProperties(property_array
, size
, props
);
1631 addon
->toAddon
->FreeProperties(addon
, property_array
, size
);
1636 PVR_ERROR
CPVRClient::GetRecordingStreamProperties(
1637 const std::shared_ptr
<const CPVRRecording
>& recording
, CPVRStreamProperties
& props
) const
1641 [this, &recording
, &props
](const AddonInstance
* addon
)
1643 if (!m_clientCapabilities
.SupportsRecordings())
1644 return PVR_ERROR_NO_ERROR
; // no error, but no need to obtain the values from the addon
1646 const CAddonRecording
addonRecording(*recording
);
1648 PVR_NAMED_VALUE
** property_array
{nullptr};
1649 unsigned int size
{0};
1650 const PVR_ERROR error
{addon
->toAddon
->GetRecordingStreamProperties(addon
, &addonRecording
,
1651 &property_array
, &size
)};
1652 if (error
== PVR_ERROR_NO_ERROR
)
1653 WriteStreamProperties(property_array
, size
, props
);
1655 addon
->toAddon
->FreeProperties(addon
, property_array
, size
);
1660 PVR_ERROR
CPVRClient::GetStreamProperties(PVR_STREAM_PROPERTIES
* props
) const
1662 return DoAddonCall(__func__
, [&props
](const AddonInstance
* addon
)
1663 { return addon
->toAddon
->GetStreamProperties(addon
, props
); });
1666 PVR_ERROR
CPVRClient::StreamClosed() const
1668 return DoAddonCall(__func__
, [](const AddonInstance
* addon
)
1669 { return addon
->toAddon
->StreamClosed(addon
); });
1672 PVR_ERROR
CPVRClient::DemuxReset()
1676 [](const AddonInstance
* addon
)
1678 addon
->toAddon
->DemuxReset(addon
);
1679 return PVR_ERROR_NO_ERROR
;
1681 m_clientCapabilities
.HandlesDemuxing());
1684 PVR_ERROR
CPVRClient::DemuxAbort()
1688 [](const AddonInstance
* addon
)
1690 addon
->toAddon
->DemuxAbort(addon
);
1691 return PVR_ERROR_NO_ERROR
;
1693 m_clientCapabilities
.HandlesDemuxing());
1696 PVR_ERROR
CPVRClient::DemuxFlush()
1700 [](const AddonInstance
* addon
)
1702 addon
->toAddon
->DemuxFlush(addon
);
1703 return PVR_ERROR_NO_ERROR
;
1705 m_clientCapabilities
.HandlesDemuxing());
1708 PVR_ERROR
CPVRClient::DemuxRead(DemuxPacket
*& packet
)
1712 [&packet
](const AddonInstance
* addon
)
1714 packet
= static_cast<DemuxPacket
*>(addon
->toAddon
->DemuxRead(addon
));
1715 return packet
? PVR_ERROR_NO_ERROR
: PVR_ERROR_NOT_IMPLEMENTED
;
1717 m_clientCapabilities
.HandlesDemuxing());
1720 const char* CPVRClient::ToString(const PVR_ERROR error
)
1724 case PVR_ERROR_NO_ERROR
:
1726 case PVR_ERROR_NOT_IMPLEMENTED
:
1727 return "not implemented";
1728 case PVR_ERROR_SERVER_ERROR
:
1729 return "server error";
1730 case PVR_ERROR_SERVER_TIMEOUT
:
1731 return "server timeout";
1732 case PVR_ERROR_RECORDING_RUNNING
:
1733 return "recording already running";
1734 case PVR_ERROR_ALREADY_PRESENT
:
1735 return "already present";
1736 case PVR_ERROR_REJECTED
:
1737 return "rejected by the backend";
1738 case PVR_ERROR_INVALID_PARAMETERS
:
1739 return "invalid parameters for this method";
1740 case PVR_ERROR_FAILED
:
1741 return "the command failed";
1742 case PVR_ERROR_UNKNOWN
:
1744 return "unknown error";
1748 PVR_ERROR
CPVRClient::DoAddonCall(const char* strFunctionName
,
1749 const std::function
<PVR_ERROR(const AddonInstance
*)>& function
,
1750 bool bIsImplemented
/* = true */,
1751 bool bCheckReadyToUse
/* = true */) const
1753 // Check preconditions.
1754 if (!bIsImplemented
)
1755 return PVR_ERROR_NOT_IMPLEMENTED
;
1757 if (m_bBlockAddonCalls
)
1759 CLog::Log(LOGWARNING
, "{}: Blocking call to add-on {}.", strFunctionName
, GetID());
1760 return PVR_ERROR_SERVER_ERROR
;
1763 if (bCheckReadyToUse
&& IgnoreClient())
1765 CLog::Log(LOGWARNING
, "{}: Blocking call to add-on {}. Add-on not (yet) connected.",
1766 strFunctionName
, GetID());
1767 return PVR_ERROR_SERVER_ERROR
;
1770 if (bCheckReadyToUse
&& !ReadyToUse())
1772 CLog::Log(LOGWARNING
, "{}: Blocking call to add-on {}. Add-on not ready to use.",
1773 strFunctionName
, GetID());
1774 return PVR_ERROR_SERVER_ERROR
;
1778 m_allAddonCallsFinished
.Reset();
1781 // CLog::LogFC(LOGDEBUG, LOGPVR, "Calling add-on function '{}' on client {}.", strFunctionName,
1784 const PVR_ERROR error
= function(m_ifc
.pvr
);
1786 // CLog::LogFC(LOGDEBUG, LOGPVR, "Called add-on function '{}' on client {}. return={}",
1787 // strFunctionName, GetID(), error);
1790 if (m_iAddonCalls
== 0)
1791 m_allAddonCallsFinished
.Set();
1793 // Log error, if any.
1794 if (error
!= PVR_ERROR_NO_ERROR
&& error
!= PVR_ERROR_NOT_IMPLEMENTED
)
1795 CLog::Log(LOGERROR
, "{}: Add-on {} returned an error: {}", strFunctionName
, GetID(),
1801 bool CPVRClient::CanPlayChannel(const std::shared_ptr
<const CPVRChannel
>& channel
) const
1803 return (m_bReadyToUse
&& ((m_clientCapabilities
.SupportsTV() && !channel
->IsRadio()) ||
1804 (m_clientCapabilities
.SupportsRadio() && channel
->IsRadio())));
1807 PVR_ERROR
CPVRClient::OpenLiveStream(const std::shared_ptr
<const CPVRChannel
>& channel
)
1810 return PVR_ERROR_INVALID_PARAMETERS
;
1812 return DoAddonCall(__func__
,
1813 [this, channel
](const AddonInstance
* addon
)
1817 if (!CanPlayChannel(channel
))
1819 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Add-on {} can not play channel '{}'",
1820 GetID(), channel
->ChannelName());
1821 return PVR_ERROR_SERVER_ERROR
;
1825 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Opening live stream for channel '{}'",
1826 channel
->ChannelName());
1827 const CAddonChannel addonChannel
{*channel
};
1828 return addon
->toAddon
->OpenLiveStream(addon
, &addonChannel
)
1829 ? PVR_ERROR_NO_ERROR
1830 : PVR_ERROR_NOT_IMPLEMENTED
;
1835 PVR_ERROR
CPVRClient::OpenRecordedStream(const std::shared_ptr
<const CPVRRecording
>& recording
,
1839 return PVR_ERROR_INVALID_PARAMETERS
;
1843 [this, recording
, &streamId
](const AddonInstance
* addon
)
1845 if (!m_clientCapabilities
.SupportsMultipleRecordedStreams())
1846 CloseRecordedStream(streamId
);
1848 const CAddonRecording
tag(*recording
);
1849 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Opening stream for recording '{}'", recording
->m_strTitle
);
1850 return addon
->toAddon
->OpenRecordedStream(addon
, &tag
, &streamId
)
1851 ? PVR_ERROR_NO_ERROR
1852 : PVR_ERROR_NOT_IMPLEMENTED
;
1854 m_clientCapabilities
.SupportsRecordings());
1857 PVR_ERROR
CPVRClient::CloseLiveStream()
1859 return DoAddonCall(__func__
,
1860 [](const AddonInstance
* addon
)
1862 addon
->toAddon
->CloseLiveStream(addon
);
1863 return PVR_ERROR_NO_ERROR
;
1867 PVR_ERROR
CPVRClient::CloseRecordedStream(int64_t streamId
)
1869 return DoAddonCall(__func__
,
1870 [streamId
](const AddonInstance
* addon
)
1872 addon
->toAddon
->CloseRecordedStream(addon
, streamId
);
1873 return PVR_ERROR_NO_ERROR
;
1877 PVR_ERROR
CPVRClient::IsRecordedStreamRealTime(int64_t streamId
, bool& isRealTime
) const
1879 if (m_clientCapabilities
.SupportsMultipleRecordedStreams())
1882 __func__
, [streamId
, &isRealTime
](const AddonInstance
* addon
)
1883 { return addon
->toAddon
->IsRecordedStreamRealTime(addon
, streamId
, &isRealTime
); });
1887 return IsRealTimeStream(isRealTime
);
1891 PVR_ERROR
CPVRClient::PauseRecordedStream(int64_t streamId
, bool paused
)
1893 if (m_clientCapabilities
.SupportsMultipleRecordedStreams())
1895 return DoAddonCall(__func__
, [streamId
, paused
](const AddonInstance
* addon
)
1896 { return addon
->toAddon
->PauseRecordedStream(addon
, streamId
, paused
); });
1900 return PauseStream(paused
);
1904 PVR_ERROR
CPVRClient::GetRecordedStreamTimes(int64_t streamId
, PVR_STREAM_TIMES
* times
) const
1906 if (m_clientCapabilities
.SupportsMultipleRecordedStreams())
1908 return DoAddonCall(__func__
, [streamId
, ×
](const AddonInstance
* addon
)
1909 { return addon
->toAddon
->GetRecordedStreamTimes(addon
, streamId
, times
); });
1913 return GetStreamTimes(times
);
1917 PVR_ERROR
CPVRClient::PauseStream(bool bPaused
)
1919 return DoAddonCall(__func__
,
1920 [bPaused
](const AddonInstance
* addon
)
1922 addon
->toAddon
->PauseStream(addon
, bPaused
);
1923 return PVR_ERROR_NO_ERROR
;
1927 PVR_ERROR
CPVRClient::SetSpeed(int speed
)
1929 return DoAddonCall(__func__
,
1930 [speed
](const AddonInstance
* addon
)
1932 addon
->toAddon
->SetSpeed(addon
, speed
);
1933 return PVR_ERROR_NO_ERROR
;
1937 PVR_ERROR
CPVRClient::FillBuffer(bool mode
)
1939 return DoAddonCall(__func__
,
1940 [mode
](const AddonInstance
* addon
)
1942 addon
->toAddon
->FillBuffer(addon
, mode
);
1943 return PVR_ERROR_NO_ERROR
;
1947 PVR_ERROR
CPVRClient::CanPauseStream(bool& bCanPause
) const
1950 return DoAddonCall(__func__
,
1951 [&bCanPause
](const AddonInstance
* addon
)
1953 bCanPause
= addon
->toAddon
->CanPauseStream(addon
);
1954 return PVR_ERROR_NO_ERROR
;
1958 PVR_ERROR
CPVRClient::CanSeekStream(bool& bCanSeek
) const
1961 return DoAddonCall(__func__
,
1962 [&bCanSeek
](const AddonInstance
* addon
)
1964 bCanSeek
= addon
->toAddon
->CanSeekStream(addon
);
1965 return PVR_ERROR_NO_ERROR
;
1969 PVR_ERROR
CPVRClient::GetStreamTimes(PVR_STREAM_TIMES
* times
) const
1971 return DoAddonCall(__func__
, [×
](const AddonInstance
* addon
)
1972 { return addon
->toAddon
->GetStreamTimes(addon
, times
); });
1975 PVR_ERROR
CPVRClient::IsRealTimeStream(bool& bRealTime
) const
1978 return DoAddonCall(__func__
,
1979 [&bRealTime
](const AddonInstance
* addon
)
1981 bRealTime
= addon
->toAddon
->IsRealTimeStream(addon
);
1982 return PVR_ERROR_NO_ERROR
;
1986 PVR_ERROR
CPVRClient::OnSystemSleep()
1988 return DoAddonCall(__func__
, [](const AddonInstance
* addon
)
1989 { return addon
->toAddon
->OnSystemSleep(addon
); });
1992 PVR_ERROR
CPVRClient::OnSystemWake()
1994 return DoAddonCall(__func__
, [](const AddonInstance
* addon
)
1995 { return addon
->toAddon
->OnSystemWake(addon
); });
1998 PVR_ERROR
CPVRClient::OnPowerSavingActivated()
2000 return DoAddonCall(__func__
, [](const AddonInstance
* addon
)
2001 { return addon
->toAddon
->OnPowerSavingActivated(addon
); });
2004 PVR_ERROR
CPVRClient::OnPowerSavingDeactivated()
2006 return DoAddonCall(__func__
, [](const AddonInstance
* addon
)
2007 { return addon
->toAddon
->OnPowerSavingDeactivated(addon
); });
2010 std::shared_ptr
<CPVRClientMenuHooks
> CPVRClient::GetMenuHooks() const
2013 m_menuhooks
= std::make_shared
<CPVRClientMenuHooks
>(ID());
2018 PVR_ERROR
CPVRClient::CallEpgTagMenuHook(const CPVRClientMenuHook
& hook
,
2019 const std::shared_ptr
<const CPVREpgInfoTag
>& tag
)
2021 return DoAddonCall(__func__
,
2022 [&hook
, &tag
](const AddonInstance
* addon
)
2024 CAddonEpgTag
addonTag(*tag
);
2026 PVR_MENUHOOK menuHook
;
2027 menuHook
.category
= PVR_MENUHOOK_EPG
;
2028 menuHook
.iHookId
= hook
.GetId();
2029 menuHook
.iLocalizedStringId
= hook
.GetLabelId();
2031 return addon
->toAddon
->CallEPGMenuHook(addon
, &menuHook
, &addonTag
);
2035 PVR_ERROR
CPVRClient::CallChannelMenuHook(const CPVRClientMenuHook
& hook
,
2036 const std::shared_ptr
<const CPVRChannel
>& channel
)
2038 return DoAddonCall(__func__
,
2039 [&hook
, &channel
](const AddonInstance
* addon
)
2041 const CAddonChannel addonChannel
{*channel
};
2043 PVR_MENUHOOK menuHook
;
2044 menuHook
.category
= PVR_MENUHOOK_CHANNEL
;
2045 menuHook
.iHookId
= hook
.GetId();
2046 menuHook
.iLocalizedStringId
= hook
.GetLabelId();
2048 return addon
->toAddon
->CallChannelMenuHook(addon
, &menuHook
, &addonChannel
);
2052 PVR_ERROR
CPVRClient::CallRecordingMenuHook(const CPVRClientMenuHook
& hook
,
2053 const std::shared_ptr
<const CPVRRecording
>& recording
,
2056 return DoAddonCall(__func__
,
2057 [&hook
, &recording
, &bDeleted
](const AddonInstance
* addon
)
2059 const CAddonRecording
tag(*recording
);
2061 PVR_MENUHOOK menuHook
;
2063 bDeleted
? PVR_MENUHOOK_DELETED_RECORDING
: PVR_MENUHOOK_RECORDING
;
2064 menuHook
.iHookId
= hook
.GetId();
2065 menuHook
.iLocalizedStringId
= hook
.GetLabelId();
2067 return addon
->toAddon
->CallRecordingMenuHook(addon
, &menuHook
, &tag
);
2071 PVR_ERROR
CPVRClient::CallTimerMenuHook(const CPVRClientMenuHook
& hook
,
2072 const std::shared_ptr
<const CPVRTimerInfoTag
>& timer
)
2074 return DoAddonCall(__func__
,
2075 [&hook
, &timer
](const AddonInstance
* addon
)
2077 const CAddonTimer
tag(*timer
);
2079 PVR_MENUHOOK menuHook
;
2080 menuHook
.category
= PVR_MENUHOOK_TIMER
;
2081 menuHook
.iHookId
= hook
.GetId();
2082 menuHook
.iLocalizedStringId
= hook
.GetLabelId();
2084 return addon
->toAddon
->CallTimerMenuHook(addon
, &menuHook
, &tag
);
2088 PVR_ERROR
CPVRClient::CallSettingsMenuHook(const CPVRClientMenuHook
& hook
)
2090 return DoAddonCall(__func__
,
2091 [&hook
](const AddonInstance
* addon
)
2093 PVR_MENUHOOK menuHook
;
2094 menuHook
.category
= PVR_MENUHOOK_SETTING
;
2095 menuHook
.iHookId
= hook
.GetId();
2096 menuHook
.iLocalizedStringId
= hook
.GetLabelId();
2098 return addon
->toAddon
->CallSettingsMenuHook(addon
, &menuHook
);
2102 void CPVRClient::SetPriority(int iPriority
)
2104 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
2105 if (m_priority
!= iPriority
)
2107 m_priority
= iPriority
;
2108 if (m_iClientId
!= PVR_CLIENT_INVALID_UID
)
2110 CServiceBroker::GetPVRManager().GetTVDatabase()->Persist(*this);
2112 CServiceBroker::GetPVRManager().PublishEvent(PVREvent::ClientsPrioritiesInvalidated
);
2116 int CPVRClient::GetPriority() const
2118 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
2119 if (!m_priority
.has_value() && m_iClientId
!= PVR_CLIENT_INVALID_UID
)
2121 m_priority
= CServiceBroker::GetPVRManager().GetTVDatabase()->GetPriority(*this);
2126 const CDateTime
& CPVRClient::GetDateTimeFirstChannelsAdded() const
2128 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
2129 if (!m_firstChannelsAdded
.has_value() && m_iClientId
!= PVR_CLIENT_INVALID_UID
)
2131 m_firstChannelsAdded
=
2132 CServiceBroker::GetPVRManager().GetTVDatabase()->GetDateTimeFirstChannelsAdded(*this);
2134 return *m_firstChannelsAdded
;
2137 void CPVRClient::SetDateTimeFirstChannelsAdded(const CDateTime
& dateTime
)
2139 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
2140 if (m_firstChannelsAdded
!= dateTime
)
2142 m_firstChannelsAdded
= dateTime
;
2143 if (m_iClientId
!= PVR_CLIENT_INVALID_UID
)
2145 CServiceBroker::GetPVRManager().GetTVDatabase()->Persist(*this);
2150 void CPVRClient::HandleAddonCallback(const char* strFunctionName
,
2152 const std::function
<void(CPVRClient
* client
)>& function
,
2153 bool bForceCall
/* = false */)
2155 // Check preconditions.
2156 CPVRClient
* client
= static_cast<CPVRClient
*>(kodiInstance
);
2159 CLog::Log(LOGERROR
, "{}: No instance pointer given!", strFunctionName
);
2163 if (!bForceCall
&& client
->m_bBlockAddonCalls
&& client
->m_iAddonCalls
== 0)
2165 CLog::Log(LOGWARNING
, LOGPVR
, "{}: Ignoring callback from PVR client '{}'", strFunctionName
,
2174 void CPVRClient::cb_transfer_channel_group(void* kodiInstance
,
2175 const PVR_HANDLE handle
,
2176 const PVR_CHANNEL_GROUP
* group
)
2178 HandleAddonCallback(__func__
, kodiInstance
,
2179 [&](CPVRClient
* client
)
2181 if (!handle
|| !group
)
2183 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2187 if (strlen(group
->strGroupName
) == 0)
2189 CLog::LogF(LOGERROR
, "Empty group name");
2193 // transfer this entry to the groups container
2194 CPVRChannelGroups
* kodiGroups
=
2195 static_cast<CPVRChannelGroups
*>(handle
->dataAddress
);
2196 const auto transferGroup
= kodiGroups
->GetGroupFactory()->CreateClientGroup(
2197 *group
, client
->GetID(), kodiGroups
->GetGroupAll());
2198 kodiGroups
->UpdateFromClient(transferGroup
);
2202 void CPVRClient::cb_transfer_channel_group_member(void* kodiInstance
,
2203 const PVR_HANDLE handle
,
2204 const PVR_CHANNEL_GROUP_MEMBER
* member
)
2206 HandleAddonCallback(__func__
, kodiInstance
,
2207 [&](CPVRClient
* client
)
2209 if (!handle
|| !member
)
2211 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2215 const std::shared_ptr
<CPVRChannel
> channel
=
2216 CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(
2217 member
->iChannelUniqueId
, client
->GetID());
2220 CLog::LogF(LOGERROR
, "Cannot find group '{}' or channel '{}'",
2221 member
->strGroupName
, member
->iChannelUniqueId
);
2225 auto* groupMembers
=
2226 static_cast<std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>>*>(
2227 handle
->dataAddress
);
2228 groupMembers
->emplace_back(std::make_shared
<CPVRChannelGroupMember
>(
2229 member
->strGroupName
, client
->GetID(), member
->iOrder
, channel
));
2234 void CPVRClient::cb_transfer_epg_entry(void* kodiInstance
,
2235 const PVR_HANDLE handle
,
2236 const EPG_TAG
* epgentry
)
2238 HandleAddonCallback(__func__
, kodiInstance
,
2239 [&](CPVRClient
* client
)
2241 if (!handle
|| !epgentry
)
2243 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2247 // transfer this entry to the epg
2248 CPVREpg
* epg
= static_cast<CPVREpg
*>(handle
->dataAddress
);
2249 epg
->UpdateEntry(epgentry
, client
->GetID());
2253 void CPVRClient::cb_transfer_provider_entry(void* kodiInstance
,
2254 const PVR_HANDLE handle
,
2255 const PVR_PROVIDER
* provider
)
2259 CLog::LogF(LOGERROR
, "Invalid handler data");
2263 CPVRClient
* client
= static_cast<CPVRClient
*>(kodiInstance
);
2264 CPVRProvidersContainer
* kodiProviders
= static_cast<CPVRProvidersContainer
*>(handle
->dataAddress
);
2265 if (!provider
|| !client
|| !kodiProviders
)
2267 CLog::LogF(LOGERROR
, "Invalid handler data");
2271 /* transfer this entry to the internal channels group */
2272 std::shared_ptr
<CPVRProvider
> transferProvider(
2273 std::make_shared
<CPVRProvider
>(*provider
, client
->GetID()));
2274 kodiProviders
->UpdateFromClient(transferProvider
);
2277 void CPVRClient::cb_transfer_channel_entry(void* kodiInstance
,
2278 const PVR_HANDLE handle
,
2279 const PVR_CHANNEL
* channel
)
2281 HandleAddonCallback(
2282 __func__
, kodiInstance
,
2283 [&](CPVRClient
* client
)
2285 if (!handle
|| !channel
)
2287 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2292 static_cast<std::vector
<std::shared_ptr
<CPVRChannel
>>*>(handle
->dataAddress
);
2293 channels
->emplace_back(std::make_shared
<CPVRChannel
>(*channel
, client
->GetID()));
2297 void CPVRClient::cb_transfer_recording_entry(void* kodiInstance
,
2298 const PVR_HANDLE handle
,
2299 const PVR_RECORDING
* recording
)
2301 HandleAddonCallback(__func__
, kodiInstance
,
2302 [&](CPVRClient
* client
)
2304 if (!handle
|| !recording
)
2306 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2310 // transfer this entry to the recordings container
2311 const std::shared_ptr
<CPVRRecording
> transferRecording
=
2312 std::make_shared
<CPVRRecording
>(*recording
, client
->GetID());
2313 CPVRRecordings
* recordings
=
2314 static_cast<CPVRRecordings
*>(handle
->dataAddress
);
2315 recordings
->UpdateFromClient(transferRecording
, *client
);
2319 void CPVRClient::cb_transfer_timer_entry(void* kodiInstance
,
2320 const PVR_HANDLE handle
,
2321 const PVR_TIMER
* timer
)
2323 HandleAddonCallback(__func__
, kodiInstance
,
2324 [&](CPVRClient
* client
)
2326 if (!handle
|| !timer
)
2328 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2332 // Note: channel can be nullptr here, for instance for epg-based timer rules
2333 // ("record on any channel" condition)
2334 const std::shared_ptr
<CPVRChannel
> channel
=
2335 CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(
2336 timer
->iClientChannelUid
, client
->GetID());
2338 // transfer this entry to the timers container
2339 const std::shared_ptr
<CPVRTimerInfoTag
> transferTimer
=
2340 std::make_shared
<CPVRTimerInfoTag
>(*timer
, channel
, client
->GetID());
2341 CPVRTimersContainer
* timers
=
2342 static_cast<CPVRTimersContainer
*>(handle
->dataAddress
);
2343 timers
->UpdateFromClient(transferTimer
);
2347 void CPVRClient::cb_add_menu_hook(void* kodiInstance
, const PVR_MENUHOOK
* hook
)
2349 HandleAddonCallback(__func__
, kodiInstance
,
2350 [&](CPVRClient
* client
)
2354 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2358 client
->GetMenuHooks()->AddHook(*hook
);
2362 void CPVRClient::cb_recording_notification(void* kodiInstance
,
2363 const char* strName
,
2364 const char* strFileName
,
2367 HandleAddonCallback(
2368 __func__
, kodiInstance
,
2369 [&](CPVRClient
* client
)
2373 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2377 const std::string strLine1
= StringUtils::Format(
2378 g_localizeStrings
.Get(bOnOff
? 19197 : 19198), client
->GetFullClientName());
2379 std::string strLine2
;
2383 strLine2
= strFileName
;
2385 // display a notification for 5 seconds
2386 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info
, strLine1
, strLine2
, 5000,
2388 auto eventLog
= CServiceBroker::GetEventLog();
2390 eventLog
->Add(EventPtr(new CNotificationEvent(client
->GetFullClientName(), strLine1
,
2391 client
->Icon(), strLine2
)));
2393 CLog::LogFC(LOGDEBUG
, LOGPVR
, "Recording {} on client {}. name='{}' filename='{}'",
2394 bOnOff
? "started" : "finished", client
->GetID(), strName
, strFileName
);
2398 void CPVRClient::cb_trigger_channel_update(void* kodiInstance
)
2400 HandleAddonCallback(__func__
, kodiInstance
,
2401 [&](CPVRClient
* client
)
2403 // update channels in the next iteration of the pvrmanager's main loop
2404 CServiceBroker::GetPVRManager().TriggerChannelsUpdate(client
->GetID());
2408 void CPVRClient::cb_trigger_provider_update(void* kodiInstance
)
2410 HandleAddonCallback(__func__
, kodiInstance
,
2411 [&](CPVRClient
* client
)
2413 /* update the providers table in the next iteration of the pvrmanager's main loop */
2414 CServiceBroker::GetPVRManager().TriggerProvidersUpdate(client
->GetID());
2418 void CPVRClient::cb_trigger_timer_update(void* kodiInstance
)
2420 HandleAddonCallback(__func__
, kodiInstance
,
2421 [&](CPVRClient
* client
)
2423 // update timers in the next iteration of the pvrmanager's main loop
2424 CServiceBroker::GetPVRManager().TriggerTimersUpdate(client
->GetID());
2428 void CPVRClient::cb_trigger_recording_update(void* kodiInstance
)
2430 HandleAddonCallback(__func__
, kodiInstance
,
2431 [&](CPVRClient
* client
)
2433 // update recordings in the next iteration of the pvrmanager's main loop
2434 CServiceBroker::GetPVRManager().TriggerRecordingsUpdate(client
->GetID());
2438 void CPVRClient::cb_trigger_channel_groups_update(void* kodiInstance
)
2440 HandleAddonCallback(__func__
, kodiInstance
,
2441 [&](CPVRClient
* client
)
2443 // update all channel groups in the next iteration of the pvrmanager's main loop
2444 CServiceBroker::GetPVRManager().TriggerChannelGroupsUpdate(client
->GetID());
2448 void CPVRClient::cb_trigger_epg_update(void* kodiInstance
, unsigned int iChannelUid
)
2450 HandleAddonCallback(__func__
, kodiInstance
,
2451 [&](CPVRClient
* client
) {
2452 CServiceBroker::GetPVRManager().EpgContainer().UpdateRequest(
2453 client
->GetID(), iChannelUid
);
2457 void CPVRClient::cb_free_demux_packet(void* kodiInstance
, DEMUX_PACKET
* pPacket
)
2459 HandleAddonCallback(
2460 __func__
, kodiInstance
,
2461 [&](CPVRClient
* client
)
2462 { CDVDDemuxUtils::FreeDemuxPacket(static_cast<DemuxPacket
*>(pPacket
)); },
2466 DEMUX_PACKET
* CPVRClient::cb_allocate_demux_packet(void* kodiInstance
, int iDataSize
)
2468 DEMUX_PACKET
* result
= nullptr;
2470 HandleAddonCallback(
2471 __func__
, kodiInstance
,
2472 [&](CPVRClient
* client
) { result
= CDVDDemuxUtils::AllocateDemuxPacket(iDataSize
); }, true);
2477 void CPVRClient::cb_connection_state_change(void* kodiInstance
,
2478 const char* strConnectionString
,
2479 PVR_CONNECTION_STATE newState
,
2480 const char* strMessage
)
2482 HandleAddonCallback(__func__
, kodiInstance
,
2483 [&](CPVRClient
* client
)
2485 if (!strConnectionString
)
2487 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2491 const PVR_CONNECTION_STATE
prevState(client
->GetConnectionState());
2492 if (prevState
== newState
)
2495 CLog::LogFC(LOGDEBUG
, LOGPVR
,
2496 "Connection state for client {} changed from {} to {}",
2497 client
->GetID(), prevState
, newState
);
2499 client
->SetConnectionState(newState
);
2505 CServiceBroker::GetPVRManager().ConnectionStateChange(
2506 client
, std::string(strConnectionString
), newState
, msg
);
2510 void CPVRClient::cb_epg_event_state_change(void* kodiInstance
,
2512 EPG_EVENT_STATE newState
)
2514 HandleAddonCallback(__func__
, kodiInstance
,
2515 [&](CPVRClient
* client
)
2519 CLog::LogF(LOGERROR
, "Invalid callback parameter(s)");
2523 // Note: channel data and epg id may not yet be available. Tag will be fully initialized later.
2524 const std::shared_ptr
<CPVREpgInfoTag
> epgTag
=
2525 std::make_shared
<CPVREpgInfoTag
>(*tag
, client
->GetID(), nullptr, -1);
2526 CServiceBroker::GetPVRManager().EpgContainer().UpdateFromClient(epgTag
,
2534 virtual ~CCodecIds() = default;
2536 static CCodecIds
& GetInstance()
2538 static CCodecIds _instance
;
2542 PVR_CODEC
GetCodecByName(const char* strCodecName
)
2544 PVR_CODEC retVal
= PVR_INVALID_CODEC
;
2545 if (strlen(strCodecName
) == 0)
2548 std::string strUpperCodecName
= strCodecName
;
2549 StringUtils::ToUpper(strUpperCodecName
);
2551 std::map
<std::string
, PVR_CODEC
>::const_iterator it
= m_lookup
.find(strUpperCodecName
);
2552 if (it
!= m_lookup
.end())
2553 retVal
= it
->second
;
2561 // get ids and names
2562 const AVCodec
* codec
= nullptr;
2565 while ((codec
= av_codec_iterate(&i
)))
2567 if (av_codec_is_decoder(codec
))
2569 tmp
.codec_type
= static_cast<PVR_CODEC_TYPE
>(codec
->type
);
2570 tmp
.codec_id
= codec
->id
;
2572 std::string strUpperCodecName
= codec
->name
;
2573 StringUtils::ToUpper(strUpperCodecName
);
2575 m_lookup
.insert(std::make_pair(strUpperCodecName
, tmp
));
2579 // teletext is not returned by av_codec_next. we got our own decoder
2580 tmp
.codec_type
= PVR_CODEC_TYPE_SUBTITLE
;
2581 tmp
.codec_id
= AV_CODEC_ID_DVB_TELETEXT
;
2582 m_lookup
.insert(std::make_pair("TELETEXT", tmp
));
2584 // rds is not returned by av_codec_next. we got our own decoder
2585 tmp
.codec_type
= PVR_CODEC_TYPE_RDS
;
2586 tmp
.codec_id
= AV_CODEC_ID_NONE
;
2587 m_lookup
.insert(std::make_pair("RDS", tmp
));
2589 // ID3 is not returned by av_codec_next. we got our own decoder
2590 tmp
.codec_type
= PVR_CODEC_TYPE_ID3
;
2591 tmp
.codec_id
= AV_CODEC_ID_NONE
;
2592 m_lookup
.insert({"ID3", tmp
});
2595 std::map
<std::string
, PVR_CODEC
> m_lookup
;
2598 PVR_CODEC
CPVRClient::cb_get_codec_by_name(const void* kodiInstance
, const char* strCodecName
)
2600 PVR_CODEC result
= PVR_INVALID_CODEC
;
2602 HandleAddonCallback(
2603 __func__
, const_cast<void*>(kodiInstance
),
2604 [&](CPVRClient
* client
) { result
= CCodecIds::GetInstance().GetCodecByName(strCodecName
); },