diff --git a/Makefile b/Makefile
index 99f2127c..c6f685dc 100644
--- a/Makefile
+++ b/Makefile
@@ -329,6 +329,10 @@ SRCS-${CONFIG_CAPMT} += \
SRCS-${CONFIG_CONSTCW} += \
src/descrambler/constcw.c
+# TSDEBUGCW
+SRCS-${CONFIG_TSDEBUG} += \
+ src/descrambler/tsdebugcw.c
+
# FFdecsa
ifneq ($(CONFIG_DVBCSA),yes)
FFDECSA-$(CONFIG_CAPMT) = yes
diff --git a/configure b/configure
index 16b6c7a2..39dc448f 100755
--- a/configure
+++ b/configure
@@ -44,6 +44,7 @@ OPTIONS=(
"kqueue:no"
"dbus_1:auto"
"android:no"
+ "tsdebug:no"
)
#
@@ -472,6 +473,13 @@ if enabled_or_auto dbus_1; then
fi
fi
+#
+# TSDebug
+#
+if enabled_or_auto tsdebug; then
+ enable mpegts_dvb
+fi
+
# ###########################################################################
# Write config
diff --git a/src/descrambler/caclient.c b/src/descrambler/caclient.c
index 3e51537e..63fb2f26 100644
--- a/src/descrambler/caclient.c
+++ b/src/descrambler/caclient.c
@@ -296,6 +296,9 @@ caclient_start ( struct service *t )
if (cac->cac_enabled)
cac->cac_start(cac, t);
pthread_mutex_unlock(&caclients_mutex);
+#if ENABLE_TSDEBUG
+ tsdebugcw_service_start(t);
+#endif
}
void
@@ -344,6 +347,9 @@ caclient_init(void)
pthread_mutex_init(&caclients_mutex, NULL);
TAILQ_INIT(&caclients);
+#if ENABLE_TSDEBUG
+ tsdebugcw_init();
+#endif
if (!(c = hts_settings_load("caclient")))
return;
diff --git a/src/descrambler/caclient.h b/src/descrambler/caclient.h
index 6a6543ff..2c18f06e 100644
--- a/src/descrambler/caclient.h
+++ b/src/descrambler/caclient.h
@@ -75,8 +75,14 @@ const char *caclient_get_status(caclient_t *cac);
void caclient_init(void);
void caclient_done(void);
+void tsdebugcw_service_start(struct service *t);
+void tsdebugcw_new_keys(struct service *t, int type, uint8_t *odd, uint8_t *even);
+void tsdebugcw_go(void);
+void tsdebugcw_init(void);
+
caclient_t *cwc_create(void);
caclient_t *capmt_create(void);
caclient_t *constcw_create(void);
+caclient_t *tsdebugcw_create(void);
#endif /* __TVH_CACLIENT_H__ */
diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c
index d42683eb..a15aa647 100755
--- a/src/descrambler/descrambler.c
+++ b/src/descrambler/descrambler.c
@@ -252,6 +252,40 @@ descrambler_keys ( th_descrambler_t *td, int type,
fin:
pthread_mutex_unlock(&t->s_stream_mutex);
+#if ENABLE_TSDEBUG
+ if (j) {
+ tsdebug_packet_t *tp = malloc(sizeof(*tp));
+ uint16_t keylen = dr->dr_csa.csa_keylen;
+ uint16_t sid = ((mpegts_service_t *)td->td_service)->s_dvb_service_id;
+ uint32_t pos = 0, crc;
+ mpegts_mux_t *mm = ((mpegts_service_t *)td->td_service)->s_dvb_mux;
+ if (!mm->mm_active)
+ return;
+ pthread_mutex_lock(&mm->mm_active->mmi_input->mi_output_lock);
+ tp->pos = mm->mm_tsdebug_pos;
+ memset(tp->pkt, 0xff, sizeof(tp->pkt));
+ tp->pkt[pos++] = 0x47; /* sync byte */
+ tp->pkt[pos++] = 0x1f; /* PID MSB */
+ tp->pkt[pos++] = 0xff; /* PID LSB */
+ tp->pkt[pos++] = 0x00; /* CC */
+ memcpy(tp->pkt + pos, "TVHeadendDescramblerKeys", 24);
+ pos += 24;
+ tp->pkt[pos++] = type & 0xff;
+ tp->pkt[pos++] = keylen & 0xff;
+ tp->pkt[pos++] = (sid >> 8) & 0xff;
+ tp->pkt[pos++] = sid & 0xff;
+ memcpy(tp->pkt + pos, even, keylen);
+ memcpy(tp->pkt + pos + keylen, odd, keylen);
+ pos += 2 * keylen;
+ crc = tvh_crc32(tp->pkt, pos, 0x859aa5ba);
+ tp->pkt[pos++] = (crc >> 24) & 0xff;
+ tp->pkt[pos++] = (crc >> 16) & 0xff;
+ tp->pkt[pos++] = (crc >> 8) & 0xff;
+ tp->pkt[pos++] = crc & 0xff;
+ TAILQ_INSERT_HEAD(&mm->mm_tsdebug_packets, tp, link);
+ pthread_mutex_unlock(&mm->mm_active->mmi_input->mi_output_lock);
+ }
+#endif
}
static void
diff --git a/src/descrambler/tsdebugcw.c b/src/descrambler/tsdebugcw.c
new file mode 100644
index 00000000..c50230f5
--- /dev/null
+++ b/src/descrambler/tsdebugcw.c
@@ -0,0 +1,169 @@
+/*
+ * tvheadend, tsdebug code word interface
+ * Copyright (C) 2014 Jaroslav Kysela
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include "tvheadend.h"
+#include "caclient.h"
+#include "service.h"
+#include "input.h"
+
+/**
+ *
+ */
+typedef struct tsdebugcw_service {
+ th_descrambler_t;
+
+ int tdcw_type;
+ uint8_t tdcw_key_even[16]; /* DES or AES key */
+ uint8_t tdcw_key_odd [16]; /* DES or AES key */
+
+} tsdebugcw_service_t;
+
+typedef struct tsdebugcw_request {
+ TAILQ_ENTRY(tsdebugcw_request) link;
+ tsdebugcw_service_t *ct;
+} tsdebugcw_request_t;
+
+pthread_mutex_t tsdebugcw_mutex;
+TAILQ_HEAD(,tsdebugcw_request) tsdebugcw_requests;
+
+/*
+ *
+ */
+static int
+tsdebugcw_ecm_reset(th_descrambler_t *th)
+{
+ return 1;
+}
+
+/**
+ * s_stream_mutex is held
+ */
+static void
+tsdebugcw_service_destroy(th_descrambler_t *td)
+{
+ tsdebugcw_service_t *ct = (tsdebugcw_service_t *)td;
+ tsdebugcw_request_t *ctr, *ctrnext;
+
+ pthread_mutex_lock(&tsdebugcw_mutex);
+ for (ctr = TAILQ_FIRST(&tsdebugcw_requests); ctr; ctr = ctrnext) {
+ ctrnext = TAILQ_NEXT(ctr, link);
+ if (ctr->ct == ct) {
+ TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
+ free(ctr);
+ }
+ }
+ pthread_mutex_unlock(&tsdebugcw_mutex);
+
+ LIST_REMOVE(td, td_service_link);
+ free(ct->td_nicename);
+ free(ct);
+}
+
+/**
+ * global_lock is held. Not that we care about that, but either way, it is.
+ */
+void
+tsdebugcw_service_start(service_t *t)
+{
+ tsdebugcw_service_t *ct;
+ th_descrambler_t *td;
+ char buf[128];
+
+ extern const idclass_t mpegts_service_class;
+ if (!idnode_is_instance(&t->s_id, &mpegts_service_class))
+ return;
+
+ LIST_FOREACH(td, &t->s_descramblers, td_service_link)
+ if (td->td_stop == tsdebugcw_service_destroy)
+ break;
+ if (td)
+ return;
+
+ ct = calloc(1, sizeof(tsdebugcw_service_t));
+ td = (th_descrambler_t *)ct;
+ snprintf(buf, sizeof(buf), "tsdebugcw");
+ td->td_nicename = strdup(buf);
+ td->td_service = t;
+ td->td_stop = tsdebugcw_service_destroy;
+ td->td_ecm_reset = tsdebugcw_ecm_reset;
+ LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even)
+{
+ static char empty[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ th_descrambler_t *td;
+ tsdebugcw_service_t *ct;
+ tsdebugcw_request_t *ctr;
+ int keylen = type == DESCRAMBLER_AES ? 16 : 8;
+
+ LIST_FOREACH(td, &t->s_descramblers, td_service_link)
+ if (td->td_stop == tsdebugcw_service_destroy)
+ break;
+ if (!td)
+ return;
+ ct = (tsdebugcw_service_t *)td;
+ ct->tdcw_type = type;
+ if (memcmp(empty, odd, keylen))
+ memcpy(ct->tdcw_key_odd, odd, keylen);
+ if (memcmp(empty, even, keylen))
+ memcpy(ct->tdcw_key_even, even, keylen);
+ ctr = malloc(sizeof(*ctr));
+ ctr->ct = ct;
+ pthread_mutex_lock(&tsdebugcw_mutex);
+ TAILQ_INSERT_TAIL(&tsdebugcw_requests, ctr, link);
+ pthread_mutex_unlock(&tsdebugcw_mutex);
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_go(void)
+{
+ tsdebugcw_request_t *ctr;
+ tsdebugcw_service_t *ct;
+
+ while (1) {
+ pthread_mutex_lock(&tsdebugcw_mutex);
+ ctr = TAILQ_FIRST(&tsdebugcw_requests);
+ if (ctr)
+ TAILQ_REMOVE(&tsdebugcw_requests, ctr, link);
+ pthread_mutex_unlock(&tsdebugcw_mutex);
+ if (!ctr) break;
+ ct = ctr->ct;
+ descrambler_keys((th_descrambler_t *)ct, ct->tdcw_type,
+ ct->tdcw_key_odd, ct->tdcw_key_even);
+ free(ctr);
+ }
+}
+
+/*
+ *
+ */
+void
+tsdebugcw_init(void)
+{
+ pthread_mutex_init(&tsdebugcw_mutex, NULL);
+ TAILQ_INIT(&tsdebugcw_requests);
+}
diff --git a/src/input/mpegts.h b/src/input/mpegts.h
index c9676e17..a59b38b5 100644
--- a/src/input/mpegts.h
+++ b/src/input/mpegts.h
@@ -329,6 +329,12 @@ enum mpegts_mux_epg_flag
};
#define MM_EPG_LAST MM_EPG_ONLY_OPENTV_SKY_AUSAT
+typedef struct tsdebug_packet {
+ TAILQ_ENTRY(tsdebug_packet) link;
+ uint8_t pkt[188];
+ off_t pos;
+} tsdebug_packet_t;
+
/* Multiplex */
struct mpegts_mux
{
@@ -421,6 +427,16 @@ struct mpegts_mux
int mm_epg;
char *mm_charset;
int mm_pmt_06_ac3;
+
+ /*
+ * TSDEBUG
+ */
+#if ENABLE_TSDEBUG
+ int mm_tsdebug_fd;
+ int mm_tsdebug_fd2;
+ off_t mm_tsdebug_pos;
+ TAILQ_HEAD(, tsdebug_packet) mm_tsdebug_packets;
+#endif
};
/* Service */
@@ -803,6 +819,28 @@ mpegts_pid_t * mpegts_input_open_pid
void mpegts_input_close_pid
( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner );
+static inline void
+tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len)
+{
+#if ENABLE_TSDEBUG
+ ssize_t r = write(mm->mm_tsdebug_fd2, buf, len);
+ if (r != len && mm->mm_tsdebug_fd2 >= 0)
+ tvherror("tsdebug", "unable to write input data (%i)", errno);
+#endif
+}
+
+static inline ssize_t
+sbuf_tsdebug_read(mpegts_mux_t *mm, sbuf_t *sb, int fd)
+{
+#if ENABLE_TSDEBUG
+ ssize_t r = sbuf_read(sb, fd);
+ tsdebug_write(mm, sb->sb_data + sb->sb_ptr - r, r);
+ return r;
+#else
+ return sbuf_read(sb, fd);
+#endif
+}
+
void mpegts_table_dispatch
(const uint8_t *sec, size_t r, void *mt);
static inline void mpegts_table_grab
diff --git a/src/input/mpegts/iptv/iptv_http.c b/src/input/mpegts/iptv/iptv_http.c
index 26c5fef8..17dbabf2 100644
--- a/src/input/mpegts/iptv/iptv_http.c
+++ b/src/input/mpegts/iptv/iptv_http.c
@@ -47,6 +47,7 @@ iptv_http_data
pthread_mutex_lock(&iptv_lock);
+ tsdebug_write((mpegts_mux_t *)im, buf, len);
sbuf_append(&im->mm_iptv_buffer, buf, len);
if (len > 0)
diff --git a/src/input/mpegts/iptv/iptv_udp.c b/src/input/mpegts/iptv/iptv_udp.c
index 42ba3efa..feaa1e11 100644
--- a/src/input/mpegts/iptv/iptv_udp.c
+++ b/src/input/mpegts/iptv/iptv_udp.c
@@ -137,6 +137,7 @@ iptv_rtp_read ( iptv_mux_t *im )
/* Move data */
len -= hlen;
+ tsdebug_write((mpegts_mux_t *)im, rtp + hlen, len);
sbuf_append(&im->mm_iptv_buffer, rtp + hlen, len);
res += len;
}
diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c
index f9d39350..c3ed43f2 100644
--- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c
+++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c
@@ -856,7 +856,7 @@ linuxdvb_frontend_input_thread ( void *aux )
if (ev[0].data.fd != dvr) break;
/* Read */
- if ((n = sbuf_read(&sb, dvr)) < 0) {
+ if ((n = sbuf_tsdebug_read(mmi->mmi_mux, &sb, dvr)) < 0) {
if (ERRNO_AGAIN(errno))
continue;
if (errno == EOVERFLOW) {
diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c
index 7b95cd1d..601e3b90 100644
--- a/src/input/mpegts/mpegts_input.c
+++ b/src/input/mpegts/mpegts_input.c
@@ -29,6 +29,9 @@
#include
#include
+#include
+#include
+
static void
mpegts_input_del_network ( mpegts_network_link_t *mnl );
@@ -475,6 +478,34 @@ static void
mpegts_input_started_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
+#if ENABLE_TSDEBUG
+ extern char *tvheadend_tsdebug;
+ static const char *tmpdir = "/tmp/tvheadend.tsdebug/";
+ char buf[128];
+ char path[PATH_MAX];
+ struct stat st;
+ if (!tvheadend_tsdebug && !stat(tmpdir, &st) && (st.st_mode & S_IFDIR) != 0)
+ tvheadend_tsdebug = (char *)tmpdir;
+ if (tvheadend_tsdebug && !strcmp(tvheadend_tsdebug, tmpdir) && stat(tmpdir, &st))
+ tvheadend_tsdebug = NULL;
+ if (tvheadend_tsdebug) {
+ mpegts_mux_nice_name(mmi->mmi_mux, buf, sizeof(buf));
+ snprintf(path, sizeof(path), "%s/%s-%li-%p-mux.ts", tvheadend_tsdebug,
+ buf, (long)dispatch_clock, mi);
+ mmi->mmi_mux->mm_tsdebug_fd = tvh_open(path, O_WRONLY | O_CREAT, 0600);
+ if (mmi->mmi_mux->mm_tsdebug_fd < 0)
+ tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno);
+ snprintf(path, sizeof(path), "%s/%s-%li-%p-input.ts", tvheadend_tsdebug,
+ buf, (long)dispatch_clock, mi);
+ mmi->mmi_mux->mm_tsdebug_fd2 = tvh_open(path, O_WRONLY | O_CREAT, 0600);
+ if (mmi->mmi_mux->mm_tsdebug_fd2 < 0)
+ tvherror("tsdebug", "unable to create file '%s' (%i)", path, errno);
+ } else {
+ mmi->mmi_mux->mm_tsdebug_fd = -1;
+ mmi->mmi_mux->mm_tsdebug_fd2 = -1;
+ }
+#endif
+
/* Deliver first TS packets as fast as possible */
mi->mi_last_dispatch = 0;
/* Wait for first TS packet */
@@ -532,6 +563,19 @@ mpegts_input_stopped_mux
}
notify_reload("input_status");
mpegts_input_dbus_notify(mi, 0);
+
+#if ENABLE_TSDEBUG
+ tsdebug_packet_t *tp;
+ close(mmi->mmi_mux->mm_tsdebug_fd);
+ close(mmi->mmi_mux->mm_tsdebug_fd2);
+ mmi->mmi_mux->mm_tsdebug_fd = -1;
+ mmi->mmi_mux->mm_tsdebug_fd2 = -1;
+ mmi->mmi_mux->mm_tsdebug_pos = 0;
+ while ((tp = TAILQ_FIRST(&mmi->mmi_mux->mm_tsdebug_packets)) != NULL) {
+ TAILQ_REMOVE(&mmi->mmi_mux->mm_tsdebug_packets, tp, link);
+ free(tp);
+ }
+#endif
}
static int
@@ -727,6 +771,37 @@ mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm )
pthread_mutex_unlock(&mm->mm_tables_lock);
}
+#if ENABLE_TSDEBUG
+static void
+tsdebug_check_tspkt( mpegts_mux_t *mm, uint8_t *pkt )
+{
+ void tsdebugcw_new_keys(service_t *t, int type, uint8_t *odd, uint8_t *even);
+ uint32_t pos, type, keylen, sid, crc;
+ mpegts_service_t *t;
+
+ if (memcmp(pkt + 4, "TVHeadendDescramblerKeys", 24))
+ return;
+ pos = 4 + 24;
+ type = pkt[pos + 0];
+ keylen = pkt[pos + 1];
+ sid = (pkt[pos + 2] << 8) | pkt[pos + 3];
+ pos += 4 + 2 * keylen;
+ if (pos > 184)
+ return;
+ crc = (pkt[pos + 0] << 24) | (pkt[pos + 1] << 16) |
+ (pkt[pos + 2] << 8) | pkt[pos + 3];
+ if (crc != tvh_crc32(pkt, pos, 0x859aa5ba))
+ return;
+ LIST_FOREACH(t, &mm->mm_services, s_dvb_mux_link)
+ if (t->s_dvb_service_id == sid) break;
+ if (!t)
+ return;
+ pos = 4 + 24 + 4;
+ tvhdebug("descrambler", "Keys from MPEG-TS source (PID 0x1FFF)!");
+ tsdebugcw_new_keys((service_t *)t, type, pkt + pos, pkt + pos + keylen);
+}
+#endif
+
static void
mpegts_input_process
( mpegts_input_t *mi, mpegts_packet_t *mpkt )
@@ -744,6 +819,9 @@ mpegts_input_process
mpegts_mux_t *mm = mpkt->mp_mux;
mpegts_mux_instance_t *mmi;
mpegts_pid_t *last_mp = NULL;
+#if ENABLE_TSDEBUG
+ off_t tsdebug_pos = mm->mm_tsdebug_pos;
+#endif
if (mm == NULL || (mmi = mm->mm_active) == NULL)
return;
@@ -767,7 +845,12 @@ mpegts_input_process
pid &= 0x1FFF;
/* Ignore NUL packets */
- if (pid == 0x1FFF) goto done;
+ if (pid == 0x1FFF) {
+#if ENABLE_TSDEBUG
+ tsdebug_check_tspkt(mm, tsb);
+#endif
+ goto done;
+ }
/* Remove in future or move it outside this loop */
lock_assert(&mi->mi_output_lock);
@@ -841,11 +924,15 @@ mpegts_input_process
done:
tsb += 188;
+#if ENABLE_TSDEBUG
+ mm->mm_tsdebug_pos += 188;
+#endif
}
/* Raw stream */
if (tsb != mpkt->mp_data &&
LIST_FIRST(&mmi->mmi_streaming_pad.sp_targets) != NULL) {
+
streaming_message_t sm;
pktbuf_t *pb = pktbuf_alloc(mpkt->mp_data, tsb - mpkt->mp_data);
memset(&sm, 0, sizeof(sm));
@@ -854,6 +941,27 @@ done:
streaming_pad_deliver(&mmi->mmi_streaming_pad, streaming_msg_clone(&sm));
pktbuf_ref_dec(pb);
}
+#if ENABLE_TSDEBUG
+ {
+ tsdebug_packet_t *tp, *tp_next;
+ off_t pos = 0;
+ size_t used = tsb - mpkt->mp_data;
+ for (tp = TAILQ_FIRST(&mm->mm_tsdebug_packets); tp; tp = tp_next) {
+ tp_next = TAILQ_NEXT(tp, link);
+ assert((tp->pos % 188) == 0);
+ assert(tp->pos >= tsdebug_pos && tp->pos < tsdebug_pos + used);
+ if (mm->mm_tsdebug_fd >= 0) {
+ tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, tp->pos - tsdebug_pos - pos);
+ tvh_write(mm->mm_tsdebug_fd, tp->pkt, 188);
+ }
+ pos = tp->pos - tsdebug_pos;
+ TAILQ_REMOVE(&mm->mm_tsdebug_packets, tp, link);
+ free(tp);
+ }
+ if (pos < used && mm->mm_tsdebug_fd >= 0)
+ tvh_write(mm->mm_tsdebug_fd, mpkt->mp_data + pos, used - pos);
+ }
+#endif
/* Wake table */
if (table_wakeup)
@@ -888,6 +996,14 @@ mpegts_input_thread ( void * p )
/* Cleanup */
free(mp);
+
+#if ENABLE_TSDEBUG
+ {
+ extern void tsdebugcw_go(void);
+ tsdebugcw_go();
+ }
+#endif
+
pthread_mutex_lock(&mi->mi_input_lock);
}
diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c
index c76a8fe6..d10480b8 100644
--- a/src/input/mpegts/satip/satip_frontend.c
+++ b/src/input/mpegts/satip/satip_frontend.c
@@ -1228,6 +1228,7 @@ fast_exit:
(uint32_t)((uint16_t)nseq-(uint16_t)(seq+1));
seq = nseq;
/* Process */
+ tsdebug_write((mpegts_mux_t *)lm, p + pos, c - pos);
sbuf_append(&sb, p + pos, c - pos);
}
mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi,
diff --git a/src/input/mpegts/tsfile/tsfile_input.c b/src/input/mpegts/tsfile/tsfile_input.c
index bced0a2a..f4433729 100644
--- a/src/input/mpegts/tsfile/tsfile_input.c
+++ b/src/input/mpegts/tsfile/tsfile_input.c
@@ -214,8 +214,8 @@ tsfile_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *t )
/* Check file is accessible */
if (lstat(mmi->mmi_tsfile_path, &st)) {
- tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat %s",
- mmi, mmi->mmi_tsfile_path);
+ tvhlog(LOG_ERR, "tsfile", "mmi %p could not stat '%s' (%i)",
+ mmi, mmi->mmi_tsfile_path, errno);
mmi->mmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
}
diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c
index aa800878..fbe90a08 100644
--- a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c
+++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c
@@ -188,7 +188,7 @@ tvhdhomerun_frontend_input_thread ( void *aux )
if (nfds < 1) continue;
if (ev[0].data.fd != sockfd) break;
- if((r = sbuf_read(&sb, sockfd)) < 0) {
+ if((r = sbuf_tsdebug_read(mmi->mmi_mux, &sb, sockfd)) < 0) {
/* whoopsy */
if(ERRNO_AGAIN(errno))
continue;
diff --git a/src/main.c b/src/main.c
index 3b4e8d72..c718e39f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -132,6 +132,7 @@ int tvheadend_webui_port;
int tvheadend_webui_debug;
int tvheadend_htsp_port;
int tvheadend_htsp_port_extra;
+const char *tvheadend_tsdebug;
const char *tvheadend_cwd;
const char *tvheadend_webroot;
const tvh_caps_t tvheadend_capabilities[] = {
@@ -469,7 +470,9 @@ main(int argc, char **argv)
opt_fileline = 0,
opt_threadid = 0,
opt_ipv6 = 0,
+#if ENABLE_TSFILE
opt_tsfile_tuner = 0,
+#endif
opt_dump = 0,
opt_xspf = 0,
opt_dbus = 0,
@@ -560,9 +563,16 @@ main(int argc, char **argv)
OPT_STR, &opt_subscribe },
+#if ENABLE_TSFILE || ENABLE_TSDEBUG
{ 0, NULL, "TODO: testing", OPT_BOOL, NULL },
+#if ENABLE_TSFILE
{ 0, "tsfile_tuners", "Number of tsfile tuners", OPT_INT, &opt_tsfile_tuner },
{ 0, "tsfile", "tsfile input (mux file)", OPT_STR_LIST, &opt_tsfile },
+#endif
+#if ENABLE_TSDEBUG
+ { 0, "tsdebug", "Output directory for tsdebug", OPT_STR, &tvheadend_tsdebug },
+#endif
+#endif
};
@@ -957,7 +967,9 @@ main(int argc, char **argv)
if(opt_fork)
unlink(opt_pidpath);
+#if ENABLE_TSFILE
free(opt_tsfile.str);
+#endif
free(opt_satip_xml.str);
/* OpenSSL - welcome to the "cleanup" hell */