Some fixes and updates to get broadcast expiration and now/next working.

This commit is contained in:
Adam Sutton 2012-05-25 11:36:44 +01:00
parent cd3482dc06
commit e9a8ad5a48
4 changed files with 94 additions and 37 deletions

111
src/epg.c
View file

@ -104,6 +104,7 @@ static int _epg_channel_cmp ( epg_channel_t *ec, channel_t *ch )
* Testing/Debug
* *************************************************************************/
#if 0
static void _epg_dump ( void )
{
epg_object_t *eo;
@ -155,6 +156,7 @@ static void _epg_dump ( void )
}
}
}
#endif
/* **************************************************************************
* Setup / Update
@ -327,21 +329,22 @@ void epg_init ( void )
void epg_updated ( void )
{
epg_object_t *eo;
LIST_FOREACH(eo, &epg_object_unref, ulink) {
printf("unref'd object %lu\n", eo->id);
while ((eo = LIST_FIRST(&epg_object_unref))) {
tvhlog(LOG_DEBUG, "epg",
"unref'd object %lu (%s) created during update", eo->id, eo->uri);
LIST_REMOVE(eo, ulink);
eo->destroy(eo);
}
// TODO: remove this
if (0)_epg_dump();
}
/* **************************************************************************
* Object
* *************************************************************************/
static void _epg_object_destroy ( epg_object_t *eo )
static void _epg_object_destroy ( epg_object_t *eo, epg_object_tree_t *tree )
{
if (eo->uri) free(eo->uri);
if (tree) RB_REMOVE(tree, eo, glink);
}
static void _epg_object_getref ( epg_object_t *eo )
@ -354,6 +357,7 @@ static void _epg_object_putref ( epg_object_t *eo )
{
assert(eo->refcount>0); // Sanity!
eo->refcount--;
printf("putref(%lu) = %d\n", eo->id, eo->refcount);
// TODO: do this here or defer to the epg_updated call?
if (!eo->refcount) eo->destroy(eo);
}
@ -436,6 +440,7 @@ static epg_object_t *_epg_object_find_by_id
static void _epg_brand_destroy ( epg_object_t *eo )
{
printf("_epg_brand_destroy(%lu, %s)\n", eo->id, eo->uri);
epg_brand_t *eb = (epg_brand_t*)eo;
if (RB_FIRST(&eb->seasons)) {
tvhlog(LOG_CRIT, "epg", "attempt to destroy brand with seasons");
@ -445,7 +450,7 @@ static void _epg_brand_destroy ( epg_object_t *eo )
tvhlog(LOG_CRIT, "epg", "attempt to destroy brand with episodes");
assert(0);
}
_epg_object_destroy(eo);
_epg_object_destroy(eo, &epg_brands);
if (eb->title) free(eb->title);
if (eb->summary) free(eb->summary);
free(eb);
@ -567,12 +572,13 @@ epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create, int *save )
static void _epg_season_destroy ( epg_object_t *eo )
{
printf("_epg_season_destroy(%lu, %s)\n", eo->id, eo->uri);
epg_season_t *es = (epg_season_t*)eo;
if (RB_FIRST(&es->episodes)) {
tvhlog(LOG_CRIT, "epg", "attempt to destory season with episodes");
assert(0);
}
_epg_object_destroy(eo);
_epg_object_destroy(eo, &epg_seasons);
if (es->brand) {
_epg_brand_rem_season(es->brand, es);
es->brand->_.putref((epg_object_t*)es->brand);
@ -641,7 +647,7 @@ int epg_season_set_brand ( epg_season_t *season, epg_brand_t *brand, int u )
}
season->brand = brand;
_epg_brand_add_season(brand, season);
season->_.getref((epg_object_t*)season);
brand->_.getref((epg_object_t*)brand);
save = 1;
}
return save;
@ -708,12 +714,13 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save )
static void _epg_episode_destroy ( epg_object_t *eo )
{
printf("_epg_episode_destroy(%lu, %s)\n", eo->id, eo->uri);
epg_episode_t *ee = (epg_episode_t*)eo;
if (RB_FIRST(&ee->broadcasts)) {
tvhlog(LOG_CRIT, "epg", "attempt to destroy episode with broadcasts");
assert(0);
}
_epg_object_destroy(eo);
_epg_object_destroy(eo, &epg_episodes);
if (ee->brand) {
_epg_brand_rem_episode(ee->brand, ee);
ee->brand->_.putref((epg_object_t*)ee->brand);
@ -948,7 +955,9 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save )
static void _epg_broadcast_destroy ( epg_object_t *eo )
{
printf("_epg_broadcast_destroy(%lu)\n", eo->id);
epg_broadcast_t *ebc = (epg_broadcast_t*)eo;
_epg_object_destroy(eo, NULL);
if (ebc->episode) {
_epg_episode_rem_broadcast(ebc->episode, ebc);
ebc->episode->_.putref((epg_object_t*)ebc->episode);
@ -1012,8 +1021,8 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast )
htsmsg_add_u32(m, "id", broadcast->_.id);
htsmsg_add_u32(m, "start", broadcast->start);
htsmsg_add_u32(m, "stop", broadcast->stop);
// TODO: should these be optional?
htsmsg_add_str(m, "channel", broadcast->channel->_.uri);
if (broadcast->channel)
htsmsg_add_str(m, "channel", broadcast->channel->_.uri);
htsmsg_add_str(m, "episode", broadcast->episode->_.uri);
if (broadcast->dvb_id)
@ -1032,10 +1041,13 @@ epg_broadcast_t *epg_broadcast_deserialize
uint32_t start, stop;
uint64_t id;
// TODO: need to handle broadcasts without a channel
// this will happen for DVR maintained broadcasts which
// reference a no longer used channel (and also they will be
// outside the time limit).
if ( htsmsg_get_u64(m, "id", &id) ) return NULL;
if ( htsmsg_get_u32(m, "start", &start) ) return NULL;
if ( htsmsg_get_u32(m, "stop", &stop) ) return NULL;
// TODO: should these be optional?
if ( !(str = htsmsg_get_str(m, "channel")) ) return NULL;
if ( !(ec = epg_channel_find_by_uri(str, 0, NULL)) ) return NULL;
if ( !(str = htsmsg_get_str(m, "episode")) ) return NULL;
@ -1063,30 +1075,72 @@ epg_broadcast_t *epg_broadcast_deserialize
* Channel
* *************************************************************************/
static void _epg_channel_expire_callback ( void *p )
static void _epg_channel_timer_callback ( void *p )
{
time_t next = 0;
epg_object_t *eo;
epg_broadcast_t *ebc;
epg_broadcast_t *ebc, *cur;
epg_channel_t *ec = (epg_channel_t*)p;
/* Clear now/next */
cur = ec->now;
ec->now = ec->next = NULL;
#if 0
printf("dispatch_clock = %lu\n", dispatch_clock);
RB_FOREACH(eo, &ec->schedule, glink) {
ebc = (epg_broadcast_t*)eo;
printf("entry %lu @ %lu to %lu\n", eo->id, ebc->start, ebc->stop);
}
#endif
/* Check events */
while ( (eo = RB_FIRST(&ec->schedule)) ) {
ebc = (epg_broadcast_t*)eo;
if ( ebc->stop < dispatch_clock ) {
/* Expire */
if ( ebc->stop <= dispatch_clock ) {
RB_REMOVE(&ec->schedule, eo, glink);
eo->putref(eo);
tvhlog(LOG_DEBUG, "epg", "expire event %lu from %s",
eo->id, ec->_.uri);
continue; // skip to next
/* No now */
} else if ( ebc->start > dispatch_clock ) {
ec->next = ebc;
next = ebc->start;
/* Now/Next */
} else {
next = ebc->stop;
break;
ec->now = ebc;
ec->next = (epg_broadcast_t*)RB_NEXT(eo, glink);
next = ebc->stop;
}
break;
}
tvhlog(LOG_DEBUG, "epg", "now/next %lu/%lu set on %s",
ec->now ? ec->now->_.id : 0,
ec->next ? ec->next->_.id : 0,
ec->_.uri);
/* re-arm */
if ( next )
gtimer_arm_abs(&ec->expire, _epg_channel_expire_callback, ec, next);
if ( next ) {
tvhlog(LOG_DEBUG, "epg", "arm channel timer @ %lu for %s",
next, ec->_.uri);
gtimer_arm_abs(&ec->expire, _epg_channel_timer_callback, ec, next);
}
/* Update HTSP */
if ( (cur != ec->now) && ec->channel ) {
tvhlog(LOG_DEBUG, "epg", "inform HTSP of now event change on %s",
ec->_.uri);
htsp_channel_update_current(ec->channel);
}
}
static void _epg_channel_destroy ( epg_object_t *eo )
{
printf("_epg_channel_destroy(%lu, %s)\n", eo->id, eo->uri);
epg_channel_t *ec = (epg_channel_t*)eo;
if (ec->channel) {
tvhlog(LOG_CRIT, "epg", "attempt to destroy mapped channel");
@ -1096,6 +1150,7 @@ static void _epg_channel_destroy ( epg_object_t *eo )
tvhlog(LOG_CRIT, "epg", "attempt to destroy channel with schedule");
assert(0);
}
_epg_object_destroy(eo, &epg_channels);
gtimer_disarm(&ec->expire);
if (ec->name) free(ec->name);
#if TODO_NOT_IMPLEMENTED
@ -1196,20 +1251,18 @@ epg_broadcast_t *epg_channel_get_broadcast
(epg_object_t**)&skel, _ebc_win_cmp);
if (save2) {
ebc->_.getref((epg_object_t*)ebc);
if (RB_FIRST(&channel->schedule) == (epg_object_t*)ebc)
_epg_channel_expire_callback(channel);
/* New current/next */
if ( (RB_FIRST(&channel->schedule) == (epg_object_t*)ebc) ||
(channel->now &&
RB_NEXT((epg_object_t*)channel->now, glink) == (epg_object_t*)ebc) ) {
_epg_channel_timer_callback(channel);
}
*save |= 1;
}
return ebc;
}
epg_broadcast_t *epg_channel_get_current_broadcast ( epg_channel_t *channel )
{
// TODO: its not really the head!
if ( !channel ) return NULL;
return (epg_broadcast_t*)RB_FIRST(&channel->schedule);
}
htsmsg_t *epg_channel_serialize ( epg_channel_t *channel )
{
htsmsg_t *m;

View file

@ -277,6 +277,9 @@ typedef struct epg_channel
LIST_ENTRY(epg_channel) umlink; ///< Unmapped channel link
channel_t *channel; ///< Link to real channel
epg_broadcast_t *now; ///< Current broadcast
epg_broadcast_t *next; ///< Next broadcast
gtimer_t expire; ///< Expiration timer
} epg_channel_t;
@ -291,7 +294,6 @@ int epg_channel_set_name ( epg_channel_t *c, const char *n )
int epg_channel_set_channel ( epg_channel_t *c, channel_t *ch );
/* Accessors */
epg_broadcast_t *epg_channel_get_current_broadcast ( epg_channel_t *c );
epg_broadcast_t *epg_channel_get_broadcast
( epg_channel_t *ch, time_t start, time_t stop, int create, int *save );

View file

@ -310,10 +310,12 @@ htsp_build_channel(channel_t *ch, const char *method)
if(ch->ch_icon != NULL)
htsmsg_add_str(out, "channelIcon", ch->ch_icon);
now = epg_channel_get_current_broadcast(ch->ch_epg_channel);
if ( now ) next = epg_broadcast_get_next(now);
htsmsg_add_u32(out, "eventId", now ? now->_.id : 0);
htsmsg_add_u32(out, "nextEventId", next ? next->_.id : 0);
if (ch->ch_epg_channel) {
now = ch->ch_epg_channel->now;
next = ch->ch_epg_channel->next;
htsmsg_add_u32(out, "eventId", now ? now->_.id : 0);
htsmsg_add_u32(out, "nextEventId", next ? next->_.id : 0);
}
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
ct = ctm->ctm_tag;
@ -1425,8 +1427,8 @@ htsp_channel_update_current(channel_t *ch)
htsmsg_add_str(m, "method", "channelUpdate");
htsmsg_add_u32(m, "channelId", ch->ch_id);
now = epg_channel_get_current_broadcast(ch->ch_epg_channel);
next = epg_broadcast_get_next(now);
now = ch->ch_epg_channel->now;
next = ch->ch_epg_channel->next;
htsmsg_add_u32(m, "eventId", now ? now->_.id : 0);
htsmsg_add_u32(m, "nextEventId", next ? next->_.id : 0);
htsp_async_send(m);

View file

@ -181,7 +181,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t
sm->sm_data = NULL;
epg_broadcast_t *e = NULL;
if(s->ths_channel) e = epg_channel_get_current_broadcast(s->ths_channel->ch_epg_channel);
if(s->ths_channel) e = s->ths_channel->ch_epg_channel->now;
if(e && event_id != e->_.id) {
event_id = e->_.id;