Tidy up of the epg broadcast code, I think this now works it should be a bit simpler.

This commit is contained in:
Adam Sutton 2012-05-31 13:25:24 +01:00
parent 2a30767ca8
commit 4a71b4c7d7
2 changed files with 65 additions and 61 deletions

124
src/epg.c
View file

@ -65,11 +65,9 @@ static int _id_cmp ( const void *a, const void *b )
return ((epg_object_t*)a)->id - ((epg_object_t*)b)->id;
}
static int _ebc_win_cmp ( const void *a, const void *b )
static int _ebc_start_cmp ( const void *a, const void *b )
{
if ( ((epg_broadcast_t*)a)->start < ((epg_broadcast_t*)b)->start ) return -1;
if ( ((epg_broadcast_t*)a)->start >= ((epg_broadcast_t*)b)->stop ) return 1;
return 0;
return ((epg_broadcast_t*)a)->start - ((epg_broadcast_t*)b)->start;
}
/* **************************************************************************
@ -940,8 +938,6 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save )
* Channel
* *************************************************************************/
static epg_broadcast_t **_epg_broadcast_skel ( void );
static void _epg_channel_timer_callback ( void *p )
{
time_t next = 0;
@ -998,74 +994,74 @@ static void _epg_channel_timer_callback ( void *p )
}
}
void epg_channel_unlink ( channel_t *ch )
static void _epg_channel_rem_broadcast
( channel_t *ch, epg_broadcast_t *ebc, epg_broadcast_t *new )
{
epg_object_t *eo;
while ( (eo = RB_FIRST(&ch->ch_epg_schedule)) ) {
RB_REMOVE(&ch->ch_epg_schedule, eo, glink);
}
gtimer_disarm(&ch->ch_epg_timer);
if (new) dvr_event_replaced(ebc, new);
RB_REMOVE(&ch->ch_epg_schedule, (epg_object_t*)ebc, glink);
ebc->_.putref((epg_object_t*)ebc);
}
static epg_broadcast_t *_epg_channel_add_broadcast
( channel_t *ch, epg_broadcast_t **ebc, int create, int *save )
( channel_t *ch, epg_broadcast_t **bcast, int create, int *save )
{
int save2 = 0, timer = 0;
epg_broadcast_t *ret;
epg_object_t *eo;
epg_broadcast_t *ebc, *ret;
/* Set channel */
(*bcast)->channel = ch;
/* Find/Create */
ret = (epg_broadcast_t*)
_epg_object_find(create, &save2, &ch->ch_epg_schedule,
(epg_object_t**)ebc, _ebc_win_cmp);
if (!ret) return NULL;
eo = _epg_object_find(create, &save2, &ch->ch_epg_schedule,
(epg_object_t**)bcast, _ebc_start_cmp);
if (!eo) return NULL;
ret = (epg_broadcast_t*)eo;
/* Created */
if (save2) {
ret->_.getref((epg_object_t*)ret);
/* New current/next */
if ( (RB_FIRST(&ch->ch_epg_schedule) == (epg_object_t*)ret) ||
(ch->ch_epg_now &&
RB_NEXT((epg_object_t*)ch->ch_epg_now, glink) == (epg_object_t*)ret) ) {
timer = 1;
}
*save |= 1;
/* No changes */
if (!save2 && (ret->start == (*bcast)->start) &&
(ret->stop == (*bcast)->stop)) return ret;
/* Update */
} else {
if ( (*ebc)->stop != ret->stop ) {
ret->stop = (*ebc)->stop;
if ( ret == ch->ch_epg_now ) timer = 1;
*save |= 1;
}
if ( (*ebc)->start != ret->start ) {
ret->start = (*ebc)->start;
if ( !ch->ch_epg_now && ret == ch->ch_epg_next ) timer = 1;
}
if ( (*ebc)->episode ) {
*save |= epg_broadcast_set_episode(ret, (*ebc)->episode);
}
// Note: scheduling changes are relatively rare and therefore
// the rest of this code will happen infrequently (hopefully)
/* Grab ref */
ret->_.getref((epg_object_t*)ret);
*save |= 1;
/* Remove overlapping (before) */
while ( (ebc = (epg_broadcast_t*)RB_PREV(eo, glink)) != NULL ) {
if ( ebc->stop <= ret->start ) break;
if ( ch->ch_epg_now == ebc ) ch->ch_epg_now = NULL;
_epg_channel_rem_broadcast(ch, ebc, ret);
}
/* reset timer */
/* Remove overlapping (after) */
while ( (ebc = (epg_broadcast_t*)RB_NEXT(eo, glink)) != NULL ) {
if ( ebc->start >= ret->stop ) break;
_epg_channel_rem_broadcast(ch, ebc, ret);
}
/* Check now/next change */
if ( RB_FIRST(&ch->ch_epg_schedule) == eo ) {
timer = 1;
} else if ( ch->ch_epg_now &&
RB_NEXT((epg_object_t*)ch->ch_epg_now, glink) == eo ) {
timer = 1;
}
/* Reset timer */
if (timer) _epg_channel_timer_callback(ch);
return ret;
}
epg_broadcast_t *epg_channel_get_broadcast
( channel_t *ch, time_t start, time_t stop, int create, int *save )
void epg_channel_unlink ( channel_t *ch )
{
epg_broadcast_t **ebc;
if ( !ch || !start || !stop ) return NULL;
if ( stop <= start ) return NULL;
if ( stop < dispatch_clock ) return NULL;
ebc = _epg_broadcast_skel();
(*ebc)->channel = ch;
(*ebc)->start = start;
(*ebc)->stop = stop;
return _epg_channel_add_broadcast(ch, ebc, create, save);
epg_object_t *eo;
while ( (eo = RB_FIRST(&ch->ch_epg_schedule)) ) {
_epg_channel_rem_broadcast(ch, (epg_broadcast_t*)eo, NULL);
}
gtimer_disarm(&ch->ch_epg_timer);
}
/* **************************************************************************
@ -1097,10 +1093,18 @@ static epg_broadcast_t **_epg_broadcast_skel ( void )
epg_broadcast_t* epg_broadcast_find_by_time
( channel_t *channel, time_t start, time_t stop, int create, int *save )
{
return epg_channel_get_broadcast(channel, start, stop, create, save);
epg_broadcast_t **ebc;
if ( !channel || !start || !stop ) return NULL;
if ( stop <= start ) return NULL;
if ( stop < dispatch_clock ) return NULL;
ebc = _epg_broadcast_skel();
(*ebc)->start = start;
(*ebc)->stop = stop;
return _epg_channel_add_broadcast(channel, ebc, create, save);
}
// TODO: allow optional channel parameter?
epg_broadcast_t *epg_broadcast_find_by_id ( uint64_t id, channel_t *ch )
{
epg_object_t *eo = NULL;
@ -1182,7 +1186,7 @@ epg_broadcast_t *epg_broadcast_deserialize
if ( ch ) {
ret = _epg_channel_add_broadcast(ch, ebc, create, save);
/* Create dangling */
/* Create dangling (possibly in use by DVR?) */
} else {
ret = *ebc;
_epg_object_create((epg_object_t*)*ebc);

View file

@ -60,7 +60,7 @@ void eit_callback ( channel_t *ch, int id, time_t start, time_t stop,
#endif
/* Find broadcast */
ebc = epg_channel_get_broadcast(ch, start, stop, 1, &save);
ebc = epg_broadcast_find_by_time(ch, start, stop, 1, &save);
if (!ebc) return;
/* TODO: Determine summary */