* Add support for prioritized recordings. The user can chose among five

different priorities.
This commit is contained in:
Andreas Öman 2010-03-17 21:16:57 +00:00
parent a241570132
commit 769dee0f3b
10 changed files with 156 additions and 13 deletions

3
debian/changelog vendored
View file

@ -33,6 +33,9 @@ hts-tvheadend (2.11-WIP) hts; urgency=low
CWC entries were not correctly updated when a connection was established
or lost. This is now fixed. Ticket #144
* Add support for prioritized recordings. The user can chose among five
different priorities.
hts-tvheadend (2.10) hts; urgency=high
* Fix a crash in HTSP server.

View file

@ -44,6 +44,15 @@ extern struct dvr_entry_list dvrentries;
#define DVR_DIR_PER_TITLE 0x40
#define DVR_EPISODE_IN_TITLE 0x80
typedef enum {
DVR_PRIO_IMPORTANT,
DVR_PRIO_HIGH,
DVR_PRIO_NORMAL,
DVR_PRIO_LOW,
DVR_PRIO_UNIMPORTANT,
} dvr_prio_t;
LIST_HEAD(dvr_rec_stream_list, dvr_rec_stream);
@ -93,6 +102,8 @@ typedef struct dvr_entry {
date and time pre/post/fixed */
char *de_desc; /* Description in UTF-8 (from EPG) */
dvr_prio_t de_pri;
epg_episode_t de_episode;
char *de_error;
@ -165,6 +176,8 @@ typedef struct dvr_autorec_entry {
channel_tag_t *dae_channel_tag;
LIST_ENTRY(dvr_autorec_entry) dae_channel_tag_link;
dvr_prio_t dae_pri;
struct dvr_entry_list dae_spawns;
} dvr_autorec_entry_t;
@ -181,7 +194,7 @@ dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator,
dvr_entry_t *dvr_entry_create(channel_t *ch, time_t start, time_t stop,
const char *title, const char *description,
const char *creator, dvr_autorec_entry_t *dae,
epg_episode_t *ee);
epg_episode_t *ee, dvr_prio_t pri);
void dvr_init(void);
@ -241,4 +254,11 @@ void autorec_destroy_by_channel(channel_t *ch);
dvr_autorec_entry_t *autorec_entry_find(const char *id, int create);
/**
*
*/
dvr_prio_t dvr_pri2val(const char *s);
const char *dvr_val2pri(dvr_prio_t v);
#endif /* DVR_H */

View file

@ -137,6 +137,7 @@ autorec_entry_find(const char *id, int create)
tally = MAX(atoi(id), tally);
}
dae->dae_weekdays = 0x7f;
dae->dae_pri = DVR_PRIO_NORMAL;
dae->dae_id = strdup(id);
TAILQ_INSERT_TAIL(&autorec_entries, dae, dae_link);
@ -235,6 +236,8 @@ autorec_record_build(dvr_autorec_entry_t *dae)
build_weekday_tags(str, sizeof(str), dae->dae_weekdays);
htsmsg_add_str(e, "weekdays", str);
htsmsg_add_str(e, "pri", dvr_val2pri(dae->dae_pri));
return e;
}
@ -340,6 +343,9 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
if(!htsmsg_get_u32(values, "enabled", &u32))
dae->dae_enabled = u32;
if((s = htsmsg_get_str(values, "pri")) != NULL)
dae->dae_pri = dvr_pri2val(s);
dvr_autorec_changed(dae);
return autorec_record_build(dae);

View file

@ -49,7 +49,6 @@ static void dvr_timer_expire(void *aux);
static void dvr_timer_start_recording(void *aux);
/**
*
*/
@ -149,7 +148,7 @@ dvr_entry_t *
dvr_entry_create(channel_t *ch, time_t start, time_t stop,
const char *title, const char *description,
const char *creator, dvr_autorec_entry_t *dae,
epg_episode_t *ee)
epg_episode_t *ee, dvr_prio_t pri)
{
dvr_entry_t *de;
char tbuf[30];
@ -168,6 +167,7 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop,
de->de_start = start;
de->de_stop = stop;
de->de_pri = pri;
if (ch->ch_dvr_extra_time_pre)
de->de_start_extra = ch->ch_dvr_extra_time_pre;
else
@ -219,7 +219,8 @@ dvr_entry_create_by_event(event_t *e, const char *creator,
return NULL;
return dvr_entry_create(e->e_channel, e->e_start, e->e_stop,
e->e_title, e->e_desc, creator, dae, &e->e_episode);
e->e_title, e->e_desc, creator, dae, &e->e_episode,
dae->dae_pri);
}
@ -326,8 +327,7 @@ dvr_db_load_one(htsmsg_t *c, int id)
de->de_stop = stop;
de->de_creator = strdup(creator);
de->de_title = strdup(title);
de->de_pri = dvr_pri2val(htsmsg_get_str(c, "pri"));
if(htsmsg_get_s32(c, "start_extra", &d))
de->de_start_extra = dvr_extra_time_pre;
@ -339,6 +339,7 @@ dvr_db_load_one(htsmsg_t *c, int id)
else
de->de_stop_extra = d;
tvh_str_set(&de->de_desc, htsmsg_get_str(c, "description"));
tvh_str_set(&de->de_filename, htsmsg_get_str(c, "filename"));
tvh_str_set(&de->de_error, htsmsg_get_str(c, "error"));
@ -416,6 +417,7 @@ dvr_entry_save(dvr_entry_t *de)
if(de->de_desc != NULL)
htsmsg_add_str(m, "description", de->de_desc);
htsmsg_add_str(m, "pri", dvr_val2pri(de->de_pri));
if(de->de_error != NULL)
htsmsg_add_str(m, "error", de->de_error);
@ -875,3 +877,28 @@ dvr_get_filesize(dvr_entry_t *de)
return st.st_size;
}
/**
*
*/
static struct strtab priotab[] = {
{ "important", DVR_PRIO_IMPORTANT },
{ "high", DVR_PRIO_HIGH },
{ "normal", DVR_PRIO_NORMAL },
{ "low", DVR_PRIO_LOW },
{ "unimportant", DVR_PRIO_UNIMPORTANT },
};
dvr_prio_t
dvr_pri2val(const char *s)
{
return str2val_def(s, priotab, DVR_PRIO_NORMAL);
}
const char *
dvr_val2pri(dvr_prio_t v)
{
return val2str(v, priotab) ?: "invalid";
}

View file

@ -52,6 +52,15 @@ static void dvr_thread_new_pkt(dvr_entry_t *de, th_pkt_t *pkt);
static void dvr_spawn_postproc(dvr_entry_t *de);
static void dvr_thread_epilog(dvr_entry_t *de);
const static int prio2weight[5] = {
[DVR_PRIO_IMPORTANT] = 500,
[DVR_PRIO_HIGH] = 400,
[DVR_PRIO_NORMAL] = 300,
[DVR_PRIO_LOW] = 200,
[DVR_PRIO_UNIMPORTANT] = 100,
};
/**
*
*/
@ -59,6 +68,7 @@ void
dvr_rec_subscribe(dvr_entry_t *de)
{
char buf[100];
int weight;
assert(de->de_s == NULL);
@ -68,8 +78,13 @@ dvr_rec_subscribe(dvr_entry_t *de)
pthread_create(&de->de_thread, NULL, dvr_thread, de);
de->de_s = subscription_create_from_channel(de->de_channel, 1000, buf,
&de->de_sq.sq_st, 0);
if(de->de_pri)
weight = prio2weight[de->de_pri];
else
weight = 300;
de->de_s = subscription_create_from_channel(de->de_channel, weight,
buf, &de->de_sq.sq_st, 0);
}
/**

View file

@ -42,6 +42,26 @@ str2val0(const char *str, struct strtab tab[], int l)
#define str2val(str, tab) str2val0(str, tab, sizeof(tab) / sizeof(tab[0]))
static int str2val0_def(const char *str, struct strtab tab[], int l, int def)
__attribute((unused));
static int
str2val0_def(const char *str, struct strtab tab[], int l, int def)
{
int i;
if(str)
for(i = 0; i < l; i++)
if(!strcasecmp(str, tab[i].str))
return tab[i].val;
return def;
}
#define str2val_def(str, tab, def) \
str2val0_def(str, tab, sizeof(tab) / sizeof(tab[0]), def)
static const char * val2str0(int val, struct strtab tab[], int l)
__attribute__((unused));

View file

@ -766,7 +766,7 @@ htsp_method_subscribe(htsp_connection_t *htsp, htsmsg_t *in)
LIST_INSERT_HEAD(&htsp->htsp_subscriptions, hs, hs_link);
streaming_target_init(&hs->hs_input, htsp_streaming_input, hs, 0);
hs->hs_s = subscription_create_from_channel(ch, 500, htsp->htsp_logname,
hs->hs_s = subscription_create_from_channel(ch, 150, htsp->htsp_logname,
&hs->hs_input, 0);
return NULL;
}

View file

@ -490,7 +490,7 @@ rtsp_subscribe(http_connection_t *hc, rtsp_t *rtsp,
char *components[5];
int nc;
char *url = hc->hc_url;
int pri = 500;
int pri = 150;
int subflags = 0;
th_subscription_t *s;
char urlprefix[128];

View file

@ -751,6 +751,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
const char *startstr = http_arg_get(&hc->hc_req_args, "starttime");
const char *stopstr = http_arg_get(&hc->hc_req_args, "stoptime");
const char *channel = http_arg_get(&hc->hc_req_args, "channelid");
const char *pri = http_arg_get(&hc->hc_req_args, "pri");
channel_t *ch = channel ? channel_find_by_identifier(atoi(channel)) : NULL;
@ -781,7 +782,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
stop += 86400;
dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative,
NULL, NULL);
NULL, NULL, dvr_pri2val(pri));
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
@ -941,6 +942,8 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(m, "creator", de->de_creator);
htsmsg_add_str(m, "pri", dvr_val2pri(de->de_pri));
switch(de->de_sched_state) {
case DVR_SCHEDULED:
s = "Scheduled for recording";

View file

@ -13,6 +13,20 @@ tvheadend.weekdays = new Ext.data.SimpleStore({
]
});
// This should be loaded from tvheadend
tvheadend.dvrprio = new Ext.data.SimpleStore({
fields: ['identifier', 'name'],
id: 0,
data: [
['important', 'Important'],
['high', 'High'],
['normal', 'Normal'],
['low', 'Low'],
['unimportant', 'Unimportant'],
]
});
/**
*
*/
@ -110,6 +124,10 @@ tvheadend.dvrschedule = function() {
}
}
function renderPri(value) {
return tvheadend.dvrprio.getById(value).data.name;
}
var dvrCm = new Ext.grid.ColumnModel([
{
width: 250,
@ -117,10 +135,16 @@ tvheadend.dvrschedule = function() {
header: "Title",
dataIndex: 'title'
},{
width: 250,
width: 100,
id:'episode',
header: "Episode",
dataIndex: 'episode'
},{
width: 100,
id:'pri',
header: "Priority",
dataIndex: 'pri',
renderer: renderPri
},{
width: 100,
id:'start',
@ -215,6 +239,16 @@ tvheadend.dvrschedule = function() {
increment: 10,
format: 'H:i'
}),
new Ext.form.ComboBox({
store: tvheadend.dvrprio,
value: "normal",
triggerAction: 'all',
mode: 'local',
fieldLabel: 'Priority',
valueField: 'identifier',
displayField: 'name',
name: 'pri'
}),
{
allowBlank: false,
fieldLabel: 'Title',
@ -363,6 +397,20 @@ tvheadend.autoreceditor = function() {
valueField: 'identifier',
displayField: 'name'
})
}, {
header: "Priority",
dataIndex: 'pri',
width: 100,
renderer: function(value, metadata, record, row, col, store) {
return tvheadend.dvrprio.getById(value).data.name;
},
editor: new fm.ComboBox({
store: tvheadend.dvrprio,
triggerAction: 'all',
mode: 'local',
valueField: 'identifier',
displayField: 'name'
})
},{
header: "Created by",
dataIndex: 'creator',
@ -394,6 +442,7 @@ tvheadend.dvr = function() {
{name: 'channel'},
{name: 'title'},
{name: 'episode'},
{name: 'pri'},
{name: 'description'},
{name: 'chicon'},
{name: 'start', type: 'date', dateFormat: 'U' /* unix time */},
@ -419,7 +468,7 @@ tvheadend.dvr = function() {
tvheadend.autorecRecord = Ext.data.Record.create([
'enabled','title','channel','tag','creator','contentgrp','comment',
'weekdays'
'weekdays', 'pri'
]);