Fix #1643 - dvb: alter the way we handle dvb tuning

This ensures that demux filters are not installed until after tuning
is locked. This should resolve most stale data issues.
(cherry picked from commit ddc466c1bf)
This commit is contained in:
Adam Sutton 2013-03-13 19:36:59 +00:00
parent 191b143f65
commit 02dc5e5f37
4 changed files with 144 additions and 75 deletions

View file

@ -29,6 +29,12 @@ struct service;
struct th_dvb_table;
struct th_dvb_mux_instance;
#define TDA_OPT_FE 0x1
#define TDA_OPT_DVR 0x2
#define TDA_OPT_DMX 0x4
#define TDA_OPT_PWR 0x8
#define TDA_OPT_ALL (TDA_OPT_FE | TDA_OPT_DVR | TDA_OPT_DMX | TDA_OPT_PWR)
#define DVB_VER_INT(maj,min) (((maj) << 16) + (min))
#define DVB_VER_ATLEAST(maj, min) \
@ -202,6 +208,8 @@ typedef struct th_dvb_adapter {
uint32_t tda_enabled;
int tda_locked;
const char *tda_rootpath;
char *tda_identifier;
uint32_t tda_autodiscovery;
@ -342,11 +350,9 @@ void dvb_adapter_init(uint32_t adapter_mask, const char *rawfile);
void dvb_adapter_mux_scanner(void *aux);
void dvb_adapter_start (th_dvb_adapter_t *tda);
void dvb_adapter_start (th_dvb_adapter_t *tda, int opt);
void dvb_adapter_stop (th_dvb_adapter_t *tda);
void dvb_adapter_stop_dvr (th_dvb_adapter_t *tda);
void dvb_adapter_stop (th_dvb_adapter_t *tda, int opt);
void dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s);

View file

