diff options
author | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2016-01-14 23:26:25 +0100 |
---|---|---|
committer | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2016-02-15 14:56:52 +0100 |
commit | 76180aee32a039f9550c4f063b4e139ec72f57d0 (patch) | |
tree | 5249f0fe77cfaf3bd3dfe44f4467a25669b10b8b | |
parent | b4c092b807c4c2b6ef22c7aa612bed5a65ac667e (diff) |
[PVR] Addon API: add epg event changes callback (async epg data transfer)
-rw-r--r-- | addons/library.xbmc.pvr/libXBMC_pvr.h | 17 | ||||
-rw-r--r-- | lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp | 8 | ||||
-rw-r--r-- | xbmc/addons/AddonCallbacks.h | 2 | ||||
-rw-r--r-- | xbmc/addons/AddonCallbacksPVR.cpp | 84 | ||||
-rw-r--r-- | xbmc/addons/AddonCallbacksPVR.h | 13 | ||||
-rw-r--r-- | xbmc/addons/include/xbmc_epg_types.h | 34 | ||||
-rw-r--r-- | xbmc/addons/include/xbmc_pvr_dll.h | 1 | ||||
-rw-r--r-- | xbmc/addons/include/xbmc_pvr_types.h | 1 | ||||
-rw-r--r-- | xbmc/epg/Epg.cpp | 104 | ||||
-rw-r--r-- | xbmc/epg/Epg.h | 22 | ||||
-rw-r--r-- | xbmc/epg/EpgInfoTag.h | 12 |
11 files changed, 255 insertions, 43 deletions
diff --git a/addons/library.xbmc.pvr/libXBMC_pvr.h b/addons/library.xbmc.pvr/libXBMC_pvr.h index 8ca1e3e2e1..3e3d479654 100644 --- a/addons/library.xbmc.pvr/libXBMC_pvr.h +++ b/addons/library.xbmc.pvr/libXBMC_pvr.h @@ -158,6 +158,10 @@ public: dlsym(m_libXBMC_pvr, "PVR_connection_state_change"); if (PVR_connection_state_change == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + PVR_epg_event_state_change = (void (*)(void* HANDLE, void* CB, EPG_TAG* tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState)) + dlsym(m_libXBMC_pvr, "PVR_epg_event_state_change"); + if (PVR_epg_event_state_change == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; } + m_Callbacks = PVR_register_me(m_Handle); return m_Callbacks != NULL; } @@ -316,6 +320,18 @@ public: return PVR_connection_state_change(m_Handle, m_Callbacks, strConnectionString, newState, strMessage); } + /*! + * @brief Notify a state change for an EPG event + * @param tag The EPG event. + * @param iUniqueChannelId The unique id of the channel for the EPG event + * @param newState The new state. For EPG_EVENT_CREATED and EPG_EVENT_UPDATED, tag must be filled with all available + * event data, not just a delta. For EPG_EVENT_DELETED, it is sufficient to fill EPG_TAG.iUniqueBroadcastId + */ + void EpgEventStateChange(EPG_TAG *tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState) + { + return PVR_epg_event_state_change(m_Handle, m_Callbacks, tag, iUniqueChannelId, newState); + } + protected: void* (*PVR_register_me)(void*); void (*PVR_unregister_me)(void*, void*); @@ -337,6 +353,7 @@ protected: DemuxPacket* (*PVR_allocate_demux_packet)(void*, void*, int); #endif void (*PVR_connection_state_change)(void*, void*, const char*, PVR_CONNECTION_STATE, const char*); + void (*PVR_epg_event_state_change)(void*, void*, EPG_TAG*, unsigned int, EPG_EVENT_STATE); private: void* m_libXBMC_pvr; diff --git a/lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp b/lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp index 8545cb7ad8..2858693e30 100644 --- a/lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp +++ b/lib/addons/library.xbmc.pvr/libXBMC_pvr.cpp @@ -172,6 +172,14 @@ DLLEXPORT void PVR_connection_state_change(void *hdl, void* cb, const char *strC ((CB_PVRLib*)cb)->ConnectionStateChange(((AddonCB*)hdl)->addonData, strConnectionString, newState, strMessage); } +DLLEXPORT void PVR_epg_event_state_change(void *hdl, void* cb, EPG_TAG *tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState) +{ + if (cb == NULL) + return; + + ((CB_PVRLib*)cb)->EpgEventStateChange(((AddonCB*)hdl)->addonData, tag, iUniqueChannelId, newState); +} + DLLEXPORT void PVR_transfer_channel_group(void *hdl, void* cb, const ADDON_HANDLE handle, const PVR_CHANNEL_GROUP *group) { if (cb == NULL) diff --git a/xbmc/addons/AddonCallbacks.h b/xbmc/addons/AddonCallbacks.h index 74539e63b4..81e8fa9b65 100644 --- a/xbmc/addons/AddonCallbacks.h +++ b/xbmc/addons/AddonCallbacks.h @@ -488,6 +488,7 @@ typedef void (*PVRFreeDemuxPacket)(void *addonData, DemuxPacket* pPacket); typedef DemuxPacket* (*PVRAllocateDemuxPacket)(void *addonData, int iDataSize); typedef void (*PVRConnectionStateChange)(void* addonData, const char* strConnectionString, PVR_CONNECTION_STATE newState, const char *strMessage); +typedef void (*PVREpgEventStateChange)(void* addonData, EPG_TAG* tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState); typedef struct CB_PVRLib { @@ -507,6 +508,7 @@ typedef struct CB_PVRLib PVRTransferChannelGroup TransferChannelGroup; PVRTransferChannelGroupMember TransferChannelGroupMember; PVRConnectionStateChange ConnectionStateChange; + PVREpgEventStateChange EpgEventStateChange; } CB_PVRLib; diff --git a/xbmc/addons/AddonCallbacksPVR.cpp b/xbmc/addons/AddonCallbacksPVR.cpp index d4ee9cad24..63fb8c6f1b 100644 --- a/xbmc/addons/AddonCallbacksPVR.cpp +++ b/xbmc/addons/AddonCallbacksPVR.cpp @@ -22,6 +22,7 @@ #include "AddonCallbacksPVR.h" #include "events/EventLog.h" #include "events/NotificationEvent.h" +#include "threads/SingleLock.h" #include "utils/log.h" #include "utils/StringUtils.h" #include "dialogs/GUIDialogKaiToast.h" @@ -64,6 +65,7 @@ CAddonCallbacksPVR::CAddonCallbacksPVR(CAddon* addon) m_callbacks->TransferChannelGroup = PVRTransferChannelGroup; m_callbacks->TransferChannelGroupMember = PVRTransferChannelGroupMember; m_callbacks->ConnectionStateChange = PVRConnectionStateChange; + m_callbacks->EpgEventStateChange = PVREpgEventStateChange; } CAddonCallbacksPVR::~CAddonCallbacksPVR() @@ -329,7 +331,6 @@ void CAddonCallbacksPVR::PVRConnectionStateChange(void* addonData, const char* s if (prevState == newState) return; - CLog::Log(LOGDEBUG, "PVR - %s - state for connection '%s' on client '%s' changed from '%d' to '%d'", __FUNCTION__, strConnectionString, client->Name().c_str(), prevState, newState); client->SetConnectionState(newState); @@ -383,4 +384,85 @@ void CAddonCallbacksPVR::PVRConnectionStateChange(void* addonData, const char* s client->Name(), strMsg, client->Icon(), bError ? EventLevel::Error : EventLevel::Information))); } +typedef struct EpgEventStateChange +{ + int iClientId; + unsigned int iUniqueChannelId; + CEpgInfoTagPtr event; + EPG_EVENT_STATE state; + + EpgEventStateChange(int _iClientId, unsigned int _iUniqueChannelId, EPG_TAG *_event, EPG_EVENT_STATE _state) + : iClientId(_iClientId), + iUniqueChannelId(_iUniqueChannelId), + event(new CEpgInfoTag(*_event)), + state(_state) {} + +} EpgEventStateChange; + +void CAddonCallbacksPVR::UpdateEpgEvent(const EpgEventStateChange &ch, bool bQueued) +{ + const CPVRChannelPtr channel(g_PVRChannelGroups->GetByUniqueID(ch.iUniqueChannelId, ch.iClientId)); + if (channel) + { + const CEpgPtr epg(channel->GetEPG()); + if (epg) + { + if (!epg->UpdateEntry(ch.event, ch.state)) + CLog::Log(LOGERROR, "PVR - %s - epg update failed for %sevent change (%d)", + __FUNCTION__, bQueued ? "queued " : "", ch.event->UniqueBroadcastID()); + } + else + { + CLog::Log(LOGERROR, "PVR - %s - channel '%s' does not have an EPG! Unable to deliver %sevent change (%d)!", + __FUNCTION__, channel->ChannelName().c_str(), bQueued ? "queued " : "", ch.event->UniqueBroadcastID()); + } + } + else + CLog::Log(LOGERROR, "PVR - %s - invalid channel (%d)! Unable to deliver %sevent change (%d)!", + __FUNCTION__, ch.iUniqueChannelId, bQueued ? "queued " : "", ch.event->UniqueBroadcastID()); +} + +void CAddonCallbacksPVR::PVREpgEventStateChange(void* addonData, EPG_TAG* tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState) +{ + CPVRClient *client = GetPVRClient(addonData); + if (!client || !tag) + { + CLog::Log(LOGERROR, "PVR - %s - invalid handler data", __FUNCTION__); + return; + } + + CLog::Log(LOGDEBUG, "PVR - %s - state for epg event '%d' on channel '%d' on client '%s' changed to '%d'.", + __FUNCTION__, tag->iUniqueBroadcastId, iUniqueChannelId, client->Name().c_str(), newState); + + static CCriticalSection queueMutex; + static std::vector<EpgEventStateChange> queuedChanges; + + // during Kodi startup, addons may push updates very early, even before EPGs are ready to use. + if (g_PVRManager.EpgsCreated()) + { + { + // deliver queued changes, if any. discard event if delivery fails. + CSingleLock lock(queueMutex); + if (!queuedChanges.empty()) + CLog::Log(LOGNOTICE, "PVR - %s - processing %ld queued epg event changes.", __FUNCTION__, queuedChanges.size()); + + while (!queuedChanges.empty()) + { + auto it = queuedChanges.begin(); + UpdateEpgEvent(*it, true); + queuedChanges.erase(it); + } + } + + // deliver current change. + UpdateEpgEvent(EpgEventStateChange(client->GetID(), iUniqueChannelId, tag, newState), false); + } + else + { + // queue for later delivery. + CSingleLock lock(queueMutex); + queuedChanges.push_back(EpgEventStateChange(client->GetID(), iUniqueChannelId, tag, newState)); + } +} + }; /* namespace ADDON */ diff --git a/xbmc/addons/AddonCallbacksPVR.h b/xbmc/addons/AddonCallbacksPVR.h index 20907ac0e5..945c789f1a 100644 --- a/xbmc/addons/AddonCallbacksPVR.h +++ b/xbmc/addons/AddonCallbacksPVR.h @@ -29,6 +29,7 @@ namespace PVR namespace ADDON { +struct EpgEventStateChange; /*! * Callbacks for a PVR add-on to XBMC. @@ -166,8 +167,20 @@ public: */ static void PVRConnectionStateChange(void* addonData, const char* strConnectionString, PVR_CONNECTION_STATE newState, const char *strMessage); + /*! + * @brief Notify a state change for an EPG event + * @param addonData A pointer to the add-on. + * @param tag The EPG event. + * @param iUniqueChannelId The unique id of the channel for the EPG event + * @param newState The new state. + * @param newState The new state. For EPG_EVENT_CREATED and EPG_EVENT_UPDATED, tag must be filled with all available + * event data, not just a delta. For EPG_EVENT_DELETED, it is sufficient to fill EPG_TAG.iUniqueBroadcastId + */ + static void PVREpgEventStateChange(void* addonData, EPG_TAG* tag, unsigned int iUniqueChannelId, EPG_EVENT_STATE newState); + private: static PVR::CPVRClient* GetPVRClient(void* addonData); + static void UpdateEpgEvent(const EpgEventStateChange &ch, bool bQueued); CB_PVRLib *m_callbacks; /*!< callback addresses */ CAddon *m_addon; /*!< the addon */ diff --git a/xbmc/addons/include/xbmc_epg_types.h b/xbmc/addons/include/xbmc_epg_types.h index 5956f98895..9460952c16 100644 --- a/xbmc/addons/include/xbmc_epg_types.h +++ b/xbmc/addons/include/xbmc_epg_types.h @@ -59,23 +59,33 @@ //@} /* Set EPGTAG.iGenreType to EPG_GENRE_USE_STRING to transfer genre strings to XBMC */ -#define EPG_GENRE_USE_STRING 0x100 - -/* EPG_TAG.iFlags values */ -const unsigned int EPG_TAG_FLAG_UNDEFINED = 0x00000000; /*!< @brief nothing special to say about this entry */ -const unsigned int EPG_TAG_FLAG_IS_SERIES = 0x00000001; /*!< @brief this EPG entry is part of a series */ - -/* Special EPG_TAG.iUniqueBroadcastId value */ - -/*! - * @brief special EPG_TAG.iUniqueBroadcastId value to indicate that a tag has not a valid EPG event uid. - */ -const unsigned int EPG_TAG_INVALID_UID = 0; +#define EPG_GENRE_USE_STRING 0x100 #ifdef __cplusplus extern "C" { #endif + /* EPG_TAG.iFlags values */ + const unsigned int EPG_TAG_FLAG_UNDEFINED = 0x00000000; /*!< @brief nothing special to say about this entry */ + const unsigned int EPG_TAG_FLAG_IS_SERIES = 0x00000001; /*!< @brief this EPG entry is part of a series */ + + /* Special EPG_TAG.iUniqueBroadcastId value */ + + /*! + * @brief special EPG_TAG.iUniqueBroadcastId value to indicate that a tag has not a valid EPG event uid. + */ + const unsigned int EPG_TAG_INVALID_UID = 0; + + /*! + * @brief EPG event states. Used with EpgEventStateChange callback. + */ + typedef enum + { + EPG_EVENT_CREATED = 0, /*!< @brief event created */ + EPG_EVENT_UPDATED = 1, /*!< @brief event updated */ + EPG_EVENT_DELETED = 2, /*!< @brief event deleted */ + } EPG_EVENT_STATE; + /*! * @brief Representation of an EPG event. */ diff --git a/xbmc/addons/include/xbmc_pvr_dll.h b/xbmc/addons/include/xbmc_pvr_dll.h index aa47bf672d..3b80134928 100644 --- a/xbmc/addons/include/xbmc_pvr_dll.h +++ b/xbmc/addons/include/xbmc_pvr_dll.h @@ -725,3 +725,4 @@ extern "C" pClient->IsRealTimeStream = IsRealTimeStream; }; }; + diff --git a/xbmc/addons/include/xbmc_pvr_types.h b/xbmc/addons/include/xbmc_pvr_types.h index 0cfa410431..ef17daaef3 100644 --- a/xbmc/addons/include/xbmc_pvr_types.h +++ b/xbmc/addons/include/xbmc_pvr_types.h @@ -585,3 +585,4 @@ extern "C" { #ifdef __cplusplus } #endif + diff --git a/xbmc/epg/Epg.cpp b/xbmc/epg/Epg.cpp index c3f1c80644..62af654520 100644 --- a/xbmc/epg/Epg.cpp +++ b/xbmc/epg/Epg.cpp @@ -309,31 +309,100 @@ void CEpg::AddEntry(const CEpgInfoTag &tag) } } -bool CEpg::UpdateEntry(const CEpgInfoTag &tag, bool bUpdateDatabase /* = false */, bool bSort /* = true */) +bool CEpg::UpdateEntry(const EPG_TAG *data, bool bUpdateDatabase /* = false */) +{ + if (!data) + return false; + + CEpgInfoTagPtr tag(new CEpgInfoTag(*data)); + return UpdateEntry(tag, bUpdateDatabase); +} + +bool CEpg::UpdateEntry(const CEpgInfoTagPtr &tag, bool bUpdateDatabase /* = false */) +{ + CSingleLock lock(m_critSection); + auto it = m_tags.find(tag->StartAsUTC()); + EPG_EVENT_STATE state = (it == m_tags.end()) ? EPG_EVENT_CREATED : EPG_EVENT_UPDATED; + return UpdateEntry(tag, state, it, bUpdateDatabase); +} + +bool CEpg::UpdateEntry(const CEpgInfoTagPtr &tag, EPG_EVENT_STATE newState, bool bUpdateDatabase /* = false */) { - CEpgInfoTagPtr infoTag; CSingleLock lock(m_critSection); - std::map<CDateTime, CEpgInfoTagPtr>::iterator it = m_tags.find(tag.StartAsUTC()); + auto it = m_tags.end(); + return UpdateEntry(tag, newState, it, bUpdateDatabase); +} + +bool CEpg::UpdateEntry(const CEpgInfoTagPtr &tag, EPG_EVENT_STATE newState, std::map<CDateTime, CEpgInfoTagPtr>::iterator &eit, bool bUpdateDatabase /* = false */) +{ + CEpgInfoTagPtr infoTag; bool bNewTag(false); - if (it != m_tags.end()) + + CSingleLock lock(m_critSection); + + if (newState == EPG_EVENT_CREATED || newState == EPG_EVENT_UPDATED) + { + // Reuse passed iterator in favor of doing expensive find self + auto it = (eit == m_tags.end()) ? m_tags.find(tag->StartAsUTC()) : eit; + if (it != m_tags.end()) + { + if (newState == EPG_EVENT_CREATED) + CLog::Log(LOGERROR, "EPG - %s - Error: EPG_EVENT_CREATED: uid %d found! Updating existing event.", __FUNCTION__, tag->UniqueBroadcastID()); + + infoTag = it->second; + } + else + { + if (newState == EPG_EVENT_UPDATED) + CLog::Log(LOGERROR, "EPG - %s - Error: EPG_EVENT_UPDATED: uid %d not found. Inserting new event.", __FUNCTION__, tag->UniqueBroadcastID()); + + infoTag.reset(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : "")); + infoTag->SetUniqueBroadcastID(tag->UniqueBroadcastID()); + m_tags.insert(std::make_pair(tag->StartAsUTC(), infoTag)); + bNewTag = true; + } + } + else if (newState == EPG_EVENT_DELETED) { - infoTag = it->second; + // Reuse passed iterator in favor of doing expensive find self + auto it = (eit == m_tags.end()) ? m_tags.find(tag->StartAsUTC()) : eit; + if (it == m_tags.end()) + { + // not guranteed that deleted tag contains valid start time. search sequential. + for (it = m_tags.begin(); it != m_tags.end(); ++it) + { + if (it->second->UniqueBroadcastID() == tag->UniqueBroadcastID()) + break; + } + } + + if (it != m_tags.end()) + { + it->second->ClearTimer(); + m_tags.erase(it); + + if (bUpdateDatabase) + m_deletedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag)); + } + else + { + CLog::Log(LOGERROR, "EPG - %s - Error: EPG_EVENT_DELETED: uid %d not found.", __FUNCTION__, tag->UniqueBroadcastID()); + return false; + } + return true; } else { - /* create a new tag if no tag with this ID exists */ - infoTag.reset(new CEpgInfoTag(this, m_pvrChannel, m_strName, m_pvrChannel ? m_pvrChannel->IconPath() : "")); - infoTag->SetUniqueBroadcastID(tag.UniqueBroadcastID()); - m_tags.insert(make_pair(tag.StartAsUTC(), infoTag)); - bNewTag = true; + CLog::Log(LOGERROR, "EPG - %s - unknownn epg event state '%d'.", __FUNCTION__, newState); + return false; } - infoTag->Update(tag, bNewTag); + infoTag->Update(*tag, bNewTag); infoTag->SetEpg(this); infoTag->SetPVRChannel(m_pvrChannel); if (bUpdateDatabase) - m_changedTags.insert(make_pair(infoTag->UniqueBroadcastID(), infoTag)); + m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag)); return true; } @@ -377,7 +446,7 @@ bool CEpg::UpdateEntries(const CEpg &epg, bool bStoreInDb /* = true */) #endif /* copy over tags */ for (std::map<CDateTime, CEpgInfoTagPtr>::const_iterator it = epg.m_tags.begin(); it != epg.m_tags.end(); ++it) - UpdateEntry(*it->second, bStoreInDb, false); + UpdateEntry(it->second, bStoreInDb); #if EPG_DEBUGGING CLog::Log(LOGDEBUG, "EPG - %s - %" PRIuS" entries in memory after merging and before fixing", __FUNCTION__, m_tags.size()); @@ -720,15 +789,6 @@ const std::string &CEpg::ConvertGenreIdToString(int iID, int iSubID) return g_localizeStrings.Get(iLabelId); } -bool CEpg::UpdateEntry(const EPG_TAG *data, bool bUpdateDatabase /* = false */) -{ - if (!data) - return false; - - CEpgInfoTagPtr tag(new CEpgInfoTag(*data)); - return UpdateEntry(*tag, bUpdateDatabase); -} - bool CEpg::IsRadio(void) const { CSingleLock lock(m_critSection); diff --git a/xbmc/epg/Epg.h b/xbmc/epg/Epg.h index 51bf728fa5..44aea47e5a 100644 --- a/xbmc/epg/Epg.h +++ b/xbmc/epg/Epg.h @@ -209,10 +209,18 @@ namespace EPG * @brief Update an entry in this EPG. * @param tag The tag to update. * @param bUpdateDatabase If set to true, this event will be persisted in the database. - * @param bSort If set to false, epg entries will not be sorted after updating; used for mass updates * @return True if it was updated successfully, false otherwise. */ - bool UpdateEntry(const CEpgInfoTag &tag, bool bUpdateDatabase = false, bool bSort = true); + bool UpdateEntry(const CEpgInfoTagPtr &tag, bool bUpdateDatabase = false); + + /*! + * @brief Update an entry in this EPG. + * @param tag The tag to update. + * @param newState the new state of the event. + * @param bUpdateDatabase If set to true, this event will be persisted in the database. + * @return True if it was updated successfully, false otherwise. + */ + bool UpdateEntry(const CEpgInfoTagPtr &tag, EPG_EVENT_STATE newState, bool bUpdateDatabase = false); /*! * @brief Update the EPG from 'start' till 'end'. @@ -310,6 +318,16 @@ namespace EPG CEpg(void); /*! + * @brief Update an entry in this EPG. + * @param data The tag to update. + * @param newState The new state of the event. + * @param it An iterator pointing to m_tags entry for the EPG event to update or m_tags.end(). + * @param bUpdateDatabase If set to true, this event will be persisted in the database. + * @return True if it was updated successfully, false otherwise. + */ + bool UpdateEntry(const CEpgInfoTagPtr &tag, EPG_EVENT_STATE newState, std::map<CDateTime, CEpgInfoTagPtr>::iterator &eit, bool bUpdateDatabase = false); + + /*! * @brief Update the EPG from a scraper set in the channel tag. * TODO: not implemented yet for non-pvr EPGs * @param start Get entries with a start date after this time. diff --git a/xbmc/epg/EpgInfoTag.h b/xbmc/epg/EpgInfoTag.h index 03dddd8e82..f5d17fb93c 100644 --- a/xbmc/epg/EpgInfoTag.h +++ b/xbmc/epg/EpgInfoTag.h @@ -50,6 +50,12 @@ namespace EPG */ static CEpgInfoTagPtr CreateDefaultTag(); + /*! + * @brief Create a new EPG infotag with 'data' as content. + * @param data The tag's content. + */ + CEpgInfoTag(const EPG_TAG &data); + private: /*! * @brief Create a new empty event. @@ -61,12 +67,6 @@ namespace EPG */ CEpgInfoTag(CEpg *epg, PVR::CPVRChannelPtr pvrChannel, const std::string &strTableName = "", const std::string &strIconPath = ""); - /*! - * @brief Create a new EPG infotag with 'data' as content. - * @param data The tag's content. - */ - CEpgInfoTag(const EPG_TAG &data); - // Prevent copy construction, even for CEpgInfoTag instances and friends. // Note: Only declared, but intentionally not implemented // to prevent compiler generated copy ctor and to force |