From d59979f4de5884baf4f935c9cdc3efb6dbf53ab9 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 13:28:27 +0100 Subject: [PATCH] Some more tidying up and adding back in missing code. --- src/dvb/dvb.h | 2 +- src/epggrab.c | 90 ++---------------- src/epggrab.h | 24 +++-- src/epggrab/channel.c | 176 +++++++++++++++++++----------------- src/epggrab/module.c | 167 +++++++++++++++++++++------------- src/epggrab/module/eit.c | 24 +++++ src/epggrab/module/opentv.c | 143 +++++++++++++++-------------- src/epggrab/module/pyepg.c | 9 +- src/epggrab/module/xmltv.c | 8 +- src/epggrab/otamux.c | 136 +++++++++++++++++++--------- src/epggrab/private.h | 16 +++- 11 files changed, 429 insertions(+), 366 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 20427302..9e627354 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -135,10 +135,10 @@ typedef struct th_dvb_mux_instance { struct service_list tdmi_transports; /* via s_mux_link */ - TAILQ_ENTRY(th_dvb_mux_instance) tdmi_scan_link; struct th_dvb_mux_instance_queue *tdmi_scan_queue; + TAILQ_HEAD(, epggrab_ota_mux) tdmi_epg_grab; } th_dvb_mux_instance_t; diff --git a/src/epggrab.c b/src/epggrab.c index 213b3af6..643af33b 100644 --- a/src/epggrab.c +++ b/src/epggrab.c @@ -34,53 +34,9 @@ uint32_t epggrab_channel_renumber; uint32_t epggrab_channel_reicon; /* ************************************************************************** - * Helpers + * Internal Grab Thread * *************************************************************************/ -void epggrab_resched ( void ) -{ -} - -/* - * Run the parse - */ -void epggrab_module_parse - ( void *m, htsmsg_t *data ) -{ - time_t tm1, tm2; - int save = 0; - epggrab_stats_t stats; - epggrab_module_int_t *mod = m; - - /* Parse */ - memset(&stats, 0, sizeof(stats)); - pthread_mutex_lock(&global_lock); - time(&tm1); - save |= mod->parse(mod, data, &stats); - time(&tm2); - if (save) epg_updated(); - pthread_mutex_unlock(&global_lock); - htsmsg_destroy(data); - - /* Debug stats */ - tvhlog(LOG_INFO, mod->id, "parse took %d seconds", tm2 - tm1); - tvhlog(LOG_INFO, mod->id, " channels tot=%5d new=%5d mod=%5d", - stats.channels.total, stats.channels.created, - stats.channels.modified); - tvhlog(LOG_INFO, mod->id, " brands tot=%5d new=%5d mod=%5d", - stats.brands.total, stats.brands.created, - stats.brands.modified); - tvhlog(LOG_INFO, mod->id, " seasons tot=%5d new=%5d mod=%5d", - stats.seasons.total, stats.seasons.created, - stats.seasons.modified); - tvhlog(LOG_INFO, mod->id, " episodes tot=%5d new=%5d mod=%5d", - stats.episodes.total, stats.episodes.created, - stats.episodes.modified); - tvhlog(LOG_INFO, mod->id, " broadcasts tot=%5d new=%5d mod=%5d", - stats.broadcasts.total, stats.broadcasts.created, - stats.broadcasts.modified); -} - /* * Grab from module */ @@ -103,10 +59,6 @@ static void _epggrab_module_grab ( epggrab_module_int_t *mod ) } } -/* ************************************************************************** - * Internal Grab Thread - * *************************************************************************/ - /* * Thread (for internal grabbing) */ @@ -340,43 +292,17 @@ int epggrab_enable_module_by_id ( const char *id, uint8_t e ) return epggrab_enable_module(epggrab_module_find_by_id(id), e); } -/* ************************************************************************** - * Module Access - * *************************************************************************/ - -epggrab_module_t* epggrab_module_find_by_id ( const char *id ) -{ - epggrab_module_t *m; - LIST_FOREACH(m, &epggrab_modules, link) { - if ( !strcmp(m->id, id) ) return m; - } - return NULL; -} - -htsmsg_t *epggrab_module_list ( void ) -{ - epggrab_module_t *m; - htsmsg_t *e, *a = htsmsg_create_list(); - LIST_FOREACH(m, &epggrab_modules, link) { - e = htsmsg_create_map(); - htsmsg_add_str(e, "id", m->id); - htsmsg_add_u32(e, "type", m->type); - htsmsg_add_u32(e, "enabled", m->enabled); - if(m->name) - htsmsg_add_str(e, "name", m->name); - if(m->type == EPGGRAB_EXT) { - epggrab_module_ext_t *ext = (epggrab_module_ext_t*)m; - htsmsg_add_str(e, "path", ext->path); - } - htsmsg_add_msg(a, NULL, e); - } - return a; -} - /* ************************************************************************** * Initialisation * *************************************************************************/ +/* + * TODO: implement this + */ +void epggrab_resched ( void ) +{ +} + /* * Initialise */ diff --git a/src/epggrab.h b/src/epggrab.h index ea95ebce..f4d8b019 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -125,9 +125,16 @@ struct epggrab_module const char *id; ///< Module identifier const char *name; ///< Module name (for display) uint8_t enabled; ///< Whether the module is enabled + epggrab_channel_tree_t *channels; ///< Channel list /* Enable/Disable */ int (*enable) ( void *m, uint8_t e ); + + /* Channel listings */ + void (*ch_add) ( void *m, struct channel *ch ); + void (*ch_rem) ( void *m, struct channel *ch ); + void (*ch_mod) ( void *m, struct channel *ch ); + void (*ch_save) ( void *m, epggrab_channel_t *ch ); }; /* @@ -138,17 +145,11 @@ struct epggrab_module_int epggrab_module_t ; ///< Parent object const char *path; ///< Path for the command - epggrab_channel_tree_t *channels; ///< Channel list /* Handle data */ char* (*grab) ( void *mod ); htsmsg_t* (*trans) ( void *mod, char *data ); int (*parse) ( void *mod, htsmsg_t *data, epggrab_stats_t *stat ); - - /* Channel listings */ - void (*ch_add) ( void *m, struct channel *ch ); - void (*ch_rem) ( void *m, struct channel *ch ); - void (*ch_mod) ( void *m, struct channel *ch ); }; /* @@ -166,15 +167,16 @@ struct epggrab_module_ext */ struct epggrab_ota_mux { - LIST_ENTRY(epggrab_ota_mux) glob_link; ///< Grabber link - TAILQ_ENTRY(epggrab_ota_mux) reg_link; ///< List of reg'd + TAILQ_ENTRY(epggrab_ota_mux) glob_link; ///< Grabber link + TAILQ_ENTRY(epggrab_ota_mux) tdmi_link; ///< Link to mux + TAILQ_ENTRY(epggrab_ota_mux) grab_link; ///< Link to grabber struct th_dvb_mux_instance *tdmi; ///< Mux instance epggrab_module_ota_t *grab; ///< Grab instance int timeout; ///< Time out if this long int interval; ///< Re-grab this often - int is_reg; ///< Registered with mux + int is_reg; ///< Permanently registered void *status; ///< Status information enum { @@ -194,7 +196,9 @@ struct epggrab_ota_mux */ struct epggrab_module_ota { - epggrab_module_t ; ///< Parent object + epggrab_module_t ; ///< Parent object + + TAILQ_HEAD(, epggrab_ota_mux) muxes; ///< List of related muxes /* Transponder tuning */ void (*start) ( epggrab_module_ota_t *m, struct th_dvb_mux_instance *tdmi ); diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c index 8b3b21eb..634f5d8c 100644 --- a/src/epggrab/channel.c +++ b/src/epggrab/channel.c @@ -28,14 +28,12 @@ #include "epggrab.h" #include "epggrab/private.h" -#if 0 -static int _ch_id_cmp ( void *a, void *b ) -{ - return strcmp(((epggrab_channel_t*)a)->id, - ((epggrab_channel_t*)b)->id); -} -#endif +/* ************************************************************************** + * EPG Grab Channel functions + * *************************************************************************/ +/* Link epggrab channel to real channel */ +// returns 1 if link made int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch ) { service_t *sv; @@ -87,6 +85,7 @@ int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch ) return match; } +/* Set name */ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) { int save = 0; @@ -94,41 +93,66 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) if (!ec->name || strcmp(ec->name, name)) { if (ec->name) free(ec->name); ec->name = strdup(name); - if (ec->channel) channel_rename(ec->channel, name); + if (ec->channel && epggrab_channel_rename) + channel_rename(ec->channel, name); save = 1; } return save; } +/* Set icon */ +int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) +{ + int save = 0; + if (!ec->icon || strcmp(ec->icon, icon) ) { + if (!ec | !icon) return 0; + if (ec->icon) free(ec->icon); + ec->icon = strdup(icon); + if (ec->channel) channel_set_icon(ec->channel, icon); + save = 1; + } + return save; +} + +/* Set channel number */ +int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) +{ + int save = 0; + if (!ec || (number <= 0)) return 0; + if (ec->number != number) { + ec->number = number; + if (ec->channel) channel_set_number(ec->channel, number); + save = 1; + } + return save; +} + +/* Set service IDs */ int epggrab_channel_set_sid ( epggrab_channel_t *ec, const uint16_t *sid ) { -#if 0 - int save = 0, i = 0, num = 0; + int save = 0, i; if ( !ec || !sid ) return 0; if (!ec->sid) save = 1; else { - - for (i = 0; i < num; i++ ) { - if (sid[i] != ec->sid[i]) { - save = 1; - break; - } + i = 0; + while ( ec->sid[i] && sid[i] ) { + if ( ec->sid[i] != sid[i] ) break; + i++; } + if (ec->sid[i] || sid[i]) save = 1; } if (save) { + i = 0; + while (ec->sid[i++]); if (ec->sid) free(ec->sid); - ec->sid = calloc(num, sizeof(uint16_t)); - for (i = 0; i < num; i++ ) { - ec->sid[i] = sid[i]; - } - ec->sid_cnt = num; + ec->sid = calloc(i, sizeof(uint16_t)); + memcpy(ec->sid, sid, i * sizeof(uint16_t)); } return save; -#endif - return 0; } +/* Set names */ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) { int save = 0, i = 0; @@ -136,13 +160,10 @@ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) if (!ec->sname) save = 1; else { while ( ec->sname[i] && sname[i] ) { - if (strcmp(ec->sname[i], sname[i])) { - save = 1; - break; - } + if (strcmp(ec->sname[i], sname[i])) break; i++; } - if (!save && (ec->sname[i] || sname[i])) save = 1; + if (ec->sname[i] || sname[i]) save = 1; } if (save) { if (ec->sname) { @@ -163,57 +184,60 @@ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) return save; } -int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) -{ - int save = 0; - if (!ec->icon || strcmp(ec->icon, icon) ) { - if (!ec | !icon) return 0; - if (ec->icon) free(ec->icon); - ec->icon = strdup(icon); - if (ec->channel) channel_set_icon(ec->channel, icon); - save = 1; - } - return save; -} - -int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) -{ - int save = 0; - if (!ec || (number <= 0)) return 0; - if (ec->number != number) { - ec->number = number; - if (ec->channel) channel_set_number(ec->channel, number); - save = 1; - } - return save; -} - - +/* Channel settings updated */ void epggrab_channel_updated ( epggrab_channel_t *ec ) { - //epggrab_channel_link(ec); - epggrab_module_ch_save(ec->mod, ec); -} - -#if 0 -void epggrab_channel_link ( epggrab_channel_t *ec ) -{ channel_t *ch; - if (!ec) return; - /* Link */ - if (!ec->channel) { - RB_FOREACH(ch, &channel_name_tree, ch_name_link) { - if (_ch_link(ec, ch)) break; + /* Find a link */ + if (!ec->channel) + RB_FOREACH(ch, &channel_name_tree, ch_name_link) + if (epggrab_channel_link(ec, ch)) break; + + /* Save */ + if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec); +} + +/* ID comparison */ +static int _ch_id_cmp ( void *a, void *b ) +{ + return strcmp(((epggrab_channel_t*)a)->id, + ((epggrab_channel_t*)b)->id); +} + +/* Find/Create channel in the list */ +epggrab_channel_t *epggrab_channel_find + ( epggrab_channel_tree_t *tree, const char *id, int create, int *save ) +{ + epggrab_channel_t *ec; + static epggrab_channel_t *skel = NULL; + if (!skel) skel = calloc(1, sizeof(epggrab_channel_t)); + skel->id = (char*)id; + + /* Find */ + if (!create) { + ec = RB_FIND(tree, skel, link, _ch_id_cmp); + + /* Find/Create */ + } else { + ec = RB_INSERT_SORTED(tree, skel, link, _ch_id_cmp); + if (!ec) { + ec = skel; + skel = NULL; + ec->id = strdup(id); + *save = 1; } } + return ec; } -#endif + +/* ************************************************************************** + * Global routines + * *************************************************************************/ htsmsg_t *epggrab_channel_list ( void ) { -#if 0 char name[100]; epggrab_module_t *mod; epggrab_channel_t *ec; @@ -232,44 +256,28 @@ htsmsg_t *epggrab_channel_list ( void ) } } return m; -#endif - return NULL; } void epggrab_channel_add ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_add) m->ch_add(m, ch); } -#endif } void epggrab_channel_rem ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_rem) m->ch_rem(m, ch); } -#endif } void epggrab_channel_mod ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_mod) m->ch_mod(m, ch); } -#endif } - -epggrab_channel_t *epggrab_channel_find - ( epggrab_channel_tree_t *tree, const char *id, int create, int *save ) -{ - // TODO - return NULL; -} - diff --git a/src/epggrab/module.c b/src/epggrab/module.c index 092f7d99..52f48c9a 100644 --- a/src/epggrab/module.c +++ b/src/epggrab/module.c @@ -35,18 +35,59 @@ #include "epggrab.h" #include "epggrab/private.h" +/* ************************************************************************** + * Module Access + * *************************************************************************/ + +epggrab_module_t* epggrab_module_find_by_id ( const char *id ) +{ + epggrab_module_t *m; + LIST_FOREACH(m, &epggrab_modules, link) { + if ( !strcmp(m->id, id) ) return m; + } + return NULL; +} + +htsmsg_t *epggrab_module_list ( void ) +{ + epggrab_module_t *m; + htsmsg_t *e, *a = htsmsg_create_list(); + LIST_FOREACH(m, &epggrab_modules, link) { + e = htsmsg_create_map(); + htsmsg_add_str(e, "id", m->id); + htsmsg_add_u32(e, "type", m->type); + htsmsg_add_u32(e, "enabled", m->enabled); + if(m->name) + htsmsg_add_str(e, "name", m->name); + if(m->type == EPGGRAB_EXT) { + epggrab_module_ext_t *ext = (epggrab_module_ext_t*)m; + htsmsg_add_str(e, "path", ext->path); + } + htsmsg_add_msg(a, NULL, e); + } + return a; +} + /* ************************************************************************** * Generic module routines * *************************************************************************/ epggrab_module_t *epggrab_module_create - ( epggrab_module_t *skel, const char *id, const char *name ) + ( epggrab_module_t *skel, const char *id, const char *name, + epggrab_channel_tree_t *channels ) { assert(skel); /* Setup */ - skel->id = strdup(id); - skel->name = strdup(name); + skel->id = strdup(id); + skel->name = strdup(name); + skel->channels = channels; + if (channels) { + skel->ch_save = epggrab_module_ch_save; + skel->ch_add = epggrab_module_ch_add; + skel->ch_mod = epggrab_module_ch_mod; + skel->ch_rem = epggrab_module_ch_rem; + } /* Insert */ assert(!epggrab_module_find_by_id(id)); @@ -55,8 +96,48 @@ epggrab_module_t *epggrab_module_create return skel; } +/* + * Run the parse + */ +void epggrab_module_parse + ( void *m, htsmsg_t *data ) +{ + time_t tm1, tm2; + int save = 0; + epggrab_stats_t stats; + epggrab_module_int_t *mod = m; + + /* Parse */ + memset(&stats, 0, sizeof(stats)); + pthread_mutex_lock(&global_lock); + time(&tm1); + save |= mod->parse(mod, data, &stats); + time(&tm2); + if (save) epg_updated(); + pthread_mutex_unlock(&global_lock); + htsmsg_destroy(data); + + /* Debug stats */ + tvhlog(LOG_INFO, mod->id, "parse took %d seconds", tm2 - tm1); + tvhlog(LOG_INFO, mod->id, " channels tot=%5d new=%5d mod=%5d", + stats.channels.total, stats.channels.created, + stats.channels.modified); + tvhlog(LOG_INFO, mod->id, " brands tot=%5d new=%5d mod=%5d", + stats.brands.total, stats.brands.created, + stats.brands.modified); + tvhlog(LOG_INFO, mod->id, " seasons tot=%5d new=%5d mod=%5d", + stats.seasons.total, stats.seasons.created, + stats.seasons.modified); + tvhlog(LOG_INFO, mod->id, " episodes tot=%5d new=%5d mod=%5d", + stats.episodes.total, stats.episodes.created, + stats.episodes.modified); + tvhlog(LOG_INFO, mod->id, " broadcasts tot=%5d new=%5d mod=%5d", + stats.broadcasts.total, stats.broadcasts.created, + stats.broadcasts.modified); +} + /* ************************************************************************** - * Channel related routines + * Module channel routines * *************************************************************************/ void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch ) @@ -102,7 +183,7 @@ void epggrab_module_ch_add ( void *m, channel_t *ch ) epggrab_module_int_t *mod = m; RB_FOREACH(egc, mod->channels, link) { if (epggrab_channel_link(egc, ch)) { - epggrab_module_ch_save(mod, egc); + if (mod->ch_save) mod->ch_save(mod, egc); break; } } @@ -115,7 +196,7 @@ void epggrab_module_ch_rem ( void *m, channel_t *ch ) RB_FOREACH(egc, mod->channels, link) { if (egc->channel == ch) { egc->channel = NULL; - epggrab_module_ch_save(mod, egc); + if (mod->ch_save) mod->ch_save(mod, egc); break; } } @@ -126,10 +207,7 @@ void epggrab_module_ch_mod ( void *mod, channel_t *ch ) return epggrab_module_ch_add(mod, ch); } - -#if 0 - -static void epggrab_module_ch_load +static void _epggrab_module_channel_load ( epggrab_module_t *mod, htsmsg_t *m, const char *id ) { int save = 0, i; @@ -138,7 +216,7 @@ static void epggrab_module_ch_load htsmsg_t *a; htsmsg_field_t *f; - epggrab_channel_t *ch = epggrab_module_channel_find(mod, id, 1, &save); + epggrab_channel_t *ch = epggrab_channel_find(mod->channels, id, 1, &save); if ((str = htsmsg_get_str(m, "name"))) ch->name = strdup(str); @@ -147,22 +225,23 @@ static void epggrab_module_ch_load if ((a = htsmsg_get_list(m, "sid"))) { i = 0; HTSMSG_FOREACH(f, a) i++; - ch->sid_cnt = i; - ch->sid = calloc(i, sizeof(uint16_t)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sid[i] = (uint16_t)f->hmf_s64; - i++; + if (i) { + ch->sid = calloc(i+1, sizeof(uint16_t)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sid[i++] = (uint16_t)f->hmf_s64; + } } } if ((a = htsmsg_get_list(m, "sname"))) { i = 0; HTSMSG_FOREACH(f, a) i++; - ch->sname = calloc(i+1, sizeof(char*)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sname[i] = strdup(f->hmf_str); - i++; + if (i) { + ch->sname = calloc(i+1, sizeof(char*)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sname[i++] = strdup(f->hmf_str); + } } } if(!htsmsg_get_u32(m, "number", &u32)) @@ -176,47 +255,16 @@ void epggrab_module_channels_load ( epggrab_module_t *mod ) { htsmsg_t *m, *e; htsmsg_field_t *f; - + if (!mod || !mod->channels) return; if ((m = hts_settings_load("epggrab/%s/channels", mod->id))) { HTSMSG_FOREACH(f, m) { if ((e = htsmsg_get_map_by_field(f))) - epggrab_module_channel_load(mod, e, f->hmf_name); + _epggrab_module_channel_load(mod, e, f->hmf_name); } htsmsg_destroy(m); } } -epggrab_channel_t *epggrab_module_ch_find - ( epggrab_module_t *mod, const char *id, int create, int *save ) -{ - epggrab_channel_t *ec; - static epggrab_channel_t *skel = NULL; - - if (!mod || !mod->channels ) return NULL; - - if ( !skel ) skel = calloc(1, sizeof(epggrab_channel_t)); - skel->id = (char*)id; - skel->mod = mod; - - /* Find */ - if (!create) { - ec = RB_FIND(mod->channels, skel, link, _ch_id_cmp); - - /* Create (if required) */ - } else { - ec = RB_INSERT_SORTED(mod->channels, skel, link, _ch_id_cmp); - if ( ec == NULL ) { - skel->id = strdup(skel->id); - ec = skel; - skel = NULL; - *save = 1; - } - } - - return ec; -} -#endif - /* ************************************************************************** * Internal module routines * *************************************************************************/ @@ -233,7 +281,7 @@ epggrab_module_int_t *epggrab_module_int_create if (!skel) skel = calloc(1, sizeof(epggrab_module_int_t)); /* Pass through */ - epggrab_module_create((epggrab_module_t*)skel, id, name); + epggrab_module_create((epggrab_module_t*)skel, id, name, channels); /* Int data */ skel->type = EPGGRAB_INT; @@ -242,11 +290,6 @@ epggrab_module_int_t *epggrab_module_int_create skel->grab = grab ?: epggrab_module_grab_spawn; skel->trans = trans ?: epggrab_module_trans_xml; skel->parse = parse; - if (channels) { - skel->ch_add = epggrab_module_ch_add; - skel->ch_rem = epggrab_module_ch_rem; - skel->ch_mod = epggrab_module_ch_mod; - } return skel; } @@ -438,7 +481,7 @@ epggrab_module_ota_t *epggrab_module_ota_create if (!skel) skel = calloc(1, sizeof(epggrab_module_ota_t)); /* Pass through */ - epggrab_module_create((epggrab_module_t*)skel, id, name); + epggrab_module_create((epggrab_module_t*)skel, id, name, channels); /* Setup */ skel->type = EPGGRAB_OTA; diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 502048ed..0f291ae0 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -36,6 +36,26 @@ typedef struct eit_status int sec; } eit_status_t; +/* ************************************************************************ + * Diagnostics + * ***********************************************************************/ + +// Dump a descriptor tag for debug (looking for new tags etc...) +static void _eit_dtag_dump ( uint8_t dtag, uint8_t dlen, uint8_t *buf ) +{ + int i = 0, j = 0; + char tmp[100]; + tvhlog(LOG_DEBUG, "eit", "dtag 0x%02X len %d\n", dtag, dlen); + while (i < dlen) + while (dlen--) { + j += sprintf(tmp+j, "%02X ", buf[i]); + i++; + if ((i % 8) == 0 || !dlen) { + tvhlog(LOG_DEBUG, "eit", " %s", tmp); + } + } +} + /* ************************************************************************ * Processing * ***********************************************************************/ @@ -182,9 +202,12 @@ static int _eit_callback if (!svc || !svc->s_enabled || !(ch = svc->s_ch)) return 0; /* Ignore (disabled) */ + // TODO: should this be altered? if (!svc->s_dvb_eit_enable) return 0; /* Register as interesting */ + // TODO: do we want to register for now/next? + // TODO: want should the intervals be? if (tableid < 0x50) epggrab_ota_register(ota, 20, 0); else @@ -320,6 +343,7 @@ static int _eit_callback /* Ignore */ default: + _eit_dtag_dump(dtag, dlen, ptr); break; } diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 71b98222..5874163e 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -56,47 +56,60 @@ typedef struct opentv_event uint8_t type; ///< 0x1=title, 0x2=summary } opentv_event_t; -typedef struct opentv_pid_status +/* PID status (for event PIDs) */ +typedef struct opentv_pid { - LIST_ENTRY(opentv_pid_status) link; - int pid; + LIST_ENTRY(opentv_pid) link; + int pid; enum { OPENTV_PID_INIT, OPENTV_PID_STARTED, OPENTV_PID_COMPLETE - } state; - uint8_t start[20]; -} opentv_pid_status_t; + } state; + uint8_t start[20]; +} opentv_pid_t; +/* Scan status */ typedef struct opentv_status { - int begbat; - int endbat; - LIST_HEAD(, opentv_pid_status) pids; - RB_HEAD(, opentv_event) events; + int begbat; + int endbat; + LIST_HEAD(, opentv_pid) pids; + RB_HEAD(, opentv_event) events; } opentv_status_t; -static opentv_pid_status_t *_opentv_get_pid_status +/* Get a pid entry */ +static opentv_pid_t *_opentv_status_get_pid ( opentv_status_t *sta, int pid ) { - opentv_pid_status_t *p; + opentv_pid_t *p; LIST_FOREACH(p, &sta->pids, link) { if (p->pid == pid) break; } if (!p) { - p = calloc(1, sizeof(opentv_pid_status_t)); + p = calloc(1, sizeof(opentv_pid_t)); p->pid = pid; LIST_INSERT_HEAD(&sta->pids, p, link); } return p; } -/* ************************************************************************ - * Data structures - * ***********************************************************************/ +/* Clear events */ +static void _opentv_status_remove_events ( opentv_status_t *sta ) +{ + opentv_event_t *ev; + while ((ev = RB_FIRST(&sta->events))) { + RB_REMOVE(&sta->events, ev, ev_link); + if (ev->title) free(ev->title); + if (ev->summary) free(ev->summary); + if (ev->desc) free(ev->desc); + free(ev); + } +} -#define OPENTV_SCAN_MAX 600 // 10min max scan period -#define OPENTV_SCAN_PER 3600 // 1hour interval +/* ************************************************************************ + * Module structure + * ***********************************************************************/ /* Huffman dictionary */ typedef struct opentv_dict @@ -138,26 +151,6 @@ static opentv_dict_t *_opentv_dict_find ( const char *id ) return RB_FIND(&_opentv_dicts, &skel, h_link, _dict_cmp); } -/* ************************************************************************ - * Module functions - * ***********************************************************************/ - -#if 0 -static opentv_status_t *_opentv_module_get_status - ( opentv_module_t *mod, int pid ) -{ - opentv_status_t *sta; - LIST_FOREACH(sta, &mod->status, link) - if (sta->pid == pid) break; - if (!sta) { - sta = calloc(1, sizeof(opentv_status_t)); - sta->pid = pid; - LIST_INSERT_HEAD(&mod->status, sta, link); - } - return sta; -} -#endif - /* ************************************************************************ * EPG Object wrappers * ***********************************************************************/ @@ -165,9 +158,9 @@ static opentv_status_t *_opentv_module_get_status static epggrab_channel_t *_opentv_find_epggrab_channel ( opentv_module_t *mod, int cid, int create, int *save ) { -// char chid[32]; -// sprintf(chid, "%s-%d", mod->id, cid); - return NULL;//return epggrab_module_channel_find((epggrab_module_t*)mod, chid, create, save); + char chid[32]; + sprintf(chid, "%s-%d", mod->id, cid); + return epggrab_channel_find(&_opentv_channels, chid, create, save); } static epg_season_t *_opentv_find_season @@ -518,26 +511,22 @@ static epggrab_ota_mux_t *_opentv_table_callback th_dvb_table_t *tdt = (th_dvb_table_t*)p; epggrab_ota_mux_t *ota = tdt->tdt_opaque; opentv_status_t *sta = ota->status; - opentv_pid_status_t *pid; + opentv_pid_t *pid; /* Ignore (not enough data) */ if (len < 20) return NULL; + /* Ignore (don't have BAT) */ + if (!sta->endbat) return NULL; + /* Finished / Blocked */ if (epggrab_ota_is_complete(ota)) return NULL; /* Begin (reset state) */ if (epggrab_ota_begin(ota)) { - opentv_event_t *ev; /* Remove outstanding event data */ - while ((ev = RB_FIRST(&sta->events))) { - RB_REMOVE(&sta->events, ev, ev_link); - if (ev->title) free(ev->title); - if (ev->desc) free(ev->desc); - if (ev->summary) free(ev->summary); - free(ev); - } + _opentv_status_remove_events(sta); /* Reset status */ LIST_FOREACH(pid, &sta->pids, link) @@ -545,7 +534,7 @@ static epggrab_ota_mux_t *_opentv_table_callback } /* Insert/Find */ - pid = _opentv_get_pid_status(sta, tdt->tdt_pid); + pid = _opentv_status_get_pid(sta, tdt->tdt_pid); /* Begin PID */ if (pid->state == OPENTV_PID_INIT) { @@ -614,7 +603,21 @@ static int _opentv_channel_callback static void _opentv_ota_destroy ( epggrab_ota_mux_t *ota ) { - // TODO + opentv_status_t *sta = ota->status; + opentv_pid_t *pid; + + /* Empty the events */ + _opentv_status_remove_events(sta); + + /* Empty pids */ + while ((pid = LIST_FIRST(&sta->pids))) { + LIST_REMOVE(pid, link); + free(pid); + } + + /* Free the rest */ + free(sta); + free(ota); } static void _opentv_start @@ -639,8 +642,8 @@ static void _opentv_start sta = ota->status; sta->begbat = sta->endbat = 0; - /* Register interest (we're always interested in this mux) */ - epggrab_ota_register(ota, OPENTV_SCAN_MAX, OPENTV_SCAN_PER); + /* Register (just in case we missed it on enable somehow) */ + epggrab_ota_register(ota, 600, 3600); // 10min scan every hour /* Install tables */ tvhlog(LOG_INFO, "opentv", "install provider %s tables", mod->id); @@ -652,7 +655,7 @@ static void _opentv_start fp->filter.filter[0] = 0x4a; fp->filter.mask[0] = 0xff; // TODO: what about 0x46 (service description) - tdt_add(tdmi, fp, _opentv_channel_callback, mod, + tdt_add(tdmi, fp, _opentv_channel_callback, ota, m->id, TDT_CRC, *t++, NULL); } @@ -662,7 +665,8 @@ static void _opentv_start fp = dvb_fparams_alloc(); fp->filter.filter[0] = 0xa0; fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_title_callback, mod, + _opentv_status_get_pid(sta, *t); + tdt_add(tdmi, fp, _opentv_title_callback, ota, m->id, TDT_CRC | TDT_TDT, *t++, NULL); } @@ -672,33 +676,28 @@ static void _opentv_start fp = dvb_fparams_alloc(); fp->filter.filter[0] = 0xa8; fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_summary_callback, mod, + _opentv_status_get_pid(sta, *t); + tdt_add(tdmi, fp, _opentv_summary_callback, ota, m->id, TDT_CRC | TDT_TDT, *t++, NULL); } } static int _opentv_enable ( void *m, uint8_t e ) { - //th_dvb_adapter_t *tda; - //th_dvb_mux_instance_t *tdmi; opentv_module_t *mod = (opentv_module_t*)m; if (mod->enabled == e) return 0; mod->enabled = e; - /* TODO - * Find muxes and enable/disable * - TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { - LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { - if (tdmi->tdmi_transport_stream_id != mod->tsid) continue; - if (e) { - epggrab_ota_register(m, tdmi, OPENTV_SCAN_MAX, OPENTV_SCAN_PER); - } else { - epggrab_ota_unregister_one(m, tdmi); - } - } + /* Register interest */ + if (e) { + epggrab_ota_create_and_register_by_id((epggrab_module_ota_t*)mod, + mod->nid, mod->tsid, + 600, 3600); + /* Remove all links */ + } else { + epggrab_ota_destroy_by_module((epggrab_module_ota_t*)mod); } -*/ return 1; } @@ -793,7 +792,7 @@ static int _opentv_prov_load_one ( const char *id, htsmsg_t *m ) epggrab_module_ota_create(calloc(1, sizeof(opentv_module_t)), ibuf, nbuf, _opentv_start, _opentv_enable, - &_opentv_channels); + NULL); /* Add provider details */ mod->dict = dict; diff --git a/src/epggrab/module/pyepg.c b/src/epggrab/module/pyepg.c index 167493be..4dc7268a 100644 --- a/src/epggrab/module/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -435,17 +435,16 @@ static int _pyepg_parse void pyepg_init ( void ) { /* Internal module */ - epggrab_module_int_create(NULL, "pyepg", "PyEPG", "/usr/bin/pyepg", - NULL, _pyepg_parse, NULL, - &_pyepg_channels); + epggrab_module_int_create(NULL, "/usr/bin/pyepg", "PyEPG", "/usr/bin/pyepg", + NULL, _pyepg_parse, NULL, NULL); /* External module */ - epggrab_module_ext_create(NULL, "pyepg.ext", "PyEPG", "pyepg", + epggrab_module_ext_create(NULL, "pyepg", "PyEPG", "pyepg", _pyepg_parse, NULL, &_pyepg_channels); } void pyepg_load ( void ) { - // TODO epggrab_module_channels_load(_pyepg_module); + epggrab_module_channels_load(epggrab_module_find_by_id("pyepg")); } diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 7b4bfa7e..546f367a 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -44,10 +44,9 @@ static epggrab_channel_tree_t _xmltv_channels; static epggrab_channel_t *_xmltv_channel_find ( const char *id, int create, int *save ) { - return NULL;//return epggrab_module_channel_find(_xmltv_module, id, create, save); + return epggrab_channel_find(&_xmltv_channels, id, create, save); } - /* ************************************************************************** * Parsing * *************************************************************************/ @@ -481,8 +480,7 @@ static void _xmltv_load_grabbers ( void ) outbuf[i] = '\0'; sprintf(name, "XMLTV: %s", &outbuf[n]); epggrab_module_int_create(NULL, &outbuf[p], name, &outbuf[p], - NULL, _xmltv_parse, NULL, - &_xmltv_channels); + NULL, _xmltv_parse, NULL, NULL); p = n = i + 1; } else if ( outbuf[i] == '|' ) { outbuf[i] = '\0'; @@ -506,5 +504,5 @@ void xmltv_init ( void ) void xmltv_load ( void ) { - //epggrab_module_channels_load(_xmltv_module); + epggrab_module_channels_load(epggrab_module_find_by_id("xmltv")); } diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 54487424..1166f951 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -17,17 +17,8 @@ */ /* - * TODO: this current implementation is a bit naff, possibly not as - * efficient as it could be (due to use of the a single list). But generally - * the length of the list will be short and it shouldn't significantly - * impact the overall performance - * - * TODO: currently all muxes are treated independently, this might result - * in the same mux being scanned on multiple adapters, which is - * a bit pointless. - * - * I think that at least _mux_next() and _ota_complete() need - * updating to handle this + * TODO: currently I don't try to block multiple scans of the same + * tdmi on different adapters */ #include "tvheadend.h" @@ -37,8 +28,7 @@ #include "epggrab.h" #include "epggrab/private.h" -LIST_HEAD(,epggrab_ota_mux) ota_mux_all; -TAILQ_HEAD(, epggrab_ota_mux) ota_mux_reg; +TAILQ_HEAD(, epggrab_ota_mux) ota_mux_all; /* ************************************************************************** * Global functions (called from DVB code) @@ -47,21 +37,21 @@ TAILQ_HEAD(, epggrab_ota_mux) ota_mux_reg; void epggrab_mux_start ( th_dvb_mux_instance_t *tdmi ) { epggrab_module_t *m; - epggrab_module_ota_t *mod; LIST_FOREACH(m, &epggrab_modules, link) { if (m->type == EPGGRAB_OTA) { - mod = (epggrab_module_ota_t*)m; - mod->start(mod, tdmi); + ((epggrab_module_ota_t*)m)->start((epggrab_module_ota_t*)m, tdmi); } } } void epggrab_mux_stop ( th_dvb_mux_instance_t *tdmi, int timeout ) { + // Note: the slightly akward list iteration here is because + // _ota_cancel/delete can remove the object and free() it epggrab_ota_mux_t *a, *b; - a = LIST_FIRST(&ota_mux_all); + a = TAILQ_FIRST(&tdmi->tdmi_epg_grab); while (a) { - b = LIST_NEXT(a, glob_link); + b = TAILQ_NEXT(a, tdmi_link); if (a->tdmi == tdmi) { if (timeout) epggrab_ota_timeout(a); @@ -74,21 +64,15 @@ void epggrab_mux_stop ( th_dvb_mux_instance_t *tdmi, int timeout ) void epggrab_mux_delete ( th_dvb_mux_instance_t *tdmi ) { - epggrab_ota_mux_t *a, *b; - a = LIST_FIRST(&ota_mux_all); - while (a) { - b = LIST_NEXT(a, glob_link); - if (a->tdmi == tdmi) - epggrab_ota_destroy(a); - a = b; - } + epggrab_ota_destroy_by_tdmi(tdmi); } int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) { int period = 0; epggrab_ota_mux_t *ota; - TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { + if (!ota->is_reg) break; if (ota->timeout > period) period = ota->timeout; } @@ -98,11 +82,11 @@ int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) { epggrab_ota_mux_t *ota; - TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + TAILQ_FOREACH(ota, &ota_mux_all, glob_link) { + if (!ota->is_reg) break; if (ota->tdmi->tdmi_adapter == tda) break; } - if (!ota) return NULL; - return ota->tdmi; + return ota ? ota->tdmi : NULL; } /* ************************************************************************** @@ -116,10 +100,17 @@ th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) */ static int _ota_time_cmp ( void *_a, void *_b ) { + int r; time_t now, wa, wb; time(&now); epggrab_ota_mux_t *a = _a; epggrab_ota_mux_t *b = _b; + + /* Unreg'd always at the end */ + r = a->is_reg - b->is_reg; + if (r) return r; + + /* Check when */ wa = a->completed + a->interval; wb = b->completed + b->interval; if (wa < now && wb < now) @@ -136,7 +127,7 @@ epggrab_ota_mux_t *epggrab_ota_create { /* Search for existing */ epggrab_ota_mux_t *ota; - LIST_FOREACH(ota, &ota_mux_all, glob_link) { + TAILQ_FOREACH(ota, &ota_mux_all, glob_link) { if (ota->grab == mod && ota->tdmi == tdmi) break; } @@ -145,7 +136,9 @@ epggrab_ota_mux_t *epggrab_ota_create ota = calloc(1, sizeof(epggrab_ota_mux_t)); ota->grab = mod; ota->tdmi = tdmi; - LIST_INSERT_HEAD(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_TAIL(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_TAIL(&tdmi->tdmi_epg_grab, ota, tdmi_link); + TAILQ_INSERT_TAIL(&mod->muxes, ota, grab_link); } else { time_t now; @@ -158,13 +151,33 @@ epggrab_ota_mux_t *epggrab_ota_create return ota; } +/* + * Create and register using mux ID + */ +void epggrab_ota_create_and_register_by_id + ( epggrab_module_ota_t *mod, int nid, int tsid, int period, int interval ) +{ + th_dvb_adapter_t *tda; + th_dvb_mux_instance_t *tdmi; + epggrab_ota_mux_t *ota; + TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { + //TODO: if (tda->nitoid != nid) continue; + LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { + if (tdmi->tdmi_transport_stream_id != tsid) continue; + ota = epggrab_ota_create(mod, tdmi); + epggrab_ota_register(ota, period, interval); + } + } +} + /* * Destrory link (either because it was temporary OR mux deleted) */ void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ) { - LIST_REMOVE(ota, glob_link); - if (ota->is_reg) TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_REMOVE(&ota->tdmi->tdmi_epg_grab, ota, tdmi_link); + TAILQ_REMOVE(&ota->grab->muxes, ota, grab_link); if (ota->destroy) ota->destroy(ota); else { if (ota->status) free(ota->status); @@ -172,18 +185,46 @@ void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ) } } +/* + * Destroy by tdmi + */ +void epggrab_ota_destroy_by_tdmi ( th_dvb_mux_instance_t *tdmi ) +{ + epggrab_ota_mux_t *ota; + while ((ota = TAILQ_FIRST(&tdmi->tdmi_epg_grab))) + epggrab_ota_destroy(ota); +} + +/* + * Destroy by module + */ +void epggrab_ota_destroy_by_module ( epggrab_module_ota_t *mod ) +{ + epggrab_ota_mux_t *ota; + while ((ota = TAILQ_FIRST(&mod->muxes))) + epggrab_ota_destroy(ota); +} + /* * Register interest (called when useful data exists on the MUX * thus inserting it into the EPG scanning queue */ void epggrab_ota_register ( epggrab_ota_mux_t *ota, int timeout, int interval ) { - // TODO: handle changes to the interval/timeout? - if (!ota->is_reg) { - ota->timeout = timeout; + int up = 0; + ota->is_reg = 1; + if (timeout > ota->timeout) { + up = 1; + ota->timeout = timeout; + } + if (interval > ota->interval) { + up = 1; ota->interval = interval; - ota->is_reg = 1; - TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + } + + if (up) { + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_SORTED(&ota_mux_all, ota, glob_link, _ota_time_cmp); } } @@ -199,8 +240,8 @@ static void _epggrab_ota_finished ( epggrab_ota_mux_t *ota ) /* Reinsert into reg queue */ else { - TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); - TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_SORTED(&ota_mux_all, ota, glob_link, _ota_time_cmp); } } @@ -216,12 +257,23 @@ int epggrab_ota_begin ( epggrab_ota_mux_t *ota ) void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) { + th_dvb_mux_instance_t *tdmi = ota->tdmi; + if (ota->state != EPGGRAB_OTA_MUX_COMPLETE) { ota->state = EPGGRAB_OTA_MUX_COMPLETE; time(&ota->completed); _epggrab_ota_finished(ota); - // TODO: need to inform tdmi + /* Check others */ + TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { + if (ota->is_reg && ota->state != EPGGRAB_OTA_MUX_RUNNING) break; + } + + /* All complete (bring timer forward) */ + if (!ota) { + gtimer_arm(&tdmi->tdmi_adapter->tda_mux_scanner_timer, + dvb_adapter_mux_scanner, tdmi->tdmi_adapter, 20); + } } } diff --git a/src/epggrab/private.h b/src/epggrab/private.h index bbf10f36..ed1942d9 100644 --- a/src/epggrab/private.h +++ b/src/epggrab/private.h @@ -25,7 +25,7 @@ epggrab_module_t *epggrab_module_create ( epggrab_module_t *skel, - const char *id, const char *name ); + const char *id, const char *name, epggrab_channel_tree_t *channels ); char *epggrab_module_grab_spawn ( void *m ); htsmsg_t *epggrab_module_trans_xml ( void *m, char *data ); @@ -39,6 +39,8 @@ int epggrab_module_enable_socket ( void *m, uint8_t e ); void epggrab_module_parse ( void *m, htsmsg_t *data ); +void epggrab_module_channels_load ( epggrab_module_t *m ); + /* ************************************************************************** * Channel processing * *************************************************************************/ @@ -94,9 +96,17 @@ epggrab_module_ota_t *epggrab_module_ota_create * blocked (i.e. has completed within interval period) */ epggrab_ota_mux_t *epggrab_ota_create - ( struct epggrab_module_ota *mod, struct th_dvb_mux_instance *tdmi ); + ( epggrab_module_ota_t *mod, struct th_dvb_mux_instance *tdmi ); +void epggrab_ota_create_and_register_by_id + ( epggrab_module_ota_t *mod, int nid, int tsid, + int period, int interval ); -void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ); +/* + * Delete + */ +void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ); +void epggrab_ota_destroy_by_module ( epggrab_module_ota_t *mod ); +void epggrab_ota_destroy_by_tdmi ( struct th_dvb_mux_instance *tdmi ); /* * Register interest