From 8ec72d956f34395f7e8e955d4c41ff1a70c5e4fb Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Tue, 18 Sep 2012 13:11:56 +0100 Subject: [PATCH] Enable asynchronous EPG output include honouring lastUpdate option. --- debian/changelog | 9 ++-- src/epg.c | 37 +++++++++---- src/epg.h | 20 +++---- src/htsp.c | 138 ++++++++++++++++++++++++++++++++++------------- src/htsp.h | 4 ++ 5 files changed, 146 insertions(+), 62 deletions(-) diff --git a/debian/changelog b/debian/changelog index 9198d58e..b1034b95 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,6 @@ -tvheadend (3.1.1) unstable; urgency=low +tvheadend (3.1.694) unstable; urgency=low - * The full changelog can be found at - https://github.com/tvheadend/tvheadend/commits/master - - -- Tvheadend Wed, 29 Aug 2012 00:00:00 +0000 + * The full changelog can be found at + http://www.lonelycoder.com/tvheadend/download + -- Andreas Ă–man Tue, 18 Sep 2012 12:45:49 +0100 diff --git a/src/epg.c b/src/epg.c index ddebb2fc..2f2ed758 100644 --- a/src/epg.c +++ b/src/epg.c @@ -110,9 +110,10 @@ void epg_updated ( void ) /* Update updated */ while ((eo = LIST_FIRST(&epg_object_updated))) { - eo->updated(eo); + eo->update(eo); LIST_REMOVE(eo, up_link); eo->_updated = 0; + eo->created = dispatch_clock; } } @@ -166,6 +167,7 @@ static void _epg_object_set_updated ( void *o ) eo, eo->id, eo->type, eo->uri); #endif eo->_updated = 1; + eo->updated = dispatch_clock; LIST_INSERT_HEAD(&epg_object_updated, eo, up_link); } } @@ -241,11 +243,13 @@ static htsmsg_t * _epg_object_serialize ( void *o ) htsmsg_add_str(m, "uri", eo->uri); if (eo->grabber) htsmsg_add_str(m, "grabber", eo->grabber->id); + htsmsg_add_s64(m, "updated", eo->updated); return m; } static epg_object_t *_epg_object_deserialize ( htsmsg_t *m, epg_object_t *eo ) { + int64_t s64; uint32_t u32; const char *s; if (htsmsg_get_u32(m, "id", &eo->id)) return NULL; @@ -254,6 +258,10 @@ static epg_object_t *_epg_object_deserialize ( htsmsg_t *m, epg_object_t *eo ) eo->uri = (char*)htsmsg_get_str(m, "uri"); if ((s = htsmsg_get_str(m, "grabber"))) eo->grabber = epggrab_module_find_by_id(s); + if (!htsmsg_get_s64(m, "updated", &s64)) { + _epg_object_set_updated(eo); + eo->updated = s64; + } #ifdef EPG_TRACE tvhlog(LOG_DEBUG, "epg", "eo [%p, %u, %d, %s] deserialize", eo, eo->id, eo->type, eo->uri); @@ -413,7 +421,7 @@ static epg_object_t **_epg_brand_skel ( void ) skel = calloc(1, sizeof(epg_brand_t)); skel->type = EPG_BRAND; skel->destroy = _epg_brand_destroy; - skel->updated = _epg_brand_updated; + skel->update = _epg_brand_updated; } return &skel; } @@ -590,7 +598,7 @@ static epg_object_t **_epg_season_skel ( void ) skel = calloc(1, sizeof(epg_season_t)); skel->type = EPG_SEASON; skel->destroy = _epg_season_destroy; - skel->updated = _epg_season_updated; + skel->update = _epg_season_updated; } return &skel; } @@ -812,7 +820,7 @@ static epg_object_t **_epg_episode_skel ( void ) skel = calloc(1, sizeof(epg_episode_t)); skel->type = EPG_EPISODE; skel->destroy = _epg_episode_destroy; - skel->updated = _epg_episode_updated; + skel->update = _epg_episode_updated; } return &skel; } @@ -1281,7 +1289,7 @@ static epg_object_t **_epg_serieslink_skel ( void ) skel = calloc(1, sizeof(epg_serieslink_t)); skel->type = EPG_SERIESLINK; skel->destroy = _epg_serieslink_destroy; - skel->updated = _epg_serieslink_updated; + skel->update = _epg_serieslink_updated; } return &skel; } @@ -1493,6 +1501,7 @@ void epg_channel_unlink ( channel_t *ch ) static void _epg_broadcast_destroy ( void *eo ) { epg_broadcast_t *ebc = eo; + if (ebc->created) htsp_event_delete(ebc); if (ebc->episode) _epg_episode_rem_broadcast(ebc->episode, ebc); if (ebc->serieslink) _epg_serieslink_rem_broadcast(ebc->serieslink, ebc); if (ebc->summary) lang_str_destroy(ebc->summary); @@ -1503,6 +1512,11 @@ static void _epg_broadcast_destroy ( void *eo ) static void _epg_broadcast_updated ( void *eo ) { + epg_broadcast_t *ebc = eo; + if (ebc->created) + htsp_event_update(eo); + else + htsp_event_add(eo); dvr_event_updated(eo); dvr_autorec_check_event(eo); } @@ -1514,7 +1528,7 @@ static epg_broadcast_t **_epg_broadcast_skel ( void ) skel = calloc(1, sizeof(epg_broadcast_t)); skel->type = EPG_BROADCAST; skel->destroy = _epg_broadcast_destroy; - skel->updated = _epg_broadcast_updated; + skel->update = _epg_broadcast_updated; } return &skel; } @@ -1723,8 +1737,8 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast ) if (!broadcast) return NULL; if (!broadcast->episode || !broadcast->episode->uri) return NULL; if (!(m = _epg_object_serialize((epg_object_t*)broadcast))) return NULL; - htsmsg_add_u32(m, "start", broadcast->start); - htsmsg_add_u32(m, "stop", broadcast->stop); + htsmsg_add_s64(m, "start", broadcast->start); + htsmsg_add_s64(m, "stop", broadcast->stop); htsmsg_add_str(m, "episode", broadcast->episode->uri); if (broadcast->channel) htsmsg_add_u32(m, "channel", broadcast->channel->ch_id); @@ -1767,10 +1781,11 @@ epg_broadcast_t *epg_broadcast_deserialize epg_serieslink_t *esl; lang_str_t *ls; const char *str; - uint32_t chid, eid, start, stop, u32; + uint32_t chid, eid, u32; + int64_t start, stop; - if ( htsmsg_get_u32(m, "start", &start) ) return NULL; - if ( htsmsg_get_u32(m, "stop", &stop) ) return NULL; + if ( htsmsg_get_s64(m, "start", &start) ) return NULL; + if ( htsmsg_get_s64(m, "stop", &stop) ) return NULL; if ( !start || !stop ) return NULL; if ( stop <= start ) return NULL; if ( stop <= dispatch_clock ) return NULL; diff --git a/src/epg.h b/src/epg.h index bc155ea1..bff1a5c2 100644 --- a/src/epg.h +++ b/src/epg.h @@ -102,25 +102,27 @@ typedef enum epg_object_type /* Object */ struct epg_object { - RB_ENTRY(epg_object) uri_link; ///< Global URI link - LIST_ENTRY(epg_object) id_link; ///< Global (ID) link - LIST_ENTRY(epg_object) un_link; ///< Global unref'd link - LIST_ENTRY(epg_object) up_link; ///< Global updated link + RB_ENTRY(epg_object) uri_link; ///< Global URI link + LIST_ENTRY(epg_object) id_link; ///< Global (ID) link + LIST_ENTRY(epg_object) un_link; ///< Global unref'd link + LIST_ENTRY(epg_object) up_link; ///< Global updated link epg_object_type_t type; ///< Specific object type uint32_t id; ///< Internal ID char *uri; ///< Unique ID (from grabber) + time_t created; ///< Time the object was created + time_t updated; ///< Last time object was changed int _updated; ///< Flag to indicate updated int refcount; ///< Reference counting // Note: could use LIST_ENTRY field to determine this! - struct epggrab_module *grabber; ///< Originating grabber + struct epggrab_module *grabber; ///< Originating grabber - void (*getref) ( void *o ); ///< Get a reference - void (*putref) ( void *o ); ///< Release a reference - void (*destroy) ( void *o ); ///< Delete the object - void (*updated) ( void *o ); ///< Updated + void (*getref) ( void *o ); ///< Get a reference + void (*putref) ( void *o ); ///< Release a reference + void (*destroy) ( void *o ); ///< Delete the object + void (*update) ( void *o ); ///< Updated }; /* Get an object by ID (special case usage) */ diff --git a/src/htsp.c b/src/htsp.c index 0ffdec95..e380daf2 100644 --- a/src/htsp.c +++ b/src/htsp.c @@ -53,6 +53,10 @@ static void *htsp_server; #define HTSP_PROTO_VERSION 6 +#define HTSP_ASYNC_OFF 0x00 +#define HTSP_ASYNC_ON 0x01 +#define HTSP_ASYNC_EPG 0x02 + #define HTSP_PRIV_MASK (ACCESS_STREAMING) extern char *dvr_storage; @@ -96,7 +100,6 @@ typedef struct htsp_msg_q { int hmq_payload; /* Bytes of streaming payload that's enqueued */ } htsp_msg_q_t; - /** * */ @@ -463,7 +466,8 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method) * */ static htsmsg_t * -htsp_build_event(epg_broadcast_t *e, const char *method, const char *lang ) +htsp_build_event + (epg_broadcast_t *e, const char *method, const char *lang, time_t update ) { htsmsg_t *out; epg_broadcast_t *n; @@ -471,6 +475,20 @@ htsp_build_event(epg_broadcast_t *e, const char *method, const char *lang ) epg_genre_t *g; epg_episode_num_t epnum; const char *str; + epg_episode_t *ee = e->episode; + + /* Ignore? */ + if (update) { + int ignore = 1; + if (e->updated > update) ignore = 0; + else if (e->serieslink && e->serieslink->updated > update) ignore = 0; + else if (ee) { + if (ee->updated > update) ignore = 0; + else if (ee->brand && ee->brand->updated > update) ignore = 0; + else if (ee->season && ee->season->updated > update) ignore = 0; + } + if (ignore) return NULL; + } out = htsmsg_create_map(); @@ -492,21 +510,21 @@ htsp_build_event(epg_broadcast_t *e, const char *method, const char *lang ) if (e->serieslink) htsmsg_add_u32(out, "serieslinkId", e->serieslink->id); - if (e->episode) { - htsmsg_add_u32(out, "episodeId", e->episode->id); - if (e->episode->brand) - htsmsg_add_u32(out, "brandId", e->episode->brand->id); - if (e->episode->season) - htsmsg_add_u32(out, "seasonId", e->episode->brand->id); - if((g = LIST_FIRST(&e->episode->genre))) + if (ee) { + htsmsg_add_u32(out, "episodeId", ee->id); + if (ee->brand) + htsmsg_add_u32(out, "brandId", ee->brand->id); + if (ee->season) + htsmsg_add_u32(out, "seasonId", ee->season->id); + if((g = LIST_FIRST(&ee->genre))) htsmsg_add_u32(out, "contentType", g->code); - if (e->episode->age_rating) - htsmsg_add_u32(out, "ageRating", e->episode->age_rating); - if (e->episode->star_rating) - htsmsg_add_u32(out, "starRating", e->episode->star_rating); - if (e->episode->first_aired) - htsmsg_add_s64(out, "firstAired", e->episode->first_aired); - epg_episode_get_epnum(e->episode, &epnum); + if (ee->age_rating) + htsmsg_add_u32(out, "ageRating", ee->age_rating); + if (ee->star_rating) + htsmsg_add_u32(out, "starRating", ee->star_rating); + if (ee->first_aired) + htsmsg_add_s64(out, "firstAired", ee->first_aired); + epg_episode_get_epnum(ee, &epnum); if (epnum.s_num) { htsmsg_add_u32(out, "seasonNumber", epnum.s_num); if (epnum.s_cnt) @@ -524,8 +542,8 @@ htsp_build_event(epg_broadcast_t *e, const char *method, const char *lang ) } if (epnum.text) htsmsg_add_str(out, "episodeOnscreen", epnum.text); - if (e->episode->image) - htsmsg_add_str(out, "image", e->episode->image); + if (ee->image) + htsmsg_add_str(out, "image", ee->image); } if((de = dvr_entry_find_by_event(e)) != NULL) { @@ -690,7 +708,9 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in) if(htsp->htsp_async_mode) return NULL; /* already in async mode */ - htsp->htsp_async_mode = 1; + htsp->htsp_async_mode = HTSP_ASYNC_ON; + if(epg) + htsp->htsp_async_mode |= HTSP_ASYNC_EPG; /* Send all enabled and external tags */ TAILQ_FOREACH(ct, &channel_tags, ct_link) @@ -715,8 +735,8 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in) RB_FOREACH(ch, &channel_name_tree, ch_name_link) RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) { if (epgMaxTime && ebc->start > epgMaxTime) break; - htsmsg_t *e = htsp_build_event(ebc, "eventAdd", lang); - htsp_send_message(htsp, e, NULL); + htsmsg_t *e = htsp_build_event(ebc, "eventAdd", lang, lastUpdate); + if (e) htsp_send_message(htsp, e, NULL); } } @@ -748,7 +768,7 @@ htsp_method_getEvent(htsp_connection_t *htsp, htsmsg_t *in) if((e = epg_broadcast_find_by_id(eventId, NULL)) == NULL) return htsp_error("Event does not exist"); - return htsp_build_event(e, NULL, lang); + return htsp_build_event(e, NULL, lang, 0); } /** @@ -787,7 +807,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in) events = htsmsg_create_list(); while (e) { if (maxTime && e->start > maxTime) break; - htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang)); + htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0)); if (numFollowing == 1) break; if (numFollowing) numFollowing--; e = epg_broadcast_get_next(e); @@ -800,7 +820,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in) int num = numFollowing; RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) { if (maxTime && e->start > maxTime) break; - htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang)); + htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0)); if (num == 1) break; if (num) num--; } @@ -857,7 +877,8 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in) array = htsmsg_create_list(); for(i = 0; i < eqr.eqr_entries; ++i) { if (full) - htsmsg_add_msg(array, NULL, htsp_build_event(eqr.eqr_array[i], NULL, lang)); + htsmsg_add_msg(array, NULL, + htsp_build_event(eqr.eqr_array[i], NULL, lang, 0)); else htsmsg_add_u32(array, NULL, eqr.eqr_array[i]->id); } @@ -1510,12 +1531,13 @@ htsp_init(void) * */ static void -htsp_async_send(htsmsg_t *m) +htsp_async_send(htsmsg_t *m, int mode) { htsp_connection_t *htsp; LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) - htsp_send_message(htsp, htsmsg_copy(m), NULL); + if (htsp->htsp_async_mode & mode) + htsp_send_message(htsp, htsmsg_copy(m), NULL); htsmsg_destroy(m); } @@ -1540,7 +1562,7 @@ htsp_channel_update_current(channel_t *ch) next = ch->ch_epg_next; htsmsg_add_u32(m, "eventId", now ? now->id : 0); htsmsg_add_u32(m, "nextEventId", next ? next->id : 0); - htsp_async_send(m); + htsp_async_send(m, HTSP_ASYNC_ON); } /** @@ -1549,7 +1571,7 @@ htsp_channel_update_current(channel_t *ch) void htsp_channel_add(channel_t *ch) { - htsp_async_send(htsp_build_channel(ch, "channelAdd")); + htsp_async_send(htsp_build_channel(ch, "channelAdd"), HTSP_ASYNC_ON); } @@ -1559,7 +1581,7 @@ htsp_channel_add(channel_t *ch) void htsp_channel_update(channel_t *ch) { - htsp_async_send(htsp_build_channel(ch, "channelUpdate")); + htsp_async_send(htsp_build_channel(ch, "channelUpdate"), HTSP_ASYNC_ON); } @@ -1572,7 +1594,7 @@ htsp_channel_delete(channel_t *ch) htsmsg_t *m = htsmsg_create_map(); htsmsg_add_u32(m, "channelId", ch->ch_id); htsmsg_add_str(m, "method", "channelDelete"); - htsp_async_send(m); + htsp_async_send(m, HTSP_ASYNC_ON); } @@ -1582,7 +1604,7 @@ htsp_channel_delete(channel_t *ch) void htsp_tag_add(channel_tag_t *ct) { - htsp_async_send(htsp_build_tag(ct, "tagAdd", 1)); + htsp_async_send(htsp_build_tag(ct, "tagAdd", 1), HTSP_ASYNC_ON); } @@ -1592,7 +1614,7 @@ htsp_tag_add(channel_tag_t *ct) void htsp_tag_update(channel_tag_t *ct) { - htsp_async_send(htsp_build_tag(ct, "tagUpdate", 1)); + htsp_async_send(htsp_build_tag(ct, "tagUpdate", 1), HTSP_ASYNC_ON); } @@ -1605,7 +1627,7 @@ htsp_tag_delete(channel_tag_t *ct) htsmsg_t *m = htsmsg_create_map(); htsmsg_add_u32(m, "tagId", ct->ct_identifier); htsmsg_add_str(m, "method", "tagDelete"); - htsp_async_send(m); + htsp_async_send(m, HTSP_ASYNC_ON); } @@ -1615,7 +1637,7 @@ htsp_tag_delete(channel_tag_t *ct) void htsp_dvr_entry_add(dvr_entry_t *de) { - htsp_async_send(htsp_build_dvrentry(de, "dvrEntryAdd")); + htsp_async_send(htsp_build_dvrentry(de, "dvrEntryAdd"), HTSP_ASYNC_ON); } @@ -1625,7 +1647,7 @@ htsp_dvr_entry_add(dvr_entry_t *de) void htsp_dvr_entry_update(dvr_entry_t *de) { - htsp_async_send(htsp_build_dvrentry(de, "dvrEntryUpdate")); + htsp_async_send(htsp_build_dvrentry(de, "dvrEntryUpdate"), HTSP_ASYNC_ON); } @@ -1638,7 +1660,49 @@ htsp_dvr_entry_delete(dvr_entry_t *de) htsmsg_t *m = htsmsg_create_map(); htsmsg_add_u32(m, "id", de->de_id); htsmsg_add_str(m, "method", "dvrEntryDelete"); - htsp_async_send(m); + htsp_async_send(m, HTSP_ASYNC_ON); +} + +/** + * Event added + */ +void +htsp_event_add(epg_broadcast_t *ebc) +{ + htsp_connection_t *htsp; + htsmsg_t *m; + LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) { + if (!(htsp->htsp_async_mode & HTSP_ASYNC_EPG)) continue; + m = htsp_build_event(ebc, "eventAdd", htsp->htsp_language, 0); + htsp_send_message(htsp, m, NULL); + } +} + +/** + * Event updated + */ +void +htsp_event_update(epg_broadcast_t *ebc) +{ + htsp_connection_t *htsp; + htsmsg_t *m; + LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) { + if (!(htsp->htsp_async_mode & HTSP_ASYNC_EPG)) continue; + m = htsp_build_event(ebc, "eventUpdate", htsp->htsp_language, 0); + htsp_send_message(htsp, m, NULL); + } +} + +/** + * Event deleted + */ +void +htsp_event_delete(epg_broadcast_t *ebc) +{ + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_str(m, "method", "eventDeleted"); + htsmsg_add_u32(m, "eventId", ebc->id); + htsp_async_send(m, HTSP_ASYNC_EPG); } const static char frametypearray[PKT_NTYPES] = { diff --git a/src/htsp.h b/src/htsp.h index f150ec27..a82cca12 100644 --- a/src/htsp.h +++ b/src/htsp.h @@ -38,4 +38,8 @@ void htsp_dvr_entry_add(dvr_entry_t *de); void htsp_dvr_entry_update(dvr_entry_t *de); void htsp_dvr_entry_delete(dvr_entry_t *de); +void htsp_event_add(epg_broadcast_t *ebc); +void htsp_event_update(epg_broadcast_t *ebc); +void htsp_event_delete(epg_broadcast_t *ebc); + #endif /* HTSP_H_ */