* 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.
This commit is contained in:
Andreas Öman 2010-03-16 19:54:45 +00:00
parent 727b590771
commit 85fc302882
8 changed files with 138 additions and 78 deletions

7
debian/changelog vendored
View file

@ -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.

View file

@ -20,6 +20,7 @@
#define DVR_H
#include <libavformat/avformat.h>
#include <regex.h>
#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 */

View file

@ -25,8 +25,6 @@
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <regex.h>
#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);
}
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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);
}