@ -141,7 +141,7 @@ dvb_adapter_set_enabled(th_dvb_adapter_t *tda, int on)
gtimer_disarm(&tda->tda_mux_scanner_timer);
if (tda->tda_mux_current)
dvb_fe_stop(tda->tda_mux_current, 0);
dvb_adapter_stop(tda);
dvb_adapter_stop(tda, TDA_OPT_ALL);
} else {
tda_init(tda);
}
@ -692,22 +692,26 @@ static void tda_init (th_dvb_adapter_t *tda)
*
*/
void
dvb_adapter_start ( th_dvb_adapter_t *tda )
dvb_adapter_start ( th_dvb_adapter_t *tda, int opt )
{
if(tda->tda_enabled == 0) {
tvhlog(LOG_INFO, "dvb", "Adapter \"%s\" cannot be started - it's disabled", tda->tda_displayname);
return;
}
/* Default to ALL */
if (!opt)
opt = TDA_OPT_ALL;
/* Open front end */
if (tda->tda_fe_fd == -1) {
if ((opt & TDA_OPT_FE) && (tda->tda_fe_fd == -1)) {
tda->tda_fe_fd = tvh_open(tda->tda_fe_path, O_RDWR | O_NONBLOCK, 0);
if (tda->tda_fe_fd == -1) return;
tvhlog(LOG_DEBUG, "dvb", "%s opened frontend %s", tda->tda_rootpath, tda->tda_fe_path);
}
/* Start DVR thread */
if (tda->tda_dvr_pipe.rd == -1) {
if ((opt & TDA_OPT_DVR) && (tda->tda_dvr_pipe.rd == -1)) {
int err = tvh_pipe(O_NONBLOCK, &tda->tda_dvr_pipe);
assert(err != -1);
pthread_create(&tda->tda_dvr_thread, NULL, dvb_adapter_input_dvr, tda);
@ -716,10 +720,14 @@ dvb_adapter_start ( th_dvb_adapter_t *tda )
}
void
dvb_adapter_stop_dvr ( th_dvb_adapter_t *tda )
dvb_adapter_stop ( th_dvb_adapter_t *tda, int opt )
{
/* Poweroff */
if (opt & TDA_OPT_PWR)
dvb_adapter_poweroff(tda);
/* Stop DVR thread */
if (tda->tda_dvr_pipe.rd != -1) {
if ((opt & TDA_OPT_DVR) && (tda->tda_dvr_pipe.rd != -1)) {
tvhlog(LOG_DEBUG, "dvb", "%s stopping thread", tda->tda_rootpath);
int err = tvh_write(tda->tda_dvr_pipe.wr, "", 1);
assert(!err);
@ -729,26 +737,17 @@ dvb_adapter_stop_dvr ( th_dvb_adapter_t *tda )
tda->tda_dvr_pipe.rd = -1;
tvhlog(LOG_DEBUG, "dvb", "%s stopped thread", tda->tda_rootpath);
}
}
void
dvb_adapter_stop ( th_dvb_adapter_t *tda )
{
/* Poweroff */
dvb_adapter_poweroff(tda);
/* Don't stop/close */
/* Don't close FE */
if (!tda->tda_idleclose && tda->tda_enabled) return;
/* Close front end */
if (tda->tda_fe_fd != -1) {
if ((opt & TDA_OPT_FE) && (tda->tda_fe_fd != -1)) {
tvhlog(LOG_DEBUG, "dvb", "%s closing frontend", tda->tda_rootpath);
close(tda->tda_fe_fd);
tda->tda_fe_fd = -1;
}
dvb_adapter_stop_dvr(tda);
dvb_adapter_notify(tda);
}
@ -980,8 +979,39 @@ dvb_adapter_clean(th_dvb_adapter_t *tda)
service_remove_subscriber(t, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN);
}
/**
* Install RAW PES filter
*/
static int
dvb_adapter_raw_filter(th_dvb_adapter_t *tda)
{
int dmx = -1;
struct dmx_pes_filter_params dmx_param;
dmx = tvh_open(tda->tda_demux_path, O_RDWR, 0);
if(dmx == -1) {
tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s",
tda->tda_demux_path, strerror(errno));
return -1;
}
memset(&dmx_param, 0, sizeof(dmx_param));
dmx_param.pid = 0x2000;
dmx_param.input = DMX_IN_FRONTEND;
dmx_param.output = DMX_OUT_TS_TAP;
dmx_param.pes_type = DMX_PES_OTHER;
dmx_param.flags = DMX_IMMEDIATE_START;
if(ioctl(dmx, DMX_SET_PES_FILTER, &dmx_param) == -1) {
tvhlog(LOG_ERR, "dvb",
"Unable to configure demuxer \"%s\" for all PIDs -- %s",
tda->tda_demux_path, strerror(errno));
close(dmx);
return -1;
}
return dmx;
}
/**
*
@ -990,54 +1020,18 @@ static void *
dvb_adapter_input_dvr(void *aux)
{
th_dvb_adapter_t *tda = aux;
int fd, i, r, c, efd, nfds, dmx = -1;
th_dvb_mux_instance_t *tdmi;
int fd = -1, i, r, c, efd, nfds, dmx = -1;
uint8_t tsb[188 * 10];
service_t *t;
struct epoll_event ev;
fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0);
if(fd == -1) {
tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s", tda->tda_dvr_path, strerror(errno));
return NULL;
}
if(tda->tda_rawmode) {
// Receive unfiltered raw transport stream
dmx = tvh_open(tda->tda_demux_path, O_RDWR, 0);
if(dmx == -1) {
tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s",
tda->tda_demux_path, strerror(errno));
close(fd);
return NULL;
}
struct dmx_pes_filter_params dmx_param;
memset(&dmx_param, 0, sizeof(dmx_param));
dmx_param.pid = 0x2000;
dmx_param.input = DMX_IN_FRONTEND;
dmx_param.output = DMX_OUT_TS_TAP;
dmx_param.pes_type = DMX_PES_OTHER;
dmx_param.flags = DMX_IMMEDIATE_START;
if(ioctl(dmx, DMX_SET_PES_FILTER, &dmx_param)) {
tvhlog(LOG_ERR, "dvb",
"Unable to configure demuxer \"%s\" for all PIDs -- %s",
tda->tda_demux_path, strerror(errno));
close(dmx);
close(fd);
return NULL;
}
}
int delay = 10, locked = 0;
fe_status_t festat;
/* Create poll */
efd = epoll_create(2);
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
ev.data.fd = tda->tda_dvr_pipe.rd;
epoll_ctl(efd, EPOLL_CTL_ADD, tda->tda_dvr_pipe.rd, &ev);
@ -1045,10 +1039,65 @@ dvb_adapter_input_dvr(void *aux)
while(1) {
/* Wait for input */
nfds = epoll_wait(efd, &ev, 1, -1);
if (nfds < 1) continue;
if (ev.data.fd != fd) break;
nfds = epoll_wait(efd, &ev, 1, delay);
/* Exit */
if ((nfds > 0) && (ev.data.fd != fd)) break;
/* Check for lock */
if (!locked) {
if (ioctl(tda->tda_fe_fd, FE_READ_STATUS, &festat))
continue;
if (!(festat & FE_HAS_LOCK))
continue;
/* Open DVR */
fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0);
if (fd == -1) {
tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s",
tda->tda_dvr_path, strerror(errno));
break;
}
ev.data.fd = fd;
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
/* Note: table handlers must be installed with global lock */
pthread_mutex_lock(&global_lock);
tda->tda_locked = locked = 1;
delay = -1;
if ((tdmi = tda->tda_mux_current)) {
/* Install table handlers */
dvb_table_add_default(tdmi);
epggrab_mux_start(tdmi);
/* Raw filter */
if(tda->tda_rawmode)
dmx = dvb_adapter_raw_filter(tda);
/* Service filters */
pthread_mutex_lock(&tda->tda_delivery_mutex);
LIST_FOREACH(t, &tda->tda_transports, s_active_link) {
if (t->s_dvb_mux_instance == tdmi) {
tda->tda_open_service(tda, t);
dvb_table_add_pmt(tdmi, t->s_pmt_pid);
}
}
pthread_mutex_unlock(&tda->tda_delivery_mutex);
}
pthread_mutex_unlock(&global_lock);
/* Error */
if (tda->tda_rawmode && (dmx == -1)) {
tvhlog(LOG_ALERT, "dvb", "Unable to install raw mux filter");
break;
}
}
/* No data */
if (nfds < 1) continue;
/* Read data */
c = read(fd, tsb+r, sizeof(tsb)-r);
if (c < 0) {
if (errno == EAGAIN || errno == EINTR)

View file

@ -273,6 +273,7 @@ void
dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
dvb_table_feed_t *dtf;
lock_assert(&global_lock);
@ -285,8 +286,13 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune)
dvb_mux_save(tdmi);
}
dvb_adapter_stop_dvr(tda);
dvb_adapter_stop(tda, TDA_OPT_DVR);
pthread_mutex_lock(&tda->tda_delivery_mutex);
while((dtf = TAILQ_FIRST(&tda->tda_table_feed)))
TAILQ_REMOVE(&tda->tda_table_feed, dtf, dtf_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
dvb_table_flush_all(tdmi);
tda->tda_locked = 0;
assert(tdmi->tdmi_scan_queue == NULL);
@ -300,7 +306,7 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune)
if (!retune) {
gtimer_disarm(&tda->tda_fe_monitor_timer);
dvb_adapter_stop(tda);
dvb_adapter_stop(tda, TDA_OPT_ALL);
}
}
@ -421,9 +427,11 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
char buf[256];
int r;
lock_assert(&global_lock);
if(tda->tda_enabled == 0)
return SM_CODE_TUNING_FAILED;
if(tda->tda_mux_current == tdmi)
return 0;
@ -434,7 +442,8 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
if(tda->tda_mux_current != NULL)
dvb_fe_stop(tda->tda_mux_current, 1);
dvb_adapter_start(tda);
dvb_adapter_start(tda, TDA_OPT_FE | TDA_OPT_PWR);
if(tda->tda_type == FE_QPSK) {
@ -486,7 +495,6 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
tda->tda_fe_monitor_hold = 4;
#if DVB_API_VERSION >= 5
if (tda->tda_type == FE_QPSK) {
tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning via s2api to \"%s\" (%d, %d Baud, "
@ -517,15 +525,18 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
if (errno == EINVAL)
dvb_mux_set_enable(tdmi, 0);
return SM_CODE_TUNING_FAILED;
}
}
tda->tda_mux_current = tdmi;
dvb_adapter_start(tda, TDA_OPT_ALL);
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
#if 0
dvb_table_add_default(tdmi);
epggrab_mux_start(tdmi);
#endif
dvb_adapter_notify(tda);
return 0;

View file

@ -86,18 +86,21 @@ dvb_service_start(service_t *t, unsigned int weight, int force_start)
dvb_adapter_clean(tda);
}
r = dvb_fe_tune(t->s_dvb_mux_instance, "Transport start");
pthread_mutex_lock(&tda->tda_delivery_mutex);
r = dvb_fe_tune(t->s_dvb_mux_instance, "Transport start");
if(!r)
LIST_INSERT_HEAD(&tda->tda_transports, t, s_active_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
if(!r)
tda->tda_open_service(tda, t);
if (tda->tda_locked) {
if(!r)
tda->tda_open_service(tda, t);
dvb_table_add_pmt(t->s_dvb_mux_instance, t->s_pmt_pid);
dvb_table_add_pmt(t->s_dvb_mux_instance, t->s_pmt_pid);
}
return r;
}