uint32_t dvr_extra_time_pre;
uint32_t dvr_extra_time_post;
uint32_t dvr_update_window;
+ int dvr_running;
muxer_config_t dvr_muxcnf;
DVR_RS_RUNNING,
DVR_RS_COMMERCIAL,
DVR_RS_ERROR,
+ DVR_RS_EPG_WAIT,
} dvr_rs_state_t;
time_t de_start_extra;
time_t de_stop_extra;
+ time_t de_running_start;
+ time_t de_running_stop;
+
char *de_owner;
char *de_creator;
char *de_comment;
uint32_t dvr_entry_get_rerecord_errors( dvr_entry_t *de );
-int dvr_entry_get_start_time( dvr_entry_t *de );
+time_t dvr_entry_get_start_time( dvr_entry_t *de );
-int dvr_entry_get_stop_time( dvr_entry_t *de );
+time_t dvr_entry_get_stop_time( dvr_entry_t *de );
-int dvr_entry_get_extra_time_post( dvr_entry_t *de );
+time_t dvr_entry_get_extra_time_post( dvr_entry_t *de );
-int dvr_entry_get_extra_time_pre( dvr_entry_t *de );
+time_t dvr_entry_get_extra_time_pre( dvr_entry_t *de );
void dvr_entry_init(void);
void dvr_event_updated(epg_broadcast_t *e);
+void dvr_event_running(epg_broadcast_t *e, epg_source_t esrc, int running);
+
dvr_entry_t *dvr_entry_find_by_id(int id);
static inline dvr_entry_t *dvr_entry_find_by_uuid(const char *uuid)
cfg->dvr_skip_commercials = 1;
dvr_charset_update(cfg, intlconv_filesystem_charset());
cfg->dvr_update_window = 24 * 3600;
+ cfg->dvr_running = 1;
cfg->dvr_pathname = strdup("$t$n.$x");
/* Muxer config */
.def.u32 = 24*3600,
.group = 1,
},
+ {
+ .type = PT_BOOL,
+ .id = "epg-running",
+ .name = N_("Use EPG Running State"),
+ .off = offsetof(dvr_config_t, dvr_running),
+ .def.u32 = 1,
+ .group = 1,
+ },
{
.type = PT_STR,
.id = "postproc",
return extra != 0 && extra != (time_t)-1;
}
-int
+time_t
dvr_entry_get_start_time( dvr_entry_t *de )
{
/* Note 30 seconds might not be enough (rotors) */
return de->de_start - (60 * dvr_entry_get_extra_time_pre(de)) - 30;
}
-int
+time_t
dvr_entry_get_stop_time( dvr_entry_t *de )
{
return de->de_stop + (60 * dvr_entry_get_extra_time_post(de));
}
-int
+time_t
dvr_entry_get_extra_time_pre( dvr_entry_t *de )
{
time_t extra = de->de_start_extra;
return extra;
}
-int
+time_t
dvr_entry_get_extra_time_post( dvr_entry_t *de )
{
time_t extra = de->de_stop_extra;
return N_("Commercial break");
case DVR_RS_ERROR:
return streaming_code2txt(de->de_last_error);
+ case DVR_RS_EPG_WAIT:
+ return N_("Waiting for EPG running flag");
default:
return N_("Invalid");
}
return used;
}
-static void
+void
dvr_entry_set_timer(dvr_entry_t *de)
{
time_t now, start, stop;
if (now >= stop || de->de_dont_reschedule) {
+ /* EPG thinks that the program is running */
+ if(de->de_running_start > de->de_running_stop) {
+ stop = dispatch_clock + 10;
+ goto recording;
+ }
+
if(htsmsg_is_empty(de->de_files))
dvr_entry_missed_time(de, de->de_last_error);
else
} else if (de->de_sched_state == DVR_RECORDING) {
+recording:
gtimer_arm_abs(&de->de_timer, dvr_timer_stop_recording, de, stop);
} else if (de->de_channel && de->de_channel->ch_enabled) {
}
}
+/**
+ * Event running status is updated
+ */
+void dvr_event_running(epg_broadcast_t *e, epg_source_t esrc, int running)
+{
+ dvr_entry_t *de;
+
+ if (esrc != EPG_SOURCE_EIT)
+ return;
+ de = dvr_entry_find_by_event(e);
+ if (de == NULL)
+ return;
+ if (!de->de_config->dvr_running) {
+ de->de_running_start = de->de_running_stop = 0;
+ return;
+ }
+ if (running) {
+ if (!de->de_running_start)
+ tvhdebug("dvr", "dvr entry %s event %s on %s - EPG marking start",
+ idnode_uuid_as_sstr(&de->de_id),
+ epg_broadcast_get_title(e, NULL),
+ channel_get_name(e->channel));
+ de->de_running_start = dispatch_clock;
+ if (dvr_entry_get_start_time(de) > dispatch_clock) {
+ de->de_start = dispatch_clock;
+ dvr_entry_set_timer(de);
+ tvhdebug("dvr", "dvr entry %s event %s on %s - EPG start",
+ idnode_uuid_as_sstr(&de->de_id),
+ epg_broadcast_get_title(e, NULL),
+ channel_get_name(e->channel));
+ }
+ } else {
+ if (!de->de_running_stop ||
+ de->de_running_start > de->de_running_stop)
+ tvhdebug("dvr", "dvr entry %s event %s on %s - EPG marking stop",
+ idnode_uuid_as_sstr(&de->de_id),
+ epg_broadcast_get_title(e, NULL),
+ channel_get_name(e->channel));
+ de->de_running_stop = dispatch_clock;
+ if (de->de_sched_state == DVR_RECORDING) {
+ if (dvr_entry_get_stop_time(de) > dispatch_clock) {
+ de->de_dont_reschedule = 1;
+ dvr_entry_set_timer(de);
+ tvhdebug("dvr", "dvr entry %s event %s on %s - EPG stop",
+ idnode_uuid_as_sstr(&de->de_id),
+ epg_broadcast_get_title(e, NULL),
+ channel_get_name(e->channel));
+ }
+ }
+ }
+}
+
/**
*
*/
static void
dvr_timer_stop_recording(void *aux)
{
+ dvr_entry_t *de = aux;
+ /* EPG thinks that the program is running */
+ if (de->de_running_start > de->de_running_stop) {
+ gtimer_arm(&de->de_timer, dvr_timer_stop_recording, de, 10);
+ return;
+ }
dvr_stop_recording(aux, SM_CODE_OK, 1, 0);
}
streaming_message_t *sm;
th_subscription_t *ts;
th_pkt_t *pkt;
- int run = 1, started = 0, comm_skip;
+ int run = 1, started = 0, comm_skip, epg_running, rs;
int commercial = COMMERCIAL_UNKNOWN;
+ int64_t packets = 0;
char *postproc;
pthread_mutex_lock(&global_lock);
/* we don't want to start new recordings at this point */
if (sm->sm_type == SMT_START && de->de_thread_shutdown)
break;
+ epg_running = de->de_running_start > de->de_running_stop ||
+ (de->de_running_start == 0 && de->de_running_stop == 0);
pthread_mutex_unlock(&sq->sq_mutex);
switch(sm->sm_type) {
case SMT_PACKET:
pkt = sm->sm_data;
- if(pkt->pkt_commercial == COMMERCIAL_YES)
- dvr_rec_set_state(de, DVR_RS_COMMERCIAL, 0);
- else
- dvr_rec_set_state(de, DVR_RS_RUNNING, 0);
- if(pkt->pkt_commercial == COMMERCIAL_YES && comm_skip)
+ rs = DVR_RS_RUNNING;
+ if (!epg_running)
+ rs = DVR_RS_EPG_WAIT;
+ else if (pkt->pkt_commercial == COMMERCIAL_YES)
+ rs = DVR_RS_COMMERCIAL;
+ dvr_rec_set_state(de, rs, 0);
+
+ if (rs == DVR_RS_COMMERCIAL && comm_skip)
break;
+ if (!epg_running)
+ break;
- if(commercial != pkt->pkt_commercial)
+ if (commercial != pkt->pkt_commercial)
muxer_add_marker(prch->prch_muxer);
commercial = pkt->pkt_commercial;
- if(started) {
+ if (started) {
+ if (!epg_running && packets)
+ goto restart;
muxer_write_pkt(prch->prch_muxer, sm->sm_type, sm->sm_data);
sm->sm_data = NULL;
dvr_notify(de);
+ packets++;
}
break;
case SMT_MPEGTS:
if(started) {
- dvr_rec_set_state(de, DVR_RS_RUNNING, 0);
+ dvr_rec_set_state(de, !epg_running ? DVR_RS_EPG_WAIT : DVR_RS_RUNNING, 0);
+ if (!epg_running && packets)
+ goto restart;
muxer_write_pkt(prch->prch_muxer, sm->sm_type, sm->sm_data);
sm->sm_data = NULL;
dvr_notify(de);
+ packets++;
}
break;
case SMT_START:
+restart:
+ packets = 0;
if(started &&
muxer_reconfigure(prch->prch_muxer, sm->sm_data) < 0) {
tvhlog(LOG_WARNING,
// support reconfiguration of the streams.
dvr_thread_epilog(de, postproc);
started = 0;
- pthread_mutex_lock(&global_lock);
- if (de->de_config->dvr_clone)
- de = dvr_entry_clone(de);
- pthread_mutex_unlock(&global_lock);
+ if (epg_running) {
+ pthread_mutex_lock(&global_lock);
+ if (de->de_config->dvr_clone)
+ de = dvr_entry_clone(de);
+ pthread_mutex_unlock(&global_lock);
+ }
}
if(!started) {
channel_t *ch = (channel_t*)p;
/* Clear now/next */
- if ((cur = ch->ch_epg_now))
+ if ((cur = ch->ch_epg_now)) {
+ if (cur->running) {
+ /* running? don't do anything */
+ gtimer_arm(&ch->ch_epg_timer, _epg_channel_timer_callback, ch, 2);
+ return;
+ }
cur->getref(cur);
+ }
if ((nxt = ch->ch_epg_next))
nxt->getref(nxt);
ch->ch_epg_now = ch->ch_epg_next = NULL;
return NULL;
}
+void epg_broadcast_notify_running
+ ( epg_broadcast_t *broadcast, epg_source_t esrc, int running )
+{
+ channel_t *ch;
+ epg_broadcast_t *now;
+
+ broadcast->running = !!running;
+ if (!running) {
+ broadcast->stop = dispatch_clock - 1;
+ } else {
+ ch = broadcast->channel;
+ now = ch ? ch->ch_epg_now : NULL;
+ if (broadcast != now && now) {
+ now->running = 0;
+ dvr_event_running(ch->ch_epg_now, esrc, 0);
+ }
+ }
+ dvr_event_running(broadcast, esrc, running);
+}
+
int epg_broadcast_set_episode
( epg_broadcast_t *broadcast, epg_episode_t *episode, epggrab_module_t *src )
{
extern int epg_in_load;
+/*
+ *
+ */
+typedef enum {
+ EPG_SOURCE_NONE = 0,
+ EPG_SOURCE_EIT = 1,
+} epg_source_t;
+
/* ************************************************************************
* Genres
* ***********************************************************************/
/* Misc flags */
uint8_t is_new; ///< New series / file premiere
uint8_t is_repeat; ///< Repeat screening
+ uint8_t running; ///< EPG running flag
/* Broadcast level text */
lang_str_t *summary; ///< Summary
/* Special */
epg_broadcast_t *epg_broadcast_clone
( struct channel *channel, epg_broadcast_t *src, int *save );
+void epg_broadcast_notify_running
+ ( epg_broadcast_t *b, epg_source_t esrc, int running );
/* Mutators */
int epg_broadcast_set_episode
#include "epggrab/private.h"
#include "input.h"
#include "input/mpegts/dvb_charset.h"
+#include "dvr/dvr.h"
/* ************************************************************************
* Status handling
* ***********************************************************************/
static int _eit_process_event_one
- ( epggrab_module_t *mod, int tableid,
+ ( epggrab_module_t *mod, int tableid, int sect,
mpegts_service_t *svc, channel_t *ch,
const uint8_t *ptr, int len,
int local, int *resched, int *save )
{
- int save2 = 0;
- int dllen;
+ int dllen, save2 = 0;
time_t start, stop;
uint16_t eid;
- uint8_t dtag, dlen;
+ uint8_t dtag, dlen, running;
epg_broadcast_t *ebc;
epg_episode_t *ee;
epg_serieslink_t *es;
stop = start + bcdtoint(ptr[7] & 0xff) * 3600 +
bcdtoint(ptr[8] & 0xff) * 60 +
bcdtoint(ptr[9] & 0xff);
+ running = (ptr[10] >> 5) & 0x07;
dllen = ((ptr[10] & 0x0f) << 8) | ptr[11];
len -= 12;
if (ev.summary) lang_str_destroy(ev.summary);
if (ev.desc) lang_str_destroy(ev.desc);
+ /* use running flag only for current broadcast */
+ if (running && tableid == 0x4e && sect == 0)
+ epg_broadcast_notify_running(ebc, EPG_SOURCE_EIT, running == 4);
+
return 0;
}
static int _eit_process_event
- ( epggrab_module_t *mod, int tableid,
+ ( epggrab_module_t *mod, int tableid, int sect,
mpegts_service_t *svc, const uint8_t *ptr, int len,
int local, int *resched, int *save )
{
LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link) {
ch = (channel_t *)ilm->ilm_in2;
if (!ch->ch_enabled || ch->ch_epg_parent) continue;
- if (_eit_process_event_one(mod, tableid, svc, ch,
+ if (_eit_process_event_one(mod, tableid, sect, svc, ch,
ptr, len, local, resched, save) < 0)
return -1;
}
ptr += 11;
while (len) {
int r;
- if ((r = _eit_process_event(mod, tableid, svc, ptr, len,
+ if ((r = _eit_process_event(mod, tableid, sect, svc, ptr, len,
mm->mm_network->mn_localtime,
&resched, &save)) < 0)
break;