#endif
static void dvr_entry_destroy(dvr_entry_t *de, int delconf);
+static void dvr_timer_rerecord(void *aux);
static void dvr_timer_expire(void *aux);
static void dvr_timer_remove_files(void *aux);
static void dvr_entry_start_recording(dvr_entry_t *de, int clone);
static void dvr_timer_start_recording(void *aux);
static void dvr_timer_stop_recording(void *aux);
+static void dvr_entry_rerecord(dvr_entry_t *de);
/*
*
return dvr_retention_cleanup(de->de_config->dvr_removal_days);
}
+uint32_t
+dvr_entry_get_rerecord_errors( dvr_entry_t *de )
+{
+ return de->de_config->dvr_rerecord_errors;
+}
+
/*
* DBUS next dvr start notifications
*/
}
#endif
+/*
+ *
+ */
+static void
+dvr_entry_retention_arm(dvr_entry_t *de, gti_callback_t *cb, time_t when)
+{
+ uint32_t rerecord = dvr_entry_get_rerecord_errors(de);
+ if (rerecord && (when - dispatch_clock) > 3600) {
+ when = dispatch_clock + 3600;
+ cb = dvr_timer_rerecord;
+ }
+ gtimer_arm_abs(&de->de_timer, cb, de, when);
+}
+
/*
*
*/
stop = de->de_stop + removal * (time_t)86400;
if (removal > 0 || retention == 0) {
if (stop > dispatch_clock) {
- gtimer_arm_abs(&de->de_timer, dvr_timer_remove_files, de, stop);
+ dvr_entry_retention_arm(de, dvr_timer_remove_files, stop);
return;
}
if (dvr_get_filename(de))
dvr_entry_delete(de, 1);
}
stop = de->de_stop + retention * (time_t)86400;
- gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, stop);
+ dvr_entry_retention_arm(de, dvr_timer_expire, stop);
}
/*
else
dvr_entry_completed(de, de->de_last_error);
+ dvr_entry_rerecord(de);
+
} else if (de->de_sched_state == DVR_RECORDING) {
gtimer_arm_abs(&de->de_timer, dvr_timer_stop_recording, de, stop);
return n == NULL ? de : n;
}
+/**
+ *
+ */
+static void
+dvr_entry_rerecord(dvr_entry_t *de)
+{
+ uint32_t rerecord = dvr_entry_get_rerecord_errors(de);
+ epg_broadcast_t *e, *ev;
+ dvr_entry_t *de2;
+ char cfg_uuid[UUID_HEX_SIZE];
+ int64_t fsize1, fsize2;
+
+ if (rerecord == 0)
+ return;
+ if (de->de_parent) {
+ if (de->de_sched_state == DVR_COMPLETED &&
+ de->de_errors == 0 &&
+ de->de_data_errors < de->de_parent->de_data_errors) {
+ fsize1 = dvr_get_filesize(de);
+ fsize2 = dvr_get_filesize(de->de_parent);
+ if (fsize1 / 5 < fsize2 / 6) {
+ goto not_so_good;
+ } else {
+ dvr_entry_cancel_delete(de->de_parent);
+ }
+ } else if (de->de_sched_state == DVR_COMPLETED) {
+not_so_good:
+ de->de_retention = 1;
+ de->de_parent->de_slave = NULL;
+ de->de_parent = NULL;
+ dvr_entry_completed(de, SM_CODE_WEAK_STREAM);
+ return;
+ }
+ }
+ if (de->de_slave)
+ return;
+ if (de->de_enabled == 0)
+ return;
+ if (de->de_channel == NULL)
+ return;
+ if (de->de_sched_state == DVR_SCHEDULED ||
+ de->de_sched_state == DVR_RECORDING)
+ return;
+ /* rerecord if - DVR_NOSTATE, DVR_MISSED_TIME */
+ if (de->de_sched_state == DVR_COMPLETED &&
+ rerecord < de->de_data_errors && de->de_errors <= 0)
+ return;
+
+ e = NULL;
+ RB_FOREACH(ev, &de->de_channel->ch_epg_schedule, sched_link) {
+ if (dvr_entry_fuzzy_match(de, ev))
+ if (!e || e->start > ev->start)
+ e = ev;
+ }
+
+ if (e == NULL)
+ return;
+
+ tvhtrace("dvr", " rerecord event %s on %s @ %"PRItime_t
+ " to %"PRItime_t,
+ epg_broadcast_get_title(e, NULL),
+ channel_get_name(e->channel),
+ e->start, e->stop);
+
+ idnode_uuid_as_str(&de->de_config->dvr_id, cfg_uuid);
+ de2 = dvr_entry_create_by_event(1, cfg_uuid, e,
+ de->de_start_extra, de->de_stop_extra,
+ de->de_owner, de->de_creator, NULL,
+ de->de_pri, de->de_retention, de->de_removal,
+ de->de_comment);
+ if (de2) {
+ de->de_slave = de2;
+ de2->de_parent = de;
+ dvr_entry_save(de);
+ dvr_entry_save(de2);
+ }
+}
+
/**
*
*/
LIST_REMOVE(de, de_global_link);
de->de_channel = NULL;
+ if (de->de_parent)
+ de->de_parent->de_slave = NULL;
+ if (de->de_slave)
+ de->de_slave->de_parent = NULL;
+
dvr_entry_dec_ref(de);
}
}
+/**
+ *
+ */
+static void
+dvr_timer_rerecord(void *aux)
+{
+ dvr_entry_t *de = aux;
+ dvr_entry_rerecord(de);
+ dvr_entry_retention_timer(de);
+}
+
+
/**
*
*/
return &ret;
}
+static int
+dvr_entry_class_parent_set(void *o, const void *v)
+{
+ dvr_entry_t *de = (dvr_entry_t *)o, *de2;
+ if (!dvr_entry_is_editable(de))
+ return 0;
+ de2 = v ? dvr_entry_find_by_uuid(v) : NULL;
+ if (de2 == NULL) {
+ if (de->de_parent) {
+ de->de_parent->de_slave = NULL;
+ de->de_parent = NULL;
+ return 1;
+ }
+ } else if (de->de_parent != de2) {
+ de->de_parent = de2;
+ de2->de_slave = de;
+ return 1;
+ }
+ return 0;
+}
+
+static const void *
+dvr_entry_class_parent_get(void *o)
+{
+ static const char *ret;
+ dvr_entry_t *de = (dvr_entry_t *)o;
+ if (de->de_parent)
+ ret = idnode_uuid_as_sstr(&de->de_parent->de_id);
+ else
+ ret = "";
+ return &ret;
+}
+
+static int
+dvr_entry_class_slave_set(void *o, const void *v)
+{
+ dvr_entry_t *de = (dvr_entry_t *)o, *de2;
+ if (!dvr_entry_is_editable(de))
+ return 0;
+ de2 = v ? dvr_entry_find_by_uuid(v) : NULL;
+ if (de2 == NULL) {
+ if (de->de_slave) {
+ de->de_slave->de_parent = NULL;
+ de->de_slave = NULL;
+ return 1;
+ }
+ } else if (de->de_slave != de2) {
+ de->de_slave = de2;
+ de2->de_parent = de;
+ return 1;
+ }
+ return 0;
+}
+
+static const void *
+dvr_entry_class_slave_get(void *o)
+{
+ static const char *ret;
+ dvr_entry_t *de = (dvr_entry_t *)o;
+ if (de->de_parent)
+ ret = idnode_uuid_as_sstr(&de->de_slave->de_id);
+ else
+ ret = "";
+ return &ret;
+}
+
static int
dvr_entry_class_broadcast_set(void *o, const void *v)
{
.get = dvr_entry_class_timerec_caption_get,
.opts = PO_RDONLY | PO_NOSAVE | PO_HIDDEN,
},
+ {
+ .type = PT_STR,
+ .id = "parent",
+ .name = N_("Parent Entry"),
+ .set = dvr_entry_class_parent_set,
+ .get = dvr_entry_class_parent_get,
+ .opts = PO_RDONLY,
+ },
+ {
+ .type = PT_STR,
+ .id = "slave",
+ .name = N_("Slave Entry"),
+ .set = dvr_entry_class_slave_set,
+ .get = dvr_entry_class_slave_get,
+ .opts = PO_RDONLY,
+ },
{
.type = PT_U32,
.id = "content_type",
return val2str(v, priotab) ?: "invalid";
}
-
/**
*
*/