[SCM] kodi-pvr-hts/master: [API 5.0.0] Added support for epg event state callback (async epg data transfer)
tiber-guest at users.alioth.debian.org
tiber-guest at users.alioth.debian.org
Fri Nov 4 23:23:38 UTC 2016
The following commit has been merged in the master branch:
commit 0f4bbed384f008ebb5ca3863035e37316ba62399
Author: Kai Sommerfeld <kai.sommerfeld at gmx.com>
Date: Thu Jan 14 14:28:27 2016 +0100
[API 5.0.0] Added support for epg event state callback (async epg data transfer)
diff --git a/src/HTSPTypes.h b/src/HTSPTypes.h
index 950f45c..c1e49bc 100644
--- a/src/HTSPTypes.h
+++ b/src/HTSPTypes.h
@@ -27,6 +27,7 @@
#include <map>
#include <string>
#include "client.h"
+#include "tvheadend/entity/Event.h"
typedef enum {
DVR_PRIO_IMPORTANT = 0,
@@ -91,17 +92,27 @@ enum eHTSPEventType
struct SHTSPEvent
{
eHTSPEventType m_type;
- uint32_t m_idx;
- SHTSPEvent (eHTSPEventType type = HTSP_EVENT_NONE, uint32_t idx = 0) :
+ // params for HTSP_EVENT_EPG_UPDATE
+ tvheadend::entity::Event m_epg;
+ EPG_EVENT_STATE m_state;
+
+ SHTSPEvent (eHTSPEventType type = HTSP_EVENT_NONE) :
m_type(type),
- m_idx (idx)
+ m_state(EPG_EVENT_CREATED)
{
}
-
+
+ SHTSPEvent (eHTSPEventType type, const tvheadend::entity::Event &epg, EPG_EVENT_STATE state) :
+ m_type(type),
+ m_epg(epg),
+ m_state(state)
+ {
+ }
+
bool operator==(const SHTSPEvent &right) const
{
- return m_type == right.m_type && m_idx == right.m_idx;
+ return m_type == right.m_type && m_epg == right.m_epg && m_state && right.m_state;
}
bool operator!=(const SHTSPEvent &right) const
diff --git a/src/Tvheadend.cpp b/src/Tvheadend.cpp
index 728c46a..c7b2646 100644
--- a/src/Tvheadend.cpp
+++ b/src/Tvheadend.cpp
@@ -1181,12 +1181,9 @@ PVR_ERROR CTvheadend::UpdateTimer ( const PVR_TIMER &timer )
* EPG
* *************************************************************************/
-/* Transfer schedule to XBMC */
-void CTvheadend::TransferEvent
- ( ADDON_HANDLE handle, const Event &event )
+void CTvheadend::CreateEvent
+ ( const Event &event, EPG_TAG &epg )
{
- /* Build */
- EPG_TAG epg;
memset(&epg, 0, sizeof(EPG_TAG));
epg.iUniqueBroadcastId = event.GetId();
epg.strTitle = event.GetTitle().c_str();
@@ -1214,43 +1211,40 @@ void CTvheadend::TransferEvent
epg.iEpisodePartNumber = event.GetPart();
epg.strEpisodeName = event.GetSubtitle().c_str();
epg.iFlags = EPG_TAG_FLAG_UNDEFINED;
+}
+
+void CTvheadend::TransferEvent
+ ( const Event &event, EPG_EVENT_STATE state )
+{
+ /* Build */
+ EPG_TAG tag;
+ CreateEvent(event, tag);
+
+ /* Transfer event to Kodi */
+ PVR->EpgEventStateChange(&tag, event.GetChannel(), state);
+}
+
+void CTvheadend::TransferEvent
+ ( ADDON_HANDLE handle, const Event &event )
+{
+ /* Build */
+ EPG_TAG tag;
+ CreateEvent(event, tag);
- /* Callback. */
- PVR->TransferEpgEntry(handle, &epg);
+ /* Transfer event to Kodi */
+ PVR->TransferEpgEntry(handle, &tag);
}
PVR_ERROR CTvheadend::GetEpg
( ADDON_HANDLE handle, const PVR_CHANNEL &chn, time_t start, time_t end )
{
htsmsg_field_t *f;
- int n = 0;
Logger::Log(LogLevel::LEVEL_TRACE, "get epg channel %d start %ld stop %ld", chn.iUniqueId,
(long long)start, (long long)end);
- /* Async transfer */
- if (Settings::GetInstance().GetAsyncEpg())
- {
- if (!m_asyncState.WaitForState(ASYNC_DONE))
- return PVR_ERROR_FAILED;
-
- // Find the relevant events
- Segment segment;
- {
- CLockObject lock(m_mutex);
- auto sit = m_schedules.find(chn.iUniqueId);
-
- if (sit != m_schedules.cend())
- segment = sit->second.GetSegment(start, end);
- }
-
- // Transfer
- for (const auto &event : segment)
- TransferEvent(handle, event);
-
- /* Synchronous transfer */
- }
- else
+ /* Note: Nothing to do if "async epg transfer" is enabled as all changes are pushed live to Kodi, then. */
+ if (!Settings::GetInstance().GetAsyncEpg())
{
/* Build message */
htsmsg_t *msg = htsmsg_create_map();
@@ -1267,13 +1261,16 @@ PVR_ERROR CTvheadend::GetEpg
/* Process */
htsmsg_t *l;
-
+
if (!(l = htsmsg_get_list(msg, "events")))
{
htsmsg_destroy(msg);
Logger::Log(LogLevel::LEVEL_ERROR, "malformed getEvents response: 'events' missing");
return PVR_ERROR_SERVER_ERROR;
}
+
+ int n = 0;
+
HTSMSG_FOREACH(f, l)
{
Event event;
@@ -1288,10 +1285,8 @@ PVR_ERROR CTvheadend::GetEpg
}
}
htsmsg_destroy(msg);
+ Logger::Log(LogLevel::LEVEL_TRACE, "get epg channel %d events %d", chn.iUniqueId, n);
}
-
- Logger::Log(LogLevel::LEVEL_TRACE, "get epg channel %d events %d", chn.iUniqueId, n);
-
return PVR_ERROR_NO_ERROR;
}
@@ -1490,7 +1485,7 @@ void* CTvheadend::Process ( void )
PVR->TriggerRecordingUpdate();
break;
case HTSP_EVENT_EPG_UPDATE:
- PVR->TriggerEpgUpdate(it->m_idx);
+ TransferEvent(it->m_epg, it->m_state);
break;
case HTSP_EVENT_NONE:
break;
@@ -1588,23 +1583,44 @@ void CTvheadend::SyncEpgCompleted ( void )
return;
/* Schedules */
- utilities::erase_if(m_schedules, [](const ScheduleMapEntry &entry)
+ std::vector<std::pair<uint32_t, uint32_t > > deletedEvents;
+ utilities::erase_if(m_schedules, [&](const ScheduleMapEntry &entry)
{
- return entry.second.IsDirty();
+ if (entry.second.IsDirty())
+ {
+ // all events are dirty too!
+ for (auto &evt : entry.second.GetEvents())
+ deletedEvents.push_back(
+ std::make_pair(evt.second.GetId() /* event uid */, entry.second.GetId() /* channel uid */));
+
+ return true;
+ }
+ return false;
});
/* Events */
for (auto &entry : m_schedules)
{
- utilities::erase_if(entry.second.GetEvents(), [](const EventMapEntry &entry)
+ utilities::erase_if(entry.second.GetEvents(), [&](const EventUidsMapEntry &mapEntry)
{
- return entry.second.IsDirty();
+ if (mapEntry.second.IsDirty())
+ {
+ deletedEvents.push_back(
+ std::make_pair(mapEntry.second.GetId() /* event uid */, entry.second.GetId() /* channel uid */));
+ return true;
+ }
+ return false;
});
}
-
- /* Trigger updates */
- for (const auto &entry : m_schedules)
- TriggerEpgUpdate(entry.second.GetId());
+
+ Event evt;
+ for (auto &entry : deletedEvents)
+ {
+ /* Transfer event to Kodi (callback) */
+ evt.SetId(entry.first);
+ evt.SetChannel(entry.second);
+ PushEpgEventUpdate(evt, EPG_EVENT_DELETED);
+ }
}
void CTvheadend::ParseTagAddOrUpdate ( htsmsg_t *msg, bool bAdd )
@@ -2083,41 +2099,56 @@ bool CTvheadend::ParseEvent ( htsmsg_t *msg, bool bAdd, Event &evt )
void CTvheadend::ParseEventAddOrUpdate ( htsmsg_t *msg, bool bAdd )
{
- Event tmp;
+ Event evt;
/* Parse */
- if (!ParseEvent(msg, bAdd, tmp))
+ if (!ParseEvent(msg, bAdd, evt))
return;
- /* Get event handle */
- Schedule &sched = m_schedules[tmp.GetChannel()];
- Events &events = sched.GetEvents();
- Event &evt = events[tmp.GetId()];
- Event comparison = evt;
- sched.SetId(tmp.GetChannel());
+ /* create/update schedule */
+ Schedule &sched = m_schedules[evt.GetChannel()];
+ sched.SetId(evt.GetChannel());
sched.SetDirty(false);
- evt.SetId(tmp.GetId());
- evt.SetDirty(false);
-
- /* Store */
- evt = tmp;
- /* Update */
- if (evt != comparison)
+ /* create/update event */
+ EventUids &events = sched.GetEvents();
+
+ bool bUpdated(false);
+ if (bAdd && m_asyncState.GetState() < ASYNC_DONE)
{
- Logger::Log(LogLevel::LEVEL_TRACE, "event id:%d channel:%d start:%d stop:%d title:%s desc:%s",
- evt.GetId(), evt.GetChannel(), (int)evt.GetStart(), (int)evt.GetStop(),
- evt.GetTitle().c_str(), evt.GetDesc().c_str());
+ // After a reconnect, during processing of "enableAsyncMetadata" htsp
+ // method, tvheadend sends all events as "added". Check whether we
+ // announced the event already and in case send it as "updated" to Kodi.
+ auto it = events.find(evt.GetId());
+ if (it != events.end())
+ {
+ bUpdated = true;
- if (m_asyncState.GetState() > ASYNC_EPG)
- TriggerEpgUpdate(tmp.GetChannel());
+ Entity &ent = it->second;
+ ent.SetId(evt.GetId());
+ ent.SetDirty(false);
+ }
+ }
+
+ if (!bUpdated)
+ {
+ Entity &ent = events[evt.GetId()];
+ ent.SetId(evt.GetId());
+ ent.SetDirty(false);
}
+
+ Logger::Log(LogLevel::LEVEL_TRACE, "event id:%d channel:%d start:%d stop:%d title:%s desc:%s",
+ evt.GetId(), evt.GetChannel(), (int)evt.GetStart(), (int)evt.GetStop(),
+ evt.GetTitle().c_str(), evt.GetDesc().c_str());
+
+ /* Transfer event to Kodi (callback) */
+ PushEpgEventUpdate(evt, (!bAdd || bUpdated) ? EPG_EVENT_UPDATED : EPG_EVENT_CREATED);
}
void CTvheadend::ParseEventDelete ( htsmsg_t *msg )
{
uint32_t u32;
-
+
/* Validate */
if (htsmsg_get_u32(msg, "eventId", &u32))
{
@@ -2125,12 +2156,12 @@ void CTvheadend::ParseEventDelete ( htsmsg_t *msg )
return;
}
Logger::Log(LogLevel::LEVEL_TRACE, "delete event %u", u32);
-
+
/* Erase */
for (auto &entry : m_schedules)
{
- Schedule &schedule = entry.second;
- Events &events = schedule.GetEvents();
+ Schedule &schedule = entry.second;
+ EventUids &events = schedule.GetEvents();
// Find the event so we can get the channel number
auto eit = events.find(u32);
@@ -2139,7 +2170,12 @@ void CTvheadend::ParseEventDelete ( htsmsg_t *msg )
{
Logger::Log(LogLevel::LEVEL_TRACE, "deleted event %d from channel %d", u32, schedule.GetId());
events.erase(eit);
- TriggerEpgUpdate(schedule.GetId());
+
+ /* Transfer event to Kodi (callback) */
+ Event evt;
+ evt.SetId(u32);
+ evt.SetChannel(schedule.GetId());
+ PushEpgEventUpdate(evt, EPG_EVENT_DELETED);
return;
}
}
diff --git a/src/Tvheadend.h b/src/Tvheadend.h
index 724bcd7..3c5dc5d 100644
--- a/src/Tvheadend.h
+++ b/src/Tvheadend.h
@@ -455,10 +455,10 @@ private:
{
m_events.push_back(SHTSPEvent(HTSP_EVENT_REC_UPDATE));
}
- inline void TriggerEpgUpdate ( uint32_t idx )
+ inline void PushEpgEventUpdate ( const tvheadend::entity::Event &epg, EPG_EVENT_STATE state )
{
- SHTSPEvent event = SHTSPEvent(HTSP_EVENT_EPG_UPDATE, idx);
-
+ SHTSPEvent event = SHTSPEvent(HTSP_EVENT_EPG_UPDATE, epg, state);
+
if (std::find(m_events.begin(), m_events.end(), event) == m_events.end())
m_events.push_back(event);
}
@@ -466,6 +466,8 @@ private:
/*
* Epg Handling
*/
+ void CreateEvent ( const tvheadend::entity::Event &event, EPG_TAG &epg );
+ void TransferEvent ( const tvheadend::entity::Event &event, EPG_EVENT_STATE state );
void TransferEvent ( ADDON_HANDLE handle, const tvheadend::entity::Event &event );
/*
diff --git a/src/tvheadend/entity/Schedule.cpp b/src/tvheadend/entity/Schedule.cpp
index 17c7293..410068b 100644
--- a/src/tvheadend/entity/Schedule.cpp
+++ b/src/tvheadend/entity/Schedule.cpp
@@ -35,22 +35,12 @@ void Schedule::SetDirty(bool dirty)
}
}
-Segment Schedule::GetSegment(time_t startTime, time_t endTime) const
+EventUids& Schedule::GetEvents()
{
- Segment segment;
-
- for (const auto &entry : m_events)
- {
- const Event &event = entry.second;
-
- if (event.GetStart() < endTime && event.GetStop() > startTime)
- segment.push_back(event);
- }
-
- return segment;
+ return m_events;
}
-Events& Schedule::GetEvents()
+const EventUids& Schedule::GetEvents() const
{
return m_events;
}
diff --git a/src/tvheadend/entity/Schedule.h b/src/tvheadend/entity/Schedule.h
index 533d3a6..b0023b8 100644
--- a/src/tvheadend/entity/Schedule.h
+++ b/src/tvheadend/entity/Schedule.h
@@ -21,9 +21,9 @@
*
*/
+#include <map>
#include <vector>
#include "Entity.h"
-#include "Event.h"
namespace tvheadend
{
@@ -32,7 +32,9 @@ namespace tvheadend
class Schedule;
typedef std::pair<int, Schedule> ScheduleMapEntry;
typedef std::map<int, Schedule> Schedules;
- typedef std::vector<Event> Segment;
+
+ typedef std::pair<uint32_t, Entity> EventUidsMapEntry;
+ typedef std::map<uint32_t, Entity> EventUids;
/**
* Represents a schedule. A schedule has a channel and a bunch of events.
@@ -44,18 +46,17 @@ namespace tvheadend
virtual void SetDirty(bool dirty);
/**
- * @return a segment containing the events that occur within the
- * specified times
+ * @return read-write reference to the events in this schedule
*/
- Segment GetSegment(time_t startTime, time_t endTime) const;
+ EventUids& GetEvents();
/**
- * @return read-write reference to the events in this schedule
+ * @return read-only reference to the events in this schedule
*/
- Events& GetEvents();
+ const EventUids& GetEvents() const;
private:
- Events m_events;
+ EventUids m_events; // event uids
};
}
-}
\ No newline at end of file
+}
--
kodi-pvr-hts packaging
More information about the pkg-multimedia-commits
mailing list