View
@@ -417,6 +417,8 @@ tasklet_thread ( void *aux )
if (tsk->tsk_callback)
tsk->tsk_callback(tsk->tsk_opaque, 0);
TAILQ_REMOVE(&tasklets, tsk, tsk_link);
+ if (tsk->tsk_allocated)
+ free(tsk);
}
pthread_mutex_unlock(&tasklet_lock);
@@ -480,7 +482,23 @@ show_usage
exit(0);
}
-
+/**
+ *
+ */
+void
+dispatch_clock_update(struct timespec *ts)
+{
+ struct timespec ts1;
+ if (ts == NULL)
+ ts = &ts1;
+ clock_gettime(CLOCK_REALTIME, ts);
+
+ /* 1sec stuff */
+ if (ts->tv_sec > dispatch_clock) {
+ dispatch_clock = ts->tv_sec;
+ comet_flush(); /* Flush idle comet mailboxes */
+ }
+}
/**
*
@@ -498,14 +516,7 @@ mainloop(void)
#endif
while(tvheadend_running) {
- clock_gettime(CLOCK_REALTIME, &ts);
-
- /* 1sec stuff */
- if (ts.tv_sec > dispatch_clock) {
- dispatch_clock = ts.tv_sec;
-
- comet_flush(); /* Flush idle comet mailboxes */
- }
+ dispatch_clock_update(&ts);
/* Global timers */
pthread_mutex_lock(&global_lock);
@@ -661,7 +672,7 @@ main(int argc, char **argv)
OPT_BOOL, &opt_dbus_session },
#endif
#if ENABLE_LINUXDVB
- { 'a', "adapters", "Only use specified DVB adapters (comma separated)",
+ { 'a', "adapters", "Only use specified DVB adapters (comma separated, -1 = none)",
OPT_STR, &opt_dvb_adapters },
#endif
#if ENABLE_SATIP_SERVER
@@ -740,9 +751,11 @@ main(int argc, char **argv)
/* Find option */
cmdline_opt_t *opt
= cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
- if (!opt)
+ if (!opt) {
show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
"invalid option specified [%s]", argv[i]);
+ continue;
+ }
/* Process */
if (opt->type == OPT_BOOL)
@@ -778,19 +791,24 @@ main(int argc, char **argv)
char *r = NULL;
char *dvb_adapters = strdup(opt_dvb_adapters);
adapter_mask = 0x0;
+ i = 0;
p = strtok_r(dvb_adapters, ",", &r);
while (p) {
int a = strtol(p, &e, 10);
- if (*e != 0 || a < 0 || a > 31) {
- tvhlog(LOG_ERR, "START", "Invalid adapter number '%s'", p);
+ if (*e != 0 || a > 31) {
+ fprintf(stderr, "Invalid adapter number '%s'\n", p);
free(dvb_adapters);
return 1;
}
- adapter_mask |= (1 << a);
+ i = 1;
+ if (a < 0)
+ adapter_mask = 0;
+ else
+ adapter_mask |= (1 << a);
p = strtok_r(NULL, ",", &r);
}
free(dvb_adapters);
- if (!adapter_mask) {
+ if (!i) {
tvhlog(LOG_ERR, "START", "No adapters specified!");
return 1;
}
View
@@ -474,6 +474,8 @@ mk_write_to_fd(mk_mux_t *mkm, htsbuf_queue_t *hq)
ssize_t r;
int iovcnt = i < dvr_iov_max ? i : dvr_iov_max;
if((r = writev(mkm->fd, iov, iovcnt)) == -1) {
+ if (ERRNO_AGAIN(errno))
+ continue;
mkm->error = errno;
return -1;
}
View
@@ -399,33 +399,55 @@ profile_find_by_name(const char *name, const char *alt)
/*
*
*/
+static int
+profile_verify(profile_t *pro, int sflags)
+{
+ if (!pro)
+ return 0;
+ if (!pro->pro_enabled)
+ return 0;
+ if ((sflags & SUBSCRIPTION_HTSP) != 0 && !pro->pro_work)
+ return 0;
+ if ((sflags & SUBSCRIPTION_HTSP) == 0 && !pro->pro_open)
+ return 0;
+ sflags &= pro->pro_sflags;
+ sflags &= SUBSCRIPTION_PACKET|SUBSCRIPTION_MPEGTS;
+ return sflags ? 1 : 0;
+}
+
+/*
+ *
+ */
profile_t *
-profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt)
+profile_find_by_list
+ (htsmsg_t *uuids, const char *name, const char *alt, int sflags)
{
profile_t *pro, *res = NULL;
htsmsg_field_t *f;
const char *uuid, *uuid2;
pro = profile_find_by_uuid(name);
if (!pro)
- pro = profile_find_by_name(name, alt);
- uuid = pro ? idnode_uuid_as_str(&pro->pro_id) : "";
+ pro = profile_find_by_name(name, alt);
+ if (!profile_verify(pro, sflags))
+ pro = NULL;
if (uuids) {
+ uuid = pro ? idnode_uuid_as_str(&pro->pro_id) : "";
HTSMSG_FOREACH(f, uuids) {
uuid2 = htsmsg_field_get_str(f) ?: "";
- if (strcmp(uuid, uuid2) == 0)
+ if (strcmp(uuid, uuid2) == 0 && profile_verify(pro, sflags))
return pro;
if (!res) {
res = profile_find_by_uuid(uuid2);
- if (!res->pro_enabled)
+ if (!profile_verify(res, sflags))
res = NULL;
}
}
} else {
res = pro;
}
if (!res)
- res = profile_find_by_name(!strcmp(alt, "htsp") ? "htsp" : NULL, NULL);
+ res = profile_find_by_name((sflags & SUBSCRIPTION_HTSP) ? "htsp" : NULL, NULL);
return res;
}
@@ -935,6 +957,7 @@ static profile_t *
profile_htsp_builder(void)
{
profile_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_work = profile_htsp_work;
pro->pro_get_mc = profile_htsp_get_mc;
return pro;
@@ -1037,6 +1060,7 @@ static profile_t *
profile_mpegts_pass_builder(void)
{
profile_mpegts_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_MPEGTS;
pro->pro_reopen = profile_mpegts_pass_reopen;
pro->pro_open = profile_mpegts_pass_open;
pro->pro_get_mc = profile_mpegts_pass_get_mc;
@@ -1120,6 +1144,7 @@ static profile_t *
profile_matroska_builder(void)
{
profile_matroska_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_reopen = profile_matroska_reopen;
pro->pro_open = profile_matroska_open;
pro->pro_get_mc = profile_matroska_get_mc;
@@ -1191,6 +1216,7 @@ static profile_t *
profile_libav_mpegts_builder(void)
{
profile_libav_mpegts_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_reopen = profile_libav_mpegts_reopen;
pro->pro_open = profile_libav_mpegts_open;
pro->pro_get_mc = profile_libav_mpegts_get_mc;
@@ -1276,6 +1302,7 @@ static profile_t *
profile_libav_matroska_builder(void)
{
profile_libav_matroska_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_reopen = profile_libav_matroska_reopen;
pro->pro_open = profile_libav_matroska_open;
pro->pro_get_mc = profile_libav_matroska_get_mc;
@@ -1463,7 +1490,7 @@ const idclass_t profile_transcode_class =
{
.type = PT_U32,
.id = "resolution",
- .name = "Resolution",
+ .name = "Resolution (height)",
.off = offsetof(profile_transcode_t, pro_resolution),
.def.u32 = 384,
},
@@ -1700,6 +1727,7 @@ static profile_t *
profile_transcode_builder(void)
{
profile_transcode_t *pro = calloc(1, sizeof(*pro));
+ pro->pro_sflags = SUBSCRIPTION_PACKET;
pro->pro_free = profile_transcode_free;
pro->pro_work = profile_transcode_work;
pro->pro_reopen = profile_transcode_reopen;
View
@@ -114,6 +114,7 @@ typedef struct profile {
LIST_HEAD(,dvr_config) pro_dvr_configs;
LIST_HEAD(,access_entry) pro_accesses;
+ int pro_sflags;
int pro_enabled;
int pro_shield;
char *pro_name;
@@ -168,7 +169,8 @@ int profile_chain_weight(profile_chain_t *prch, int custom);
static inline profile_t *profile_find_by_uuid(const char *uuid)
{ return (profile_t*)idnode_find(uuid, &profile_class, NULL); }
profile_t *profile_find_by_name(const char *name, const char *alt);
-profile_t *profile_find_by_list(htsmsg_t *uuids, const char *name, const char *alt);
+profile_t *profile_find_by_list(htsmsg_t *uuids, const char *name,
+ const char *alt, int sflags);
htsmsg_t * profile_class_get_list(void *o);
View
@@ -625,13 +625,18 @@ satip_rtcp_thread(void *aux)
/*
*
*/
-void satip_rtp_init(void)
+void satip_rtp_init(int boot)
{
TAILQ_INIT(&satip_rtp_sessions);
pthread_mutex_init(&satip_rtp_lock, NULL);
- satip_rtcp_run = 1;
- tvhthread_create(&satip_rtcp_tid, NULL, satip_rtcp_thread, NULL);
+ if (boot)
+ satip_rtcp_run = 0;
+
+ if (!boot && !satip_rtcp_run) {
+ satip_rtcp_run = 1;
+ tvhthread_create(&satip_rtcp_tid, NULL, satip_rtcp_thread, NULL);
+ }
}
/*
View
@@ -476,6 +476,8 @@ rtsp_start
mux = NULL;
mn2 = NULL;
LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
+ if (!idnode_is_instance(&mn->mn_id, &dvb_network_class))
+ continue;
ln = (dvb_network_t *)mn;
if (ln->ln_type == rs->dmc.dmc_fe_type &&
mn->mn_satip_source == rs->src) {
@@ -1064,6 +1066,7 @@ rtsp_parse_cmd
rtsp_rearm_session_timer(rs);
mpegts_pid_done(&addpids);
mpegts_pid_done(&delpids);
+ mpegts_pid_done(&pids);
return errcode;
eargs:
@@ -1298,7 +1301,7 @@ rtsp_process_play(http_connection_t *hc, int setup)
}
}
- if ((errcode = rtsp_start(hc, rs, hc->hc_peer_ipstr, valid, setup, oldstate)) < 0)
+ if ((errcode = rtsp_start(hc, rs, hc->hc_peer_ipstr, valid, setup, oldstate)) != 0)
goto error;
if (setup) {
@@ -1539,7 +1542,7 @@ void satip_server_rtsp_init
session_number = *(uint32_t *)rnd;
TAILQ_INIT(&rtsp_sessions);
pthread_mutex_init(&rtsp_lock, NULL);
- satip_rtp_init();
+ satip_rtp_init(1);
}
if (rtsp_port != port && rtsp_server) {
rtsp_close_sessions();
@@ -1561,6 +1564,7 @@ void satip_server_rtsp_init
void satip_server_rtsp_register(void)
{
tcp_server_register(rtsp_server);
+ satip_rtp_init(0);
}
void satip_server_rtsp_done(void)
View
@@ -293,7 +293,7 @@ DEVICEID.SES.COM: %d\r\n\r\n"
tvhtrace("satips", "sending announce");
- for (attempt = 1; attempt < 3; attempt++) {
+ for (attempt = 1; attempt <= 3; attempt++) {
switch (attempt) {
case 1:
nt = "upnp:rootdevice";
@@ -567,7 +567,7 @@ void satip_server_init(int rtsp_port)
satip_server_uuid = NULL;
satip_server_deviceid = 1;
- if (tcp_server_bound(http_server, &http) < 0) {
+ if (tcp_server_bound(http_server, &http, PF_INET) < 0) {
tvherror("satips", "Unable to determine the HTTP/RTSP address");
return;
}
View
@@ -45,7 +45,7 @@ void satip_rtp_update_pids(void *id, mpegts_apids_t *pids);
int satip_rtp_status(void *id, char *buf, int len);
void satip_rtp_close(void *id);
-void satip_rtp_init(void);
+void satip_rtp_init(int boot);
void satip_rtp_done(void);
void satip_server_rtsp_init(const char *bindaddr, int port,
View
@@ -54,6 +54,9 @@ static void service_class_save(struct idnode *self);
struct service_queue service_all;
struct service_queue service_raw_all;
+struct service_queue service_raw_remove;
+
+static gtimer_t service_raw_remove_timer;
static void
service_class_notify_enabled ( void *obj )
@@ -347,7 +350,7 @@ void
service_stop(service_t *t)
{
elementary_stream_t *st;
-
+
gtimer_disarm(&t->s_receive_timer);
t->s_stop_feed(t);
@@ -394,9 +397,6 @@ service_remove_subscriber(service_t *t, th_subscription_t *s,
} else {
subscription_unlink_service(s, reason);
}
-
- if(LIST_FIRST(&t->s_subscriptions) == NULL)
- service_stop(t);
}
@@ -842,8 +842,7 @@ service_destroy(service_t *t, int delconf)
idnode_unlink(&t->s_id);
- if(t->s_status != SERVICE_IDLE)
- service_stop(t);
+ assert(t->s_status == SERVICE_IDLE);
t->s_status = SERVICE_ZOMBIE;
@@ -855,14 +854,39 @@ service_destroy(service_t *t, int delconf)
avgstat_flush(&t->s_rate);
- if (t->s_type == STYPE_RAW)
+ switch (t->s_type) {
+ case STYPE_RAW:
TAILQ_REMOVE(&service_raw_all, t, s_all_link);
- else
+ break;
+ case STYPE_RAW_REMOVED:
+ TAILQ_REMOVE(&service_raw_remove, t, s_all_link);
+ break;
+ default:
TAILQ_REMOVE(&service_all, t, s_all_link);
+ }
service_unref(t);
}
+static void
+service_remove_raw_timer_cb(void *aux)
+{
+ service_t *t;
+ while ((t = TAILQ_FIRST(&service_raw_remove)) != NULL)
+ service_destroy(t, 0);
+}
+
+void
+service_remove_raw(service_t *t)
+{
+ if (t == NULL) return;
+ assert(t->s_type == STYPE_RAW);
+ t->s_type = STYPE_RAW_REMOVED;
+ TAILQ_REMOVE(&service_raw_all, t, s_all_link);
+ TAILQ_INSERT_TAIL(&service_raw_remove, t, s_all_link);
+ gtimer_arm(&service_raw_remove_timer, service_remove_raw_timer_cb, NULL, 0);
+}
+
void
service_set_enabled(service_t *t, int enabled, int _auto)
{
@@ -1414,6 +1438,7 @@ service_init(void)
TAILQ_INIT(&pending_save_queue);
TAILQ_INIT(&service_all);
TAILQ_INIT(&service_raw_all);
+ TAILQ_INIT(&service_raw_remove);
pthread_mutex_init(&pending_save_mutex, NULL);
pthread_cond_init(&pending_save_cond, NULL);
tvhthread_create(&service_saver_tid, NULL, service_saver, NULL);
@@ -1422,8 +1447,15 @@ service_init(void)
void
service_done(void)
{
+ service_t *t;
+
pthread_cond_signal(&pending_save_cond);
pthread_join(service_saver_tid, NULL);
+
+ pthread_mutex_lock(&global_lock);
+ while ((t = TAILQ_FIRST(&service_raw_remove)) != NULL)
+ service_destroy(t, 0);
+ pthread_mutex_unlock(&global_lock);
}
/**
View
@@ -28,6 +28,7 @@ extern const idclass_t service_raw_class;
extern struct service_queue service_all;
extern struct service_queue service_raw_all;
+extern struct service_queue service_raw_remove;
struct channel;
struct tvh_input;
@@ -241,7 +242,8 @@ typedef struct service {
*/
enum {
STYPE_STD,
- STYPE_RAW
+ STYPE_RAW,
+ STYPE_RAW_REMOVED
} s_type;
/**
@@ -535,6 +537,8 @@ void service_set_enabled ( service_t *t, int enabled, int _auto );
void service_destroy(service_t *t, int delconf);
+void service_remove_raw(service_t *);
+
void service_remove_subscriber(service_t *t, struct th_subscription *s,
int reason);
View
@@ -357,14 +357,34 @@ spawn_parse_args(char ***argv, int argc, const char *cmd, const char **replace)
*argv = calloc(argc, sizeof(char *));
while (*s && i < argc - 1) {
+ while (*s == ' ')
+ s++;
f = s;
while (*s && *s != ' ') {
- while (*s && *s != ' ' && *s != '\\')
- s++;
if (*s == '\\') {
- memmove(s, s + 1, strlen(s));
- if (*s)
- s++;
+ l = *(s + 1);
+ if (l == 'b')
+ l = '\b';
+ else if (l == 'f')
+ l = '\f';
+ else if (l == 'n')
+ l = '\n';
+ else if (l == 'r')
+ l = '\r';
+ else if (l == 't')
+ l = '\t';
+ else
+ l = 0;
+ if (l) {
+ *s++ = l;
+ memmove(s, s + 1, strlen(s));
+ } else {
+ memmove(s, s + 1, strlen(s));
+ if (*s)
+ s++;
+ }
+ } else {
+ s++;
}
}
if (f != s) {
View
@@ -116,16 +116,14 @@ subscription_link_service(th_subscription_t *s, service_t *t)
/**
* Called from service code
*/
-static void
+static int
subscription_unlink_service0(th_subscription_t *s, int reason, int stop)
{
streaming_message_t *sm;
- service_t *t = s->ths_service;
+ service_t *t = s->ths_service, *tr = s->ths_raw_service;
/* Ignore - not actually linked */
- if (!s->ths_current_instance) return;
-
- tvhtrace("subscription", "%04X: unlinking sub %p from svc %p", shortid(s), s, t);
+ if (!s->ths_current_instance) goto stop;
pthread_mutex_lock(&t->s_stream_mutex);
@@ -142,9 +140,19 @@ subscription_unlink_service0(th_subscription_t *s, int reason, int stop)
LIST_REMOVE(s, ths_service_link);
s->ths_service = NULL;
+ s->ths_raw_service = NULL;
- if (stop && (s->ths_flags & SUBSCRIPTION_ONESHOT) != 0)
+ if (stop && (s->ths_flags & SUBSCRIPTION_ONESHOT) != 0) {
+ if (tr)
+ LIST_REMOVE(s, ths_mux_link);
subscription_unsubscribe(s, 0);
+ service_remove_raw(tr);
+ }
+
+stop:
+ if(LIST_FIRST(&t->s_subscriptions) == NULL)
+ service_stop(t);
+ return 1;
}
void
@@ -329,11 +337,7 @@ subscription_reschedule(void)
subscription_unlink_service0(s, SM_CODE_BAD_SOURCE, 0);
- if(t && LIST_FIRST(&t->s_subscriptions) == NULL)
- service_stop(t);
-
si = s->ths_current_instance;
-
assert(si != NULL);
si->si_error = s->ths_testing_error;
time(&si->si_error_time);
@@ -549,13 +553,17 @@ subscription_input(void *opauqe, streaming_message_t *sm)
void
subscription_unsubscribe(th_subscription_t *s, int quiet)
{
- service_t *t = s->ths_service;
+ service_t *t;
char buf[512];
size_t l = 0;
+ service_t *raw;
if (s == NULL)
return;
+ t = s->ths_service;
+ raw = s->ths_raw_service;
+
lock_assert(&global_lock);
s->ths_state = SUBSCRIPTION_ZOMBIE;
@@ -566,7 +574,7 @@ subscription_unsubscribe(th_subscription_t *s, int quiet)
LIST_SAFE_REMOVE(s, ths_remove_link);
#if ENABLE_MPEGTS
- if (s->ths_raw_service)
+ if (raw)
LIST_REMOVE(s, ths_mux_link);
#endif
@@ -592,8 +600,8 @@ subscription_unsubscribe(th_subscription_t *s, int quiet)
}
#if ENABLE_MPEGTS
- if (s->ths_raw_service)
- service_destroy(s->ths_raw_service, 0);
+ if (raw)
+ service_remove_raw(s->ths_raw_service);
#endif
streaming_msg_free(s->ths_start_message);
View
@@ -39,6 +39,7 @@ extern struct th_subscription_list subscriptions;
#define SUBSCRIPTION_IDLESCAN 0x2000 ///< for mux subscriptions
#define SUBSCRIPTION_USERSCAN 0x4000 ///< for mux subscriptions
#define SUBSCRIPTION_EPG 0x8000 ///< for mux subscriptions
+#define SUBSCRIPTION_HTSP 0x10000
/* Some internal priorities */
#define SUBSCRIPTION_PRIO_KEEP 1 ///< Keep input rolling
View
@@ -65,7 +65,7 @@ tcp_connect(const char *hostname, int port, const char *bindaddr,
}
fd = tvh_socket(ai->ai_family, SOCK_STREAM, 0);
- if(fd == -1) {
+ if(fd < 0) {
snprintf(errbuf, errbufsize, "Unable to create socket: %s",
strerror(errno));
freeaddrinfo(ai);
@@ -88,6 +88,7 @@ tcp_connect(const char *hostname, int port, const char *bindaddr,
ai->ai_family == AF_INET6 ? "6" : "4",
bindaddr);
freeaddrinfo(ai);
+ close(fd);
return -1;
}
}
@@ -100,7 +101,7 @@ tcp_connect(const char *hostname, int port, const char *bindaddr,
r = connect(fd, ai->ai_addr, ai->ai_addrlen);
freeaddrinfo(ai);
- if(r == -1) {
+ if(r < 0) {
/* timeout < 0 - do not wait at all */
if(errno == EINPROGRESS && timeout < 0) {
err = 0;
@@ -755,15 +756,15 @@ tcp_server_delete(void *server)
*
*/
int
-tcp_default_ip_addr ( struct sockaddr_storage *deflt )
+tcp_default_ip_addr ( struct sockaddr_storage *deflt, int family )
{
struct sockaddr_storage ss;
socklen_t ss_len;
int sock;
memset(&ss, 0, sizeof(ss));
- ss.ss_family = tcp_preferred_address_family;
+ ss.ss_family = family == PF_UNSPEC ? tcp_preferred_address_family : family;
if (inet_pton(ss.ss_family,
ss.ss_family == AF_INET ?
/* Google name servers */
@@ -804,7 +805,7 @@ tcp_default_ip_addr ( struct sockaddr_storage *deflt )
*
*/
int
-tcp_server_bound ( void *server, struct sockaddr_storage *bound )
+tcp_server_bound ( void *server, struct sockaddr_storage *bound, int family )
{
tcp_server_t *ts = server;
int i, len, port;
@@ -827,7 +828,7 @@ tcp_server_bound ( void *server, struct sockaddr_storage *bound )
port = IP_PORT(ts->bound);
/* no bind address was set, try to find one */
- if (tcp_default_ip_addr(bound) < 0)
+ if (tcp_default_ip_addr(bound, family) < 0)
return -1;
if (bound->ss_family == AF_INET)
IP_AS_V4(*bound, port) = port;
View
@@ -70,9 +70,9 @@ void tcp_server_register(void *server);
void tcp_server_delete(void *server);
-int tcp_default_ip_addr(struct sockaddr_storage *deflt);
+int tcp_default_ip_addr(struct sockaddr_storage *deflt, int family);
-int tcp_server_bound(void *server, struct sockaddr_storage *bound);
+int tcp_server_bound(void *server, struct sockaddr_storage *bound, int family);
int tcp_read(int fd, void *buf, size_t len);
View
@@ -44,6 +44,7 @@
static ssize_t _read_buf ( timeshift_file_t *tsf, int fd, void *buf, size_t size )
{
if (tsf && tsf->ram) {
+ if (tsf->roff == tsf->woff) return 0;
if (tsf->roff + size > tsf->woff) return -1;
pthread_mutex_lock(&tsf->ram_lock);
memcpy(buf, tsf->ram + tsf->roff, size);
@@ -250,7 +251,7 @@ static int _timeshift_skip
timeshift_index_iframe_t **iframe )
{
timeshift_index_iframe_t *tsi = *iframe;
- timeshift_file_t *tsf = cur_file;
+ timeshift_file_t *tsf = cur_file, *tsf_last;
int64_t sec = req_time / (1000000 * TIMESHIFT_FILE_PERIOD);
int back = (req_time < cur_time) ? 1 : 0;
int end = 0;
@@ -303,20 +304,26 @@ static int _timeshift_skip
/* Find start/end of buffer */
if (end) {
if (back) {
- tsf = timeshift_filemgr_oldest(ts);
+ tsf = tsf_last = timeshift_filemgr_oldest(ts);
tsi = NULL;
while (tsf && !tsi) {
+ tsf_last = tsf;
if (!(tsi = TAILQ_FIRST(&tsf->iframes)))
tsf = timeshift_filemgr_next(tsf, &end, 0);
}
+ if (!tsf)
+ tsf = tsf_last;
end = -1;
} else {
- tsf = timeshift_filemgr_get(ts, 0);
+ tsf = tsf_last = timeshift_filemgr_get(ts, 0);
tsi = NULL;
while (tsf && !tsi) {
+ tsf_last = tsf;
if (!(tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list)))
tsf = timeshift_filemgr_prev(tsf, &end, 0);
}
+ if (!tsf)
+ tsf = tsf_last;
end = 1;
}
}
@@ -502,7 +509,7 @@ void *timeshift_reader ( void *p )
/* Ignore negative */
if (ts->ondemand && (speed < 0))
- speed = 0;
+ speed = cur_file ? speed : 0;
/* Process */
if (cur_speed != speed) {
@@ -757,7 +764,7 @@ void *timeshift_reader ( void *p )
/* Report error */
skip->type = SMT_SKIP_ERROR;
skip = NULL;
- tvhlog(LOG_DEBUG, "timeshift", "ts %d skip failed", ts->id);
+ tvhlog(LOG_DEBUG, "timeshift", "ts %d skip failed (%d)", ts->id, sm ? sm->sm_type : -1);
}
streaming_target_deliver2(ts->output, ctrl);
ctrl = NULL;
@@ -831,6 +838,7 @@ void *timeshift_reader ( void *p )
cur_speed = 0;
ts->state = TS_PAUSE;
} else {
+ cur_speed = 100;
ts->state = TS_PLAY;
play_time = now;
}
View
@@ -27,6 +27,7 @@
#endif
#include <pthread.h>
#include <stdarg.h>
+#include <time.h>
#include "htsmsg.h"
@@ -117,4 +118,6 @@ static inline int tvhlog_limit ( tvhlog_limit_t *limit, uint32_t delay )
#define tvhnotice(...) tvhlog(LOG_NOTICE, ##__VA_ARGS__)
#define tvherror(...) tvhlog(LOG_ERR, ##__VA_ARGS__)
+void dispatch_clock_update(struct timespec *ts);
+
#endif /* __TVH_LOGGING_H__ */
View
@@ -48,6 +48,7 @@ tvheadend.cometPoller = function() {
tvheadend.boxid = response.boxid;
for (x = 0; x < response.messages.length; x++) {
m = response.messages[x];
+ if (0) console.log(JSON.stringify(m), null, " ");
try {
tvheadend.comet.fireEvent(m.notificationClass, m);
} catch (e) {
View
@@ -1901,7 +1901,7 @@ tvheadend.idnode_tree = function(panel, conf)
}
function updatenode(o) {
- if (o.uuid) {
+ if ('change' in o || 'delete' in o) {
tree.getRootNode().reload();
tree.expandAll();
}
View
@@ -611,13 +611,14 @@ http_dvr_list_playlist(http_connection_t *hc)
char buf[255];
dvr_entry_t *de;
const char *uuid;
- char *hostpath = http_get_hostpath(hc);
+ char *hostpath;
off_t fsize;
time_t durration;
struct tm tm;
int bandwidth;
hq = &hc->hc_reply;
+ hostpath = http_get_hostpath(hc);
htsbuf_qprintf(hq, "#EXTM3U\n");
LIST_FOREACH(de, &dvrentries, de_global_link) {
@@ -788,7 +789,8 @@ http_stream_service(http_connection_t *hc, service_t *service, int weight)
if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
http_arg_get(&hc->hc_req_args, "profile"),
- "service")))
+ "service",
+ SUBSCRIPTION_PACKET | SUBSCRIPTION_MPEGTS)))
return HTTP_STATUS_NOT_ALLOWED;
if((tcp_id = http_stream_preop(hc)) == NULL)
@@ -925,7 +927,8 @@ http_stream_channel(http_connection_t *hc, channel_t *ch, int weight)
if(!(pro = profile_find_by_list(hc->hc_access->aa_profiles,
http_arg_get(&hc->hc_req_args, "profile"),
- "channel")))
+ "channel",
+ SUBSCRIPTION_PACKET | SUBSCRIPTION_MPEGTS)))
return HTTP_STATUS_NOT_ALLOWED;
if((tcp_id = http_stream_preop(hc)) == NULL)
@@ -1037,28 +1040,37 @@ page_xspf(http_connection_t *hc, const char *remain, void *opaque)
{
size_t maxlen;
char *buf, *hostpath = http_get_hostpath(hc);
- const char *title, *profile, *image;
+ const char *title, *profile, *ticket, *image;
size_t len;
if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
title = "TVHeadend Stream";
profile = http_arg_get(&hc->hc_req_args, "profile");
+ ticket = http_arg_get(&hc->hc_req_args, "ticket");
image = http_arg_get(&hc->hc_req_args, "image");
maxlen = strlen(remain) + strlen(title) + 512;
buf = alloca(maxlen);
+ pthread_mutex_lock(&global_lock);
+ if (ticket == NULL) {
+ snprintf(buf, maxlen, "/%s", remain);
+ ticket = access_ticket_create(buf, hc->hc_access);
+ }
snprintf(buf, maxlen, "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\
<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\">\r\n\
<trackList>\r\n\
<track>\r\n\
<title>%s</title>\r\n\
- <location>%s/%s%s%s</location>\r\n%s%s%s\
+ <location>%s/%s%s%s%s%s</location>\r\n%s%s%s\
</track>\r\n\
</trackList>\r\n\
-</playlist>\r\n", title, hostpath, remain, profile ? "?profile=" : "", profile ?: "",
- image ? " <image>" : "", image ?: "", image ? "</image>\r\n" : "");
+</playlist>\r\n", title, hostpath, remain,
+ profile ? "?profile=" : "", profile ?: "",
+ profile ? "&ticket=" : "?ticket=", ticket,
+ image ? " <image>" : "", image ?: "", image ? "</image>\r\n" : "");
+ pthread_mutex_unlock(&global_lock);
len = strlen(buf);
http_send_header(hc, 200, "application/xspf+xml", len, 0, NULL, 10, 0, NULL, NULL);
@@ -1077,20 +1089,29 @@ page_m3u(http_connection_t *hc, const char *remain, void *opaque)
{
size_t maxlen;
char *buf, *hostpath = http_get_hostpath(hc);
- const char *title, *profile;
+ const char *title, *profile, *ticket;
size_t len;
if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
title = "TVHeadend Stream";
profile = http_arg_get(&hc->hc_req_args, "profile");
+ ticket = http_arg_get(&hc->hc_req_args, "ticket");
maxlen = strlen(remain) + strlen(title) + 256;
buf = alloca(maxlen);
+ pthread_mutex_lock(&global_lock);
+ if (ticket == NULL) {
+ snprintf(buf, maxlen, "/%s", remain);
+ ticket = access_ticket_create(buf, hc->hc_access);
+ }
snprintf(buf, maxlen, "\
#EXTM3U\r\n\
#EXTINF:-1,%s\r\n\
-%s/%s%s%s\r\n", title, hostpath, remain, profile ? "?profile=" : "", profile ?: "");
+%s/%s%s%s%s%s\r\n", title, hostpath, remain,
+ profile ? "?profile=" : "", profile ?: "",
+ profile ? "&ticket=" : "?ticket=", ticket);
+ pthread_mutex_unlock(&global_lock);
len = strlen(buf);
http_send_header(hc, 200, "audio/x-mpegurl", len, 0, NULL, 10, 0, NULL, NULL);
@@ -1436,7 +1457,7 @@ webui_init(int xspf)
http_path_add("/state", NULL, page_statedump, ACCESS_ADMIN);
- http_path_add("/stream", NULL, http_stream, ACCESS_STREAMING);
+ http_path_add("/stream", NULL, http_stream, ACCESS_ANONYMOUS);
http_path_add("/imagecache", NULL, page_imagecache, ACCESS_ANONYMOUS);
View
@@ -82,6 +82,7 @@ tvh_write(int fd, const void *buf, size_t len)
if (dispatch_clock > next)
break;
usleep(100);
+ dispatch_clock_update(NULL);
continue;
}
break;
View
@@ -7,7 +7,6 @@
VERBOSE = 'V' in os.environ and len(os.environ['V']) > 0
TVHDIR = os.path.realpath('.')
-PWD = os.path.realpath(os.environ['PWD'])
def info(fmt, *msg):
sys.stderr.write(" [INFO ] " + (fmt % msg) + '\n')
@@ -38,7 +37,7 @@ def url(fn):
f = utf8open(fn, 'r')
if fn[0] != '/':
- fn = os.path.join(PWD, fn)
+ fn = os.path.join(TVHDIR, fn)
fn = os.path.normpath(fn)
if VERBOSE:
info('css: %s', fn)
@@ -78,7 +77,7 @@ def url(fn):
def utf_check(fn):
f = utf8open(fn, 'r')
if fn[0] != '/':
- fn = os.path.join(PWD, fn)
+ fn = os.path.join(TVHDIR, fn)
fn = os.path.normpath(fn)
if VERBOSE:
info('utf-check: %s', fn)