aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/pvr/addons/PVRClient.cpp419
-rw-r--r--xbmc/pvr/addons/PVRClient.h15
2 files changed, 241 insertions, 193 deletions
diff --git a/xbmc/pvr/addons/PVRClient.cpp b/xbmc/pvr/addons/PVRClient.cpp
index db09d2f210..700b959774 100644
--- a/xbmc/pvr/addons/PVRClient.cpp
+++ b/xbmc/pvr/addons/PVRClient.cpp
@@ -104,6 +104,8 @@ void CPVRClient::ResetProperties(int iClientId /* = PVR_INVALID_CLIENT_ID */)
m_strClientPath = CSpecialProtocol::TranslatePath(Path());
m_bReadyToUse = false;
m_bBlockAddonCalls = false;
+ m_iAddonCalls = 0;
+ m_allAddonCallsFinished.Set();
m_connectionState = PVR_CONNECTION_STATE_UNKNOWN;
m_prevConnectionState = PVR_CONNECTION_STATE_UNKNOWN;
m_ignoreClient = false;
@@ -156,7 +158,6 @@ ADDON_STATUS CPVRClient::Create(int iClientId)
if (iClientId <= PVR_INVALID_CLIENT_ID)
return status;
- /* reset all properties to defaults */
ResetProperties(iClientId);
/* initialise the add-on */
@@ -176,16 +177,18 @@ void CPVRClient::Destroy()
m_bReadyToUse = false;
- /* reset 'ready to use' to false */
CLog::LogFC(LOGDEBUG, LOGPVR, "Destroying PVR add-on instance '{}'", GetFriendlyName());
- /* destroy the add-on */
+ m_bBlockAddonCalls = true;
+ m_allAddonCallsFinished.Wait();
+
DestroyInstance();
+ CLog::LogFC(LOGDEBUG, LOGPVR, "PVR add-on instance '{}' destroyed", GetFriendlyName());
+
if (m_menuhooks)
m_menuhooks->Clear();
- /* reset all properties to defaults */
ResetProperties();
}
@@ -1378,8 +1381,15 @@ PVR_ERROR CPVRClient::DoAddonCall(const char* strFunctionName,
return PVR_ERROR_SERVER_ERROR;
// Call.
+ m_allAddonCallsFinished.Reset();
+ m_iAddonCalls++;
+
const PVR_ERROR error = function(&m_struct);
+ m_iAddonCalls--;
+ if (m_iAddonCalls == 0)
+ m_allAddonCallsFinished.Set();
+
// Log error, if any.
if (error != PVR_ERROR_NO_ERROR && error != PVR_ERROR_NOT_IMPLEMENTED)
CLog::LogFunction(LOGERROR, strFunctionName, "Add-on '{}' returned an error: {}",
@@ -1647,177 +1657,176 @@ int CPVRClient::GetPriority() const
return m_iPriority;
}
-void CPVRClient::cb_transfer_channel_group(void* kodiInstance,
- const ADDON_HANDLE handle,
- const PVR_CHANNEL_GROUP* group)
+void CPVRClient::HandleAddonCallback(const char* strFunctionName,
+ void* kodiInstance,
+ const std::function<void(CPVRClient* client)>& function,
+ bool bForceCall /* = false */)
{
- if (!handle)
+ // Check preconditions.
+ CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
+ if (!client)
{
- CLog::LogF(LOGERROR, "Invalid handler data");
+ CLog::LogFunction(LOGERROR, strFunctionName, "No instance pointer given!");
return;
}
- CPVRChannelGroups* kodiGroups = static_cast<CPVRChannelGroups*>(handle->dataAddress);
- if (!group || !kodiGroups)
+ if (!bForceCall && client->m_bBlockAddonCalls && client->m_iAddonCalls == 0)
{
- CLog::LogF(LOGERROR, "Invalid handler data");
+ CLog::LogFunction(LOGWARNING, strFunctionName, LOGPVR, "Ignoring callback from PVR client '{}'",
+ client->GetFriendlyName());
return;
}
- if (strlen(group->strGroupName) == 0)
- {
- CLog::LogF(LOGERROR, "Empty group name");
- return;
- }
+ // Call.
+ function(client);
+}
- /* transfer this entry to the groups container */
- CPVRChannelGroup transferGroup(*group, kodiGroups->GetGroupAll());
- kodiGroups->UpdateFromClient(transferGroup);
+void CPVRClient::cb_transfer_channel_group(void* kodiInstance,
+ const ADDON_HANDLE handle,
+ const PVR_CHANNEL_GROUP* group)
+{
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !group)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
+
+ if (strlen(group->strGroupName) == 0)
+ {
+ CLog::LogF(LOGERROR, "Empty group name");
+ return;
+ }
+
+ // transfer this entry to the groups container
+ CPVRChannelGroups* kodiGroups = static_cast<CPVRChannelGroups*>(handle->dataAddress);
+ CPVRChannelGroup transferGroup(*group, kodiGroups->GetGroupAll());
+ kodiGroups->UpdateFromClient(transferGroup);
+ });
}
void CPVRClient::cb_transfer_channel_group_member(void* kodiInstance,
const ADDON_HANDLE handle,
const PVR_CHANNEL_GROUP_MEMBER* member)
{
- if (!handle)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- CPVRChannelGroup* group = static_cast<CPVRChannelGroup*>(handle->dataAddress);
- if (!member || !client || !group)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !member)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- std::shared_ptr<CPVRChannel> channel =
- CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(member->iChannelUniqueId,
- client->GetID());
- if (!channel)
- {
- CLog::LogF(LOGERROR, "Cannot find group '{}' or channel '{}'", member->strGroupName,
- member->iChannelUniqueId);
- }
- else if (group->IsRadio() == channel->IsRadio())
- {
- /* transfer this entry to the group */
- group->AddToGroup(channel, CPVRChannelNumber(), member->iOrder, true,
- CPVRChannelNumber(member->iChannelNumber, member->iSubChannelNumber));
- }
+ CPVRChannelGroup* group = static_cast<CPVRChannelGroup*>(handle->dataAddress);
+ const std::shared_ptr<CPVRChannel> channel =
+ CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(member->iChannelUniqueId,
+ client->GetID());
+ if (!channel)
+ {
+ CLog::LogF(LOGERROR, "Cannot find group '{}' or channel '{}'", member->strGroupName,
+ member->iChannelUniqueId);
+ }
+ else if (group->IsRadio() == channel->IsRadio())
+ {
+ // add this entry to the group
+ group->AddToGroup(channel, CPVRChannelNumber(), member->iOrder, true,
+ CPVRChannelNumber(member->iChannelNumber, member->iSubChannelNumber));
+ }
+ });
}
void CPVRClient::cb_transfer_epg_entry(void* kodiInstance,
const ADDON_HANDLE handle,
const EPG_TAG* epgentry)
{
- if (!handle)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- CPVREpg* kodiEpg = static_cast<CPVREpg*>(handle->dataAddress);
- if (!epgentry || !client || !kodiEpg)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !epgentry)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- /* transfer this entry to the epg */
- kodiEpg->UpdateEntry(epgentry, client->GetID());
+ // transfer this entry to the epg
+ CPVREpg* epg = static_cast<CPVREpg*>(handle->dataAddress);
+ epg->UpdateEntry(epgentry, client->GetID());
+ });
}
void CPVRClient::cb_transfer_channel_entry(void* kodiInstance,
const ADDON_HANDLE handle,
const PVR_CHANNEL* channel)
{
- if (!handle)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- CPVRChannelGroupInternal* kodiChannels =
- static_cast<CPVRChannelGroupInternal*>(handle->dataAddress);
- if (!channel || !client || !kodiChannels)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !channel)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- /* transfer this entry to the internal channels group */
- std::shared_ptr<CPVRChannel> transferChannel(new CPVRChannel(*channel, client->GetID()));
- kodiChannels->UpdateFromClient(transferChannel, CPVRChannelNumber(), channel->iOrder,
- transferChannel->ClientChannelNumber());
+ // transfer this entry to the internal channels group
+ const std::shared_ptr<CPVRChannel> transferChannel =
+ std::make_shared<CPVRChannel>(*channel, client->GetID());
+ CPVRChannelGroupInternal* channels =
+ static_cast<CPVRChannelGroupInternal*>(handle->dataAddress);
+ channels->UpdateFromClient(transferChannel, CPVRChannelNumber(), channel->iOrder,
+ transferChannel->ClientChannelNumber());
+ });
}
void CPVRClient::cb_transfer_recording_entry(void* kodiInstance,
const ADDON_HANDLE handle,
const PVR_RECORDING* recording)
{
- if (!handle)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- CPVRRecordings* kodiRecordings = static_cast<CPVRRecordings*>(handle->dataAddress);
- if (!recording || !client || !kodiRecordings)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !recording)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- /* transfer this entry to the recordings container */
- std::shared_ptr<CPVRRecording> transferRecording(new CPVRRecording(*recording, client->GetID()));
- kodiRecordings->UpdateFromClient(transferRecording, *client);
+ // transfer this entry to the recordings container
+ const std::shared_ptr<CPVRRecording> transferRecording =
+ std::make_shared<CPVRRecording>(*recording, client->GetID());
+ CPVRRecordings* recordings = static_cast<CPVRRecordings*>(handle->dataAddress);
+ recordings->UpdateFromClient(transferRecording, *client);
+ });
}
void CPVRClient::cb_transfer_timer_entry(void* kodiInstance,
const ADDON_HANDLE handle,
const PVR_TIMER* timer)
{
- if (!handle)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- CPVRTimersContainer* kodiTimers = static_cast<CPVRTimersContainer*>(handle->dataAddress);
- if (!timer || !client || !kodiTimers)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- /* Note: channel can be NULL here, for instance for epg-based timer rules ("record on any channel" condition). */
- std::shared_ptr<CPVRChannel> channel =
- CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(timer->iClientChannelUid,
- client->GetID());
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!handle || !timer)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- /* transfer this entry to the timers container */
- std::shared_ptr<CPVRTimerInfoTag> transferTimer(
- new CPVRTimerInfoTag(*timer, channel, client->GetID()));
- kodiTimers->UpdateFromClient(transferTimer);
+ // Note: channel can be nullptr here, for instance for epg-based timer rules
+ // ("record on any channel" condition)
+ const std::shared_ptr<CPVRChannel> channel =
+ CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(timer->iClientChannelUid,
+ client->GetID());
+
+ // transfer this entry to the timers container
+ const std::shared_ptr<CPVRTimerInfoTag> transferTimer =
+ std::make_shared<CPVRTimerInfoTag>(*timer, channel, client->GetID());
+ CPVRTimersContainer* timers = static_cast<CPVRTimersContainer*>(handle->dataAddress);
+ timers->UpdateFromClient(transferTimer);
+ });
}
void CPVRClient::cb_add_menu_hook(void* kodiInstance, const PVR_MENUHOOK* hook)
{
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- if (!hook || !client)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!hook)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- client->GetMenuHooks()->AddHook(*hook);
+ client->GetMenuHooks()->AddHook(*hook);
+ });
}
void CPVRClient::cb_recording_notification(void* kodiInstance,
@@ -1825,74 +1834,89 @@ void CPVRClient::cb_recording_notification(void* kodiInstance,
const char* strFileName,
bool bOnOff)
{
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- if (!client || !strFileName)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- std::string strLine1 = StringUtils::Format(g_localizeStrings.Get(bOnOff ? 19197 : 19198).c_str(),
- client->Name().c_str());
- std::string strLine2;
- if (strName)
- strLine2 = strName;
- else if (strFileName)
- strLine2 = strFileName;
-
- /* display a notification for 5 seconds */
- CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, strLine1, strLine2, 5000, false);
- CServiceBroker::GetEventLog().Add(
- EventPtr(new CNotificationEvent(client->Name(), strLine1, client->Icon(), strLine2)));
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!strFileName)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- CLog::LogFC(LOGDEBUG, LOGPVR, "Recording {} on client '{}'. name='{}' filename='{}'",
- bOnOff ? "started" : "finished", client->Name(), strName, strFileName);
+ const std::string strLine1 = StringUtils::Format(
+ g_localizeStrings.Get(bOnOff ? 19197 : 19198).c_str(), client->Name().c_str());
+ std::string strLine2;
+ if (strName)
+ strLine2 = strName;
+ else if (strFileName)
+ strLine2 = strFileName;
+
+ // display a notification for 5 seconds
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, strLine1, strLine2, 5000,
+ false);
+ CServiceBroker::GetEventLog().Add(
+ EventPtr(new CNotificationEvent(client->Name(), strLine1, client->Icon(), strLine2)));
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Recording {} on client '{}'. name='{}' filename='{}'",
+ bOnOff ? "started" : "finished", client->Name(), strName, strFileName);
+ });
}
void CPVRClient::cb_trigger_channel_update(void* kodiInstance)
{
- /* update the channels table in the next iteration of the pvrmanager's main loop */
- CServiceBroker::GetPVRManager().TriggerChannelsUpdate();
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ // update channels in the next iteration of the pvrmanager's main loop
+ CServiceBroker::GetPVRManager().TriggerChannelsUpdate();
+ });
}
void CPVRClient::cb_trigger_timer_update(void* kodiInstance)
{
- /* update the timers table in the next iteration of the pvrmanager's main loop */
- CServiceBroker::GetPVRManager().TriggerTimersUpdate();
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ // update timers in the next iteration of the pvrmanager's main loop
+ CServiceBroker::GetPVRManager().TriggerTimersUpdate();
+ });
}
void CPVRClient::cb_trigger_recording_update(void* kodiInstance)
{
- /* update the recordings table in the next iteration of the pvrmanager's main loop */
- CServiceBroker::GetPVRManager().TriggerRecordingsUpdate();
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ // update recordings in the next iteration of the pvrmanager's main loop
+ CServiceBroker::GetPVRManager().TriggerRecordingsUpdate();
+ });
}
void CPVRClient::cb_trigger_channel_groups_update(void* kodiInstance)
{
- /* update all channel groups in the next iteration of the pvrmanager's main loop */
- CServiceBroker::GetPVRManager().TriggerChannelGroupsUpdate();
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ // update all channel groups in the next iteration of the pvrmanager's main loop
+ CServiceBroker::GetPVRManager().TriggerChannelGroupsUpdate();
+ });
}
void CPVRClient::cb_trigger_epg_update(void* kodiInstance, unsigned int iChannelUid)
{
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- if (!client)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
-
- CServiceBroker::GetPVRManager().EpgContainer().UpdateRequest(client->GetID(), iChannelUid);
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ CServiceBroker::GetPVRManager().EpgContainer().UpdateRequest(client->GetID(), iChannelUid);
+ });
}
void CPVRClient::cb_free_demux_packet(void* kodiInstance, DEMUX_PACKET* pPacket)
{
- CDVDDemuxUtils::FreeDemuxPacket(static_cast<DemuxPacket*>(pPacket));
+ HandleAddonCallback(__func__, kodiInstance,
+ [&](CPVRClient* client) {
+ CDVDDemuxUtils::FreeDemuxPacket(static_cast<DemuxPacket*>(pPacket));
+ },
+ true);
}
DEMUX_PACKET* CPVRClient::cb_allocate_demux_packet(void* kodiInstance, int iDataSize)
{
- return CDVDDemuxUtils::AllocateDemuxPacket(iDataSize);
+ DEMUX_PACKET* result = nullptr;
+
+ HandleAddonCallback(
+ __func__, kodiInstance,
+ [&](CPVRClient* client) { result = CDVDDemuxUtils::AllocateDemuxPacket(iDataSize); }, true);
+
+ return result;
}
void CPVRClient::cb_connection_state_change(void* kodiInstance,
@@ -1900,46 +1924,48 @@ void CPVRClient::cb_connection_state_change(void* kodiInstance,
PVR_CONNECTION_STATE newState,
const char* strMessage)
{
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- if (!client || !strConnectionString)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!strConnectionString)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- const PVR_CONNECTION_STATE prevState(client->GetConnectionState());
- if (prevState == newState)
- return;
+ const PVR_CONNECTION_STATE prevState(client->GetConnectionState());
+ if (prevState == newState)
+ return;
- CLog::LogFC(LOGDEBUG, LOGPVR,
- "State for connection '{}' on client '{}' changed from '{}' to '{}'",
- strConnectionString, client->Name(), prevState, newState);
+ CLog::LogFC(LOGDEBUG, LOGPVR,
+ "State for connection '{}' on client '{}' changed from '{}' to '{}'",
+ strConnectionString, client->Name(), prevState, newState);
- client->SetConnectionState(newState);
+ client->SetConnectionState(newState);
- std::string msg;
- if (strMessage != nullptr)
- msg = strMessage;
+ std::string msg;
+ if (strMessage)
+ msg = strMessage;
- CServiceBroker::GetPVRManager().ConnectionStateChange(client, std::string(strConnectionString),
- newState, msg);
+ CServiceBroker::GetPVRManager().ConnectionStateChange(client, std::string(strConnectionString),
+ newState, msg);
+ });
}
void CPVRClient::cb_epg_event_state_change(void* kodiInstance,
EPG_TAG* tag,
EPG_EVENT_STATE newState)
{
- CPVRClient* client = static_cast<CPVRClient*>(kodiInstance);
- if (!client || !tag)
- {
- CLog::LogF(LOGERROR, "Invalid handler data");
- return;
- }
+ HandleAddonCallback(__func__, kodiInstance, [&](CPVRClient* client) {
+ if (!tag)
+ {
+ CLog::LogF(LOGERROR, "Invalid callback parameter(s)");
+ return;
+ }
- // Note: channel data and epg id may not yet be available. Tag will be fully initialized later.
- const std::shared_ptr<CPVREpgInfoTag> epgTag =
- std::make_shared<CPVREpgInfoTag>(*tag, client->GetID(), nullptr, -1);
- CServiceBroker::GetPVRManager().EpgContainer().UpdateFromClient(epgTag, newState);
+ // Note: channel data and epg id may not yet be available. Tag will be fully initialized later.
+ const std::shared_ptr<CPVREpgInfoTag> epgTag =
+ std::make_shared<CPVREpgInfoTag>(*tag, client->GetID(), nullptr, -1);
+ CServiceBroker::GetPVRManager().EpgContainer().UpdateFromClient(epgTag, newState);
+ });
}
class CCodecIds
@@ -2006,7 +2032,14 @@ private:
PVR_CODEC CPVRClient::cb_get_codec_by_name(const void* kodiInstance, const char* strCodecName)
{
- return CCodecIds::GetInstance().GetCodecByName(strCodecName);
+ PVR_CODEC result = PVR_INVALID_CODEC;
+
+ HandleAddonCallback(
+ __func__, const_cast<void*>(kodiInstance),
+ [&](CPVRClient* client) { result = CCodecIds::GetInstance().GetCodecByName(strCodecName); },
+ true);
+
+ return result;
}
CPVRClientCapabilities::CPVRClientCapabilities(const CPVRClientCapabilities& other)
diff --git a/xbmc/pvr/addons/PVRClient.h b/xbmc/pvr/addons/PVRClient.h
index a724cffd43..d7a085212c 100644
--- a/xbmc/pvr/addons/PVRClient.h
+++ b/xbmc/pvr/addons/PVRClient.h
@@ -10,6 +10,7 @@
#include "addons/binary-addons/AddonInstanceHandler.h"
#include "addons/kodi-dev-kit/include/kodi/c-api/addon-instance/pvr.h"
+#include "threads/Event.h"
#include <atomic>
#include <functional>
@@ -1079,6 +1080,18 @@ private:
bool bCheckReadyToUse = true) const;
/*!
+ * @brief Wraps an addon callback function call in order to do common pre and post function invocation actions.
+ * @param strFunctionName The function name, for logging purposes.
+ * @param kodiInstance The addon instance pointer.
+ * @param function The function to wrap. It must take one parameter of type CPVRClient*.
+ * @param bForceCall If true, make the call, ignoring client's state.
+ */
+ static void HandleAddonCallback(const char* strFunctionName,
+ void* kodiInstance,
+ const std::function<void(CPVRClient* client)>& function,
+ bool bForceCall = false);
+
+ /*!
* @brief Callback functions from addon to kodi
*/
//@{
@@ -1240,6 +1253,8 @@ private:
std::atomic<bool>
m_bReadyToUse; /*!< true if this add-on is initialised (ADDON_Create returned true), false otherwise */
std::atomic<bool> m_bBlockAddonCalls; /*!< true if no add-on API calls are allowed */
+ mutable std::atomic<int> m_iAddonCalls; /*!< number of in-progress addon calls */
+ mutable CEvent m_allAddonCallsFinished; /*!< fires after last in-progress addon call finished */
PVR_CONNECTION_STATE m_connectionState; /*!< the backend connection state */
PVR_CONNECTION_STATE m_prevConnectionState; /*!< the previous backend connection state */
bool