From 85fc302882093fb4f5c1c37e58c0bc2adf0842a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Tue, 16 Mar 2010 19:54:45 +0000 Subject: [PATCH] * Inject entries in DVR schedule as soon as we know about an EPG entry that matches an autorecording rule. Previously Tvheadend would scan the EPG continously and just grab shows as they neared air time. The drawbacks of this approach was that it's a bit hard to understand what is happening. It also makes (more) correct wakeup from suspend hard to do. --- debian/changelog | 7 +++ src/dvr/dvr.h | 48 +++++++++++++++++++-- src/dvr/dvr_autorec.c | 99 +++++++++++++++++-------------------------- src/dvr/dvr_db.c | 45 +++++++++++++++++--- src/epg.c | 6 +-- src/htsp.c | 5 ++- src/webui/extjs.c | 4 +- src/webui/simpleui.c | 2 +- 8 files changed, 138 insertions(+), 78 deletions(-) diff --git a/debian/changelog b/debian/changelog index d74ef384..ce862f83 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,13 @@ hts-tvheadend (2.11-WIP) hts; urgency=low written to disk as Tvheadend tunes to it. This should aid a lot when it comes to debugging + * Inject entries in DVR schedule as soon as we know about an EPG + entry that matches an autorecording rule. Previously Tvheadend + would scan the EPG continously and just grab shows as they neared + air time. The drawbacks of this approach was that it's a bit hard + to understand what is happening. It also makes (more) correct + wakeup from suspend hard to do. + hts-tvheadend (2.10) hts; urgency=high * Fix a crash in HTSP server. diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 6bb0e254..f3699a0c 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -20,6 +20,7 @@ #define DVR_H #include +#include #include "epg.h" #include "channels.h" #include "subscriptions.h" @@ -96,6 +97,12 @@ typedef struct dvr_entry { uint32_t de_dont_reschedule; + /** + * Autorec linkage + */ + LIST_ENTRY(dvr_entry) de_autorec_link; + struct dvr_autorec_entry *de_autorec; + /** * Fields for recording */ @@ -129,14 +136,47 @@ typedef struct dvr_entry { } dvr_entry_t; + +/** + * Autorec entry + */ +typedef struct dvr_autorec_entry { + TAILQ_ENTRY(dvr_autorec_entry) dae_link; + char *dae_id; + + int dae_enabled; + char *dae_creator; + char *dae_comment; + + char *dae_title; + regex_t dae_title_preg; + + epg_content_group_t *dae_ecg; + + int dae_weekdays; + + channel_t *dae_channel; + LIST_ENTRY(dvr_autorec_entry) dae_channel_link; + + channel_tag_t *dae_channel_tag; + LIST_ENTRY(dvr_autorec_entry) dae_channel_tag_link; + + struct dvr_entry_list dae_spawns; + +} dvr_autorec_entry_t; + + /** * Prototypes */ -dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator); +void dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae); + +dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator, + dvr_autorec_entry_t *dae); dvr_entry_t *dvr_entry_create(channel_t *ch, time_t start, time_t stop, const char *title, const char *description, - const char *creator); + const char *creator, dvr_autorec_entry_t *dae); void dvr_init(void); @@ -190,8 +230,10 @@ void dvr_autorec_add(const char *title, const char *channel, const char *tag, const char *contentgrp, const char *creator, const char *comment); -void dvr_autorec_check(event_t *e); +void dvr_autorec_check_event(event_t *e); void autorec_destroy_by_channel(channel_t *ch); +dvr_autorec_entry_t *autorec_entry_find(const char *id, int create); + #endif /* DVR_H */ diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 9a0baaec..1bf417bf 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -25,8 +25,6 @@ #include #include #include -#include - #include "tvhead.h" #include "settings.h" @@ -41,31 +39,22 @@ TAILQ_HEAD(dvr_autorec_entry_queue, dvr_autorec_entry); struct dvr_autorec_entry_queue autorec_entries; -typedef struct dvr_autorec_entry { - TAILQ_ENTRY(dvr_autorec_entry) dae_link; - char *dae_id; +static void dvr_autorec_changed(dvr_autorec_entry_t *dae); - int dae_enabled; - char *dae_creator; - char *dae_comment; - - char *dae_title; - regex_t dae_title_preg; - - epg_content_group_t *dae_ecg; - - int dae_weekdays; - - channel_t *dae_channel; - LIST_ENTRY(dvr_autorec_entry) dae_channel_link; - - channel_tag_t *dae_channel_tag; - LIST_ENTRY(dvr_autorec_entry) dae_channel_tag_link; - -} dvr_autorec_entry_t; - -static void dvr_autorec_check_just_enabled(dvr_autorec_entry_t *dae); +/** + * + */ +static void +dvr_autorec_purge_spawns(dvr_autorec_entry_t *dae) +{ + dvr_entry_t *de; + while((de = LIST_FIRST(&dae->dae_spawns)) != NULL) { + LIST_REMOVE(de, de_autorec_link); + de->de_autorec = NULL; + dvr_entry_cancel(de); + } +} /** @@ -98,9 +87,11 @@ autorec_cmp(dvr_autorec_entry_t *dae, event_t *e) return 0; } - if(dae->dae_title != NULL && e->e_title != NULL && - regexec(&dae->dae_title_preg, e->e_title, 0, NULL, 0)) + if(dae->dae_title != NULL) { + if(e->e_title == NULL || + regexec(&dae->dae_title_preg, e->e_title, 0, NULL, 0)) return 0; + } if(dae->dae_weekdays != 0x7f) { struct tm tm; @@ -115,7 +106,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, event_t *e) /** * */ -static dvr_autorec_entry_t * +dvr_autorec_entry_t * autorec_entry_find(const char *id, int create) { dvr_autorec_entry_t *dae; @@ -154,6 +145,8 @@ autorec_entry_find(const char *id, int create) static void autorec_entry_destroy(dvr_autorec_entry_t *dae) { + dvr_autorec_purge_spawns(dae); + free(dae->dae_id); free(dae->dae_creator); @@ -293,8 +286,11 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values, if((dae = autorec_entry_find(id, maycreate)) == NULL) return NULL; - tvh_str_set(&dae->dae_creator, htsmsg_get_str(values, "creator")); - tvh_str_set(&dae->dae_comment, htsmsg_get_str(values, "comment")); + printf("autorec_record_update\n"); + htsmsg_print(values); + + tvh_str_update(&dae->dae_creator, htsmsg_get_str(values, "creator")); + tvh_str_update(&dae->dae_comment, htsmsg_get_str(values, "comment")); if((s = htsmsg_get_str(values, "channel")) != NULL) { if(dae->dae_channel != NULL) { @@ -340,8 +336,7 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values, if(!htsmsg_get_u32(values, "enabled", &u32)) dae->dae_enabled = u32; - if(dae->dae_enabled) - dvr_autorec_check_just_enabled(dae); + dvr_autorec_changed(dae); return autorec_record_build(dae); } @@ -435,19 +430,7 @@ dvr_autorec_add(const char *title, const char *channel, htsmsg_add_u32(m, "asyncreload", 1); notify_by_msg("autorec", m); - dvr_autorec_check_just_enabled(dae); -} - -/** - * - */ -static void -autorec_schedule(event_t *e, dvr_autorec_entry_t *dae) -{ - char buf[200]; - - snprintf(buf, sizeof(buf), "Auto recording by: %s", dae->dae_creator); - dvr_entry_create_by_event(e, buf); + dvr_autorec_changed(dae); } @@ -455,37 +438,31 @@ autorec_schedule(event_t *e, dvr_autorec_entry_t *dae) * */ void -dvr_autorec_check(event_t *e) +dvr_autorec_check_event(event_t *e) { dvr_autorec_entry_t *dae; TAILQ_FOREACH(dae, &autorec_entries, dae_link) if(autorec_cmp(dae, e)) - autorec_schedule(e, dae); - - if((e = RB_NEXT(e, e_channel_link)) == NULL) - return; - - /* Check next event too */ - TAILQ_FOREACH(dae, &autorec_entries, dae_link) - if(autorec_cmp(dae, e)) - autorec_schedule(e, dae); + dvr_entry_create_by_autorec(e, dae); } /** * */ static void -dvr_autorec_check_just_enabled(dvr_autorec_entry_t *dae) +dvr_autorec_changed(dvr_autorec_entry_t *dae) { channel_t *ch; + event_t *e; + + dvr_autorec_purge_spawns(dae); RB_FOREACH(ch, &channel_name_tree, ch_name_link) { - if(ch->ch_epg_current == NULL) - continue; - - if(autorec_cmp(dae, ch->ch_epg_current)) - autorec_schedule(ch->ch_epg_current, dae); + RB_FOREACH(e, &ch->ch_epg_events, e_channel_link) { + if(autorec_cmp(dae, e)) + dvr_entry_create_by_autorec(e, dae); + } } } diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index be73ada5..850bee6f 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -137,7 +137,7 @@ dvr_entry_link(dvr_entry_t *de) dvr_entry_t * dvr_entry_create(channel_t *ch, time_t start, time_t stop, const char *title, const char *description, - const char *creator) + const char *creator, dvr_autorec_entry_t *dae) { dvr_entry_t *de; char tbuf[30]; @@ -174,6 +174,9 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop, localtime_r(&t, &tm); strftime(tbuf, sizeof(tbuf), "%c", &tm); + de->de_autorec = dae; + LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link); + tvhlog(LOG_INFO, "dvr", "\"%s\" on \"%s\" starting at %s, " "scheduled for recording by \"%s\"", de->de_title, de->de_channel->ch_name, tbuf, creator); @@ -188,13 +191,27 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop, * */ dvr_entry_t * -dvr_entry_create_by_event(event_t *e, const char *creator) +dvr_entry_create_by_event(event_t *e, const char *creator, + dvr_autorec_entry_t *dae) { if(e->e_channel == NULL || e->e_title == NULL) return NULL; return dvr_entry_create(e->e_channel, e->e_start, e->e_stop, - e->e_title, e->e_desc, creator); + e->e_title, e->e_desc, creator, dae); +} + + +/** + * + */ +void +dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae) +{ + char buf[200]; + + snprintf(buf, sizeof(buf), "Auto recording by: %s", dae->dae_creator); + dvr_entry_create_by_event(e, buf, dae); } @@ -211,6 +228,9 @@ dvr_entry_dec_ref(dvr_entry_t *de) return; } + if(de->de_autorec != NULL) + LIST_REMOVE(de, de_autorec_link); + free(de->de_creator); free(de->de_title); free(de->de_ititle); @@ -301,6 +321,17 @@ dvr_db_load_one(htsmsg_t *c, int id) tvh_str_set(&de->de_error, htsmsg_get_str(c, "error")); htsmsg_get_u32(c, "noresched", &de->de_dont_reschedule); + + s = htsmsg_get_str(c, "autorec"); + if(s != NULL) { + dvr_autorec_entry_t *dae = autorec_entry_find(s, 0); + + if(dae != NULL) { + de->de_autorec = dae; + LIST_INSERT_HEAD(&dae->dae_spawns, de, de_autorec_link); + } + } + dvr_entry_link(de); } @@ -359,6 +390,9 @@ dvr_entry_save(dvr_entry_t *de) htsmsg_add_u32(m, "noresched", de->de_dont_reschedule); + if(de->de_autorec != NULL) + htsmsg_add_str(m, "autorec", de->de_autorec->dae_id); + hts_settings_save(m, "dvr/log/%d", de->de_id); htsmsg_destroy(m); } @@ -589,10 +623,9 @@ dvr_init(void) dvr_storage); } - dvr_db_load(); - dvr_autorec_init(); + dvr_db_load(); } /** @@ -611,7 +644,7 @@ dvr_save(void) htsmsg_add_u32(m, "channel-in-title", !!(dvr_flags & DVR_CHANNEL_IN_TITLE)); htsmsg_add_u32(m, "date-in-title", !!(dvr_flags & DVR_DATE_IN_TITLE)); htsmsg_add_u32(m, "time-in-title", !!(dvr_flags & DVR_TIME_IN_TITLE)); - htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE)); + htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE)); if(dvr_postproc != NULL) htsmsg_add_str(m, "postproc", dvr_postproc); diff --git a/src/epg.c b/src/epg.c index 2598c8c9..2ecd38d7 100644 --- a/src/epg.c +++ b/src/epg.c @@ -57,11 +57,9 @@ epg_set_current(channel_t *ch, event_t *e) return; ch->ch_epg_current = e; - if(e != NULL) { + if(e != NULL) gtimer_arm_abs(&ch->ch_epg_timer_current, epg_ch_check_current_event, ch, MAX(e->e_stop, dispatch_clock + 1)); - dvr_autorec_check(e); - } htsp_event_update(ch, e); } @@ -113,7 +111,7 @@ epg_ch_check_current_event(void *aux) static void epg_event_changed(event_t *e) { - /* nothing atm */ + dvr_autorec_check_event(e); } diff --git a/src/htsp.c b/src/htsp.c index 03f3ef41..0f55a541 100644 --- a/src/htsp.c +++ b/src/htsp.c @@ -497,7 +497,10 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in) return htsp_error("Event does not exist"); //create the dvr entry - de = dvr_entry_create_by_event(e, (htsp->htsp_username) ? htsp->htsp_username:"anonymous"); + de = dvr_entry_create_by_event(e, + htsp->htsp_username ? + htsp->htsp_username : "anonymous", + NULL); dvr_status = de != NULL ? de->de_sched_state : DVR_NOSTATE; diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 20614e9a..a734122b 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -724,7 +724,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) return HTTP_STATUS_BAD_REQUEST; } - dvr_entry_create_by_event(e, hc->hc_representative); + dvr_entry_create_by_event(e, hc->hc_representative, NULL); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); @@ -777,7 +777,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) if(stop < start) stop += 86400; - dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative); + dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative, NULL); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); diff --git a/src/webui/simpleui.c b/src/webui/simpleui.c index ce45a624..4aeab012 100644 --- a/src/webui/simpleui.c +++ b/src/webui/simpleui.c @@ -209,7 +209,7 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque) de = dvr_entry_find_by_event(e); if((http_arg_get(&hc->hc_req_args, "rec")) != NULL) { - de = dvr_entry_create_by_event(e, hc->hc_username ?: "anonymous"); + de = dvr_entry_create_by_event(e, hc->hc_username ?: "anonymous", NULL); } else if(de != NULL && (http_arg_get(&hc->hc_req_args, "cancel")) != NULL) { de = dvr_entry_cancel(de); }