mpegts: starting to tidy up input class

This commit is contained in:
Adam Sutton 2013-06-01 20:51:10 +01:00
parent 8e6d14b635
commit f1eb285c8f
4 changed files with 229 additions and 160 deletions

View file

@ -381,15 +381,14 @@ struct mpegts_input
/*
* Functions
*/
int (*mi_is_enabled) (mpegts_input_t*);
void (*mi_display_name) (mpegts_input_t*, char *buf, size_t len);
int (*mi_is_free) (mpegts_input_t*);
int (*mi_current_weight) (mpegts_input_t*);
int (*mi_start_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_stop_mux) (mpegts_input_t*,mpegts_mux_instance_t*);
void (*mi_open_service) (mpegts_input_t*,mpegts_service_t*);
void (*mi_close_service) (mpegts_input_t*,mpegts_service_t*);
int (*mi_is_free) (mpegts_input_t*);
int (*mi_current_weight) (mpegts_input_t*);
int (*mi_is_enabled) (mpegts_input_t*);
void (*mi_display_name) (mpegts_input_t*, char *buf, size_t len);
};
#endif /* __TVH_MPEGTS_H__ */
@ -399,16 +398,15 @@ struct mpegts_input
* ***************************************************************************/
mpegts_input_t *mpegts_input_create0
( mpegts_input_t *mi, const idclass_t *idc, const char *uuid );
( mpegts_input_t *mi, const idclass_t *idc, const char *uuid, htsmsg_t *c );
#define mpegts_input_create(t, u)\
(struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), &t##_class, u)
#define mpegts_input_create(t, u, c)\
(struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), &t##_class, u, c)
#define mpegts_input_create1(u)\
#define mpegts_input_create1(u, c)\
mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
&mpegts_input_class, u)
&mpegts_input_class, u, c)
mpegts_network_t *mpegts_network_create0
( mpegts_network_t *mn, const idclass_t *idc, const char *uuid,
const char *name, htsmsg_t *conf );
@ -456,7 +454,7 @@ int mpegts_mux_set_crid_authority ( mpegts_mux_t *mm, const char *defauth );
size_t mpegts_input_recv_packets
(mpegts_input_t *mi, mpegts_mux_instance_t *mmi, uint8_t *tsb, size_t len,
int64_t *pcr, uint16_t *pcr_pid);
int64_t *pcr, uint16_t *pcr_pid, const char *name);
void *mpegts_input_table_thread ( void *aux );
@ -464,6 +462,8 @@ int mpegts_input_is_free ( mpegts_input_t *mi );
int mpegts_input_current_weight ( mpegts_input_t *mi );
void mpegts_input_save ( mpegts_input_t *mi, htsmsg_t *c );
void mpegts_table_dispatch
(const uint8_t *sec, size_t r, void *mt);
void mpegts_table_release

View file

@ -29,8 +29,16 @@
#include <assert.h>
#include <linux/dvb/dmx.h>
static int
linuxdvb_frontend_tune
( linuxdvb_frontend_t *lfe, linuxdvb_mux_t *lm );
static void
linuxdvb_frontend_monitor ( void *aux );
static void *
linuxdvb_frontend_input_thread ( void *aux );
/* **************************************************************************
* Class definitions
* Class definition
* *************************************************************************/
extern const idclass_t linuxdvb_hardware_class;
@ -67,6 +75,8 @@ const idclass_t linuxdvb_frontend_class =
PT_STR, linuxdvb_frontend_t, lfe_dvr_path, 1) },
{ PROPDEF2("dmx_path", "Demux Path",
PT_STR, linuxdvb_frontend_t, lfe_dmx_path, 1) },
{ PROPDEF2("number", "FE Number",
PT_INT, linuxdvb_frontend_t, lfe_number, 1) },
{}
}
};
@ -112,24 +122,9 @@ const idclass_t linuxdvb_frontend_atsc_class =
};
/* **************************************************************************
* Frontend
* Class methods
* *************************************************************************/
void
linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m )
{
htsmsg_add_u32(m, "number", lfe->lfe_number);
htsmsg_add_str(m, "type", dvb_type2str(lfe->lfe_info.type));
if (lfe->mi_network)
htsmsg_add_str(m, "network", idnode_uuid_as_str(&lfe->mi_network->mn_id));
if (lfe->lfe_fe_path)
htsmsg_add_str(m, "fe_path", lfe->lfe_fe_path);
if (lfe->lfe_dmx_path)
htsmsg_add_str(m, "dmx_path", lfe->lfe_dmx_path);
if (lfe->lfe_dvr_path)
htsmsg_add_str(m, "dvr_path", lfe->lfe_dvr_path);
}
static int
linuxdvb_frontend_is_enabled ( mpegts_input_t *mi )
{
@ -185,12 +180,81 @@ linuxdvb_frontend_stop_mux
}
}
static int
linuxdvb_frontend_start_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
int r;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
mpegts_mux_instance_t *cur = LIST_FIRST(&mi->mi_mux_active);
tvhtrace("mpegts", "linuxdvb_frontend_start_mux(%p, %p)", mi, mmi);
// Not sure if this is right place?
/* Currently active */
if (cur != NULL) {
/* Already tuned */
if (mmi == cur)
return 0;
/* Stop current */
cur->mmi_mux->mm_stop(cur->mmi_mux);
}
assert(LIST_FIRST(&mi->mi_mux_active) == NULL);
/* Open FE */
if (lfe->lfe_fe_fd <= 0) {
lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0);
if (lfe->lfe_fe_fd <= 0) {
return SM_CODE_TUNING_FAILED;
}
}
/* Tune */
r = linuxdvb_frontend_tune(lfe, (linuxdvb_mux_t*)mmi->mmi_mux);
/* Failed */
if (r != 0) {
tvhlog(LOG_ERR, "linuxdvb", "'%s' failed to tune '%s' error %s",
lfe->lfe_fe_path, "TODO", strerror(errno));
if (errno == EINVAL)
mmi->mmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
}
/* Start monitor */
time(&lfe->lfe_monitor);
lfe->lfe_monitor += 4;
gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50);
/* Send alert */
// TODO: should this be moved elsewhere?
return r;
}
static void
linuxdvb_frontend_open_service
( mpegts_input_t *mi, mpegts_service_t *ms )
{
}
static void
linuxdvb_frontend_close_service
( mpegts_input_t *mi, mpegts_service_t *ms )
{
}
/* **************************************************************************
* Data processing
* *************************************************************************/
static void *
linuxdvb_frontend_input_thread ( void *aux )
{
linuxdvb_frontend_t *lfe = aux;
mpegts_mux_instance_t *mmi;
int dmx = -1, dvr = -1;
char buf[256];
uint8_t tsb[18800];
int pos = 0, nfds, efd;
ssize_t c;
@ -199,6 +263,7 @@ linuxdvb_frontend_input_thread ( void *aux )
/* Get MMI */
pthread_mutex_lock(&global_lock);
lfe->mi_display_name((mpegts_input_t*)lfe, buf, sizeof(buf));
mmi = LIST_FIRST(&lfe->mi_mux_active);
pthread_mutex_unlock(&global_lock);
if (mmi == NULL) return NULL;
@ -206,7 +271,7 @@ linuxdvb_frontend_input_thread ( void *aux )
/* Open DMX */
dmx = tvh_open(lfe->lfe_dmx_path, O_RDWR, 0);
if (dmx < 0) {
tvhlog(LOG_ERR, "linuxdvb", "failed to open %s", lfe->lfe_dmx_path);
tvherror("linuxdvb", "%s - failed to open %s", buf, lfe->lfe_dmx_path);
return NULL;
}
memset(&dmx_param, 0, sizeof(dmx_param));
@ -227,7 +292,7 @@ linuxdvb_frontend_input_thread ( void *aux )
dvr = tvh_open(lfe->lfe_dvr_path, O_RDONLY | O_NONBLOCK, 0);
if (dvr < 0) {
close(dmx);
tvhlog(LOG_ERR, "linuxdvb", "failed to open %s", lfe->lfe_dvr_path);
tvherror("linuxdvb", "%s - failed to open %s", buf, lfe->lfe_dvr_path);
return NULL;
}
@ -253,20 +318,19 @@ linuxdvb_frontend_input_thread ( void *aux )
if ((errno == EAGAIN) || (errno == EINTR))
continue;
if (errno == EOVERFLOW) {
tvhlog(LOG_WARNING, "linuxdvb", "read() EOVERFLOW");
tvhlog(LOG_WARNING, "linuxdvb", "%s - read() EOVERFLOW", buf);
continue;
}
tvhlog(LOG_ERR, "linuxdvb", "read() error %d (%s)",
errno, strerror(errno));
tvhlog(LOG_ERR, "linuxdvb", "%s - read() error %d (%s)",
buf, errno, strerror(errno));
break;
}
/* Process */
pos = mpegts_input_recv_packets((mpegts_input_t*)lfe, mmi, tsb, c,
NULL, NULL);
NULL, NULL, buf);
}
//exit:
close(dmx);
close(dvr);
return NULL;
@ -372,75 +436,14 @@ linuxdvb_frontend_tune
#endif
static int
linuxdvb_frontend_start_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
int r;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
mpegts_mux_instance_t *cur = LIST_FIRST(&mi->mi_mux_active);
tvhtrace("mpegts", "linuxdvb_frontend_start_mux(%p, %p)", mi, mmi);
// Not sure if this is right place?
/* Currently active */
if (cur != NULL) {
/* Already tuned */
if (mmi == cur)
return 0;
/* Stop current */
cur->mmi_mux->mm_stop(cur->mmi_mux);
}
assert(LIST_FIRST(&mi->mi_mux_active) == NULL);
/* Open FE */
if (lfe->lfe_fe_fd <= 0) {
lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0);
if (lfe->lfe_fe_fd <= 0) {
return SM_CODE_TUNING_FAILED;
}
}
/* Tune */
r = linuxdvb_frontend_tune(lfe, (linuxdvb_mux_t*)mmi->mmi_mux);
/* Failed */
if (r != 0) {
tvhlog(LOG_ERR, "linuxdvb", "'%s' failed to tune '%s' error %s",
lfe->lfe_fe_path, "TODO", strerror(errno));
if (errno == EINVAL)
mmi->mmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
}
/* Start monitor */
time(&lfe->lfe_monitor);
lfe->lfe_monitor += 4;
gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50);
/* Send alert */
// TODO: should this be moved elsewhere?
return r;
}
static void
linuxdvb_frontend_open_service
( mpegts_input_t *mi, mpegts_service_t *ms )
{
}
static void
linuxdvb_frontend_close_service
( mpegts_input_t *mi, mpegts_service_t *ms )
{
}
/* **************************************************************************
* Creation/Config
* *************************************************************************/
linuxdvb_frontend_t *
linuxdvb_frontend_create0
( linuxdvb_adapter_t *la, const char *uuid, htsmsg_t *conf, fe_type_t type )
{
uint32_t u32;
const char *str;
const idclass_t *idc;
pthread_t tid;
@ -462,18 +465,19 @@ linuxdvb_frontend_create0
else if (type == FE_ATSC)
idc = &linuxdvb_frontend_atsc_class;
else {
tvhlog(LOG_ERR, "linuxdvb", "unknown FE type %d", type);
tvherror("linuxdvb", "unknown FE type %d", type);
return NULL;
}
linuxdvb_frontend_t *lfe
= (linuxdvb_frontend_t*)
mpegts_input_create0(calloc(1, sizeof(linuxdvb_frontend_t)), idc, uuid);
mpegts_input_create0(calloc(1, sizeof(linuxdvb_frontend_t)),
idc, uuid, conf);
lfe->lfe_info.type = type;
/* Input callbacks */
lfe->mi_display_name = linuxdvb_frontend_display_name;
lfe->mi_is_enabled = linuxdvb_frontend_is_enabled;
lfe->mi_display_name = linuxdvb_frontend_display_name;
lfe->mi_start_mux = linuxdvb_frontend_start_mux;
lfe->mi_stop_mux = linuxdvb_frontend_stop_mux;
lfe->mi_open_service = linuxdvb_frontend_open_service;
@ -490,10 +494,7 @@ linuxdvb_frontend_create0
if (!conf)
return lfe;
if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
lfe->mi_enabled = u32;
if (!htsmsg_get_u32(conf, "number", &u32))
lfe->lfe_number = u32;
/* TODO: this should be done differently */
if ((str = htsmsg_get_str(conf, "network"))) {
linuxdvb_network_t *ln = linuxdvb_network_find_by_uuid(str);
if (ln) {
@ -553,3 +554,16 @@ linuxdvb_frontend_added
return lfe;
}
void
linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m )
{
mpegts_input_save((mpegts_input_t*)lfe, m);
htsmsg_add_str(m, "type", dvb_type2str(lfe->lfe_info.type));
}
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/

View file

@ -26,20 +26,86 @@
#include <pthread.h>
#include <assert.h>
/* **************************************************************************
* Class definition
* *************************************************************************/
const idclass_t mpegts_input_class =
{
.ic_class = "mpegts_input",
.ic_caption = "MPEGTS Input",
.ic_properties = (const property_t[]){
{ PROPDEF1("enabled", "Enabled",
PT_BOOL, mpegts_input_t, mi_enabled) },
{}
}
};
/* **************************************************************************
* Class methods
* *************************************************************************/
static int
mpegts_input_is_enabled ( mpegts_input_t *mi )
{
return mi->mi_enabled;
}
static void
mpegts_input_display_name ( mpegts_input_t *mi, char *buf, size_t len )
{
*buf = 0;
}
int
mpegts_input_is_free ( mpegts_input_t *mi )
{
char buf[256];
mpegts_mux_instance_t *mmi = LIST_FIRST(&mi->mi_mux_active);
mi->mi_display_name(mi, buf, sizeof(buf));
tvhtrace("mpegts", "%s - is free? %d", buf, mmi == NULL);
return mmi ? 0 : 1;
}
int
mpegts_input_current_weight ( mpegts_input_t *mi )
{
const mpegts_mux_instance_t *mmi;
const service_t *s;
const th_subscription_t *ths;
int w = 0;
// TODO: we probably need a way for mux level subs
/* Check for scan (weight 1) */
LIST_FOREACH(mmi, &mi->mi_mux_active, mmi_active_link) {
if (mmi->mmi_mux->mm_initial_scan_status == MM_SCAN_CURRENT) {
w = 1;
break;
}
}
/* Check subscriptions */
pthread_mutex_lock(&mi->mi_delivery_mutex);
LIST_FOREACH(s, &mi->mi_transports, s_active_link) {
LIST_FOREACH(ths, &s->s_subscriptions, ths_service_link)
w = MAX(w, ths->ths_weight);
}
pthread_mutex_unlock(&mi->mi_delivery_mutex);
return w;
}
static int
mpegts_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
return SM_CODE_TUNING_FAILED;
}
static void
mpegts_input_stop_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
}
static void
mpegts_input_open_service ( mpegts_input_t *mi, mpegts_service_t *s )
{
@ -50,18 +116,26 @@ mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s )
{
}
/* **************************************************************************
* Data processing
* *************************************************************************/
size_t
mpegts_input_recv_packets
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi,
uint8_t *tsb, size_t l, int64_t *pcr, uint16_t *pcr_pid )
uint8_t *tsb, size_t l, int64_t *pcr, uint16_t *pcr_pid,
const char *name )
{
int len = l; // TODO: fix ts_resync() to remove this
int len = l;
int i = 0, table_wakeup = 0;
mpegts_mux_t *mm = mmi->mmi_mux;
assert(mmi->mmi_input == mi);
assert(mm != NULL);
tvhtrace("tsdemux", "recv_packets tsb=%p, len=%d, pcr=%p, pcr_pid=%p",
tsb, (int)len, pcr, pcr_pid);
assert(name != NULL);
// TODO: get the input name
tvhtrace("tsdemux", "%s - recv_packets tsb=%p, len=%d, pcr=%p, pcr_pid=%p",
name, tsb, (int)len, pcr, pcr_pid);
/* Not enough data */
if (len < 188) return 0;
@ -86,7 +160,7 @@ mpegts_input_recv_packets
/* Sync */
if ( tsb[i] == 0x47 ) {
int pid = ((tsb[i+1] & 0x1f) << 8) | tsb[i+2];
tvhtrace("tsdemux", "recv_packet for pid %04X (%d)", pid, pid);
tvhtrace("tsdemux", "%s - recv_packet for pid %04X (%d)", name, pid, pid);
/* SI data */
if (mm->mm_table_filter[pid]) {
@ -114,10 +188,9 @@ mpegts_input_recv_packets
/* Re-sync */
} else {
// TODO: set flag (to avoid spam)
tvhdebug("tsdemux", "%s ts sync lost", "TODO");
tvhdebug("tsdemux", "%s - ts sync lost", name);
if (ts_resync(tsb, &len, &i)) break;
tvhdebug("tsdemux", "%s ts sync found", "TODO");
tvhdebug("tsdemux", "%s - ts sync found", name);
}
}
@ -179,7 +252,6 @@ mpegts_input_table_thread ( void *aux )
/* Process */
pthread_mutex_lock(&global_lock);
// TODO: should we check the mux is active
mpegts_input_table_dispatch(mtf->mtf_mux, mtf);
pthread_mutex_unlock(&global_lock);
free(mtf);
@ -187,59 +259,28 @@ mpegts_input_table_thread ( void *aux )
return NULL;
}
int
mpegts_input_is_free ( mpegts_input_t *mi )
{
mpegts_mux_instance_t *mmi = LIST_FIRST(&mi->mi_mux_active);
tvhtrace("mpegts", "input_is_free(%p) mmi = %p", mi, mmi);
return mmi ? 0 : 1;
}
int
mpegts_input_current_weight ( mpegts_input_t *mi )
{
const mpegts_mux_instance_t *mmi;
const service_t *s;
const th_subscription_t *ths;
int w = 0;
LIST_FOREACH(mmi, &mi->mi_mux_active, mmi_active_link) {
if (mmi->mmi_mux->mm_initial_scan_status == MM_SCAN_CURRENT) {
w = 1;
break;
}
}
pthread_mutex_lock(&mi->mi_delivery_mutex);
LIST_FOREACH(s, &mi->mi_transports, s_active_link) {
LIST_FOREACH(ths, &s->s_subscriptions, ths_service_link)
w = MAX(w, ths->ths_weight);
}
pthread_mutex_unlock(&mi->mi_delivery_mutex);
return w;
}
static int
mpegts_input_is_enabled ( mpegts_input_t *mi )
{
return mi->mi_enabled;
}
/* **************************************************************************
* Creation/Config
* *************************************************************************/
mpegts_input_t*
mpegts_input_create0
( mpegts_input_t *mi, const idclass_t *class, const char *uuid )
( mpegts_input_t *mi, const idclass_t *class, const char *uuid,
htsmsg_t *c )
{
idnode_insert(&mi->mi_id, uuid, class);
if (c)
idnode_load(&mi->mi_id, c);
/* Defaults */
mi->mi_start_mux = NULL;
mi->mi_stop_mux = NULL;
mi->mi_open_service = mpegts_input_open_service;
mi->mi_close_service = mpegts_input_close_service;
mi->mi_is_enabled = mpegts_input_is_enabled;
mi->mi_display_name = mpegts_input_display_name;
mi->mi_is_free = mpegts_input_is_free;
mi->mi_current_weight = mpegts_input_current_weight;
mi->mi_display_name = mpegts_input_display_name;
mi->mi_start_mux = mpegts_input_start_mux;
mi->mi_stop_mux = mpegts_input_stop_mux;
mi->mi_open_service = mpegts_input_open_service;
mi->mi_close_service = mpegts_input_close_service;
/* Init mutex */
pthread_mutex_init(&mi->mi_delivery_mutex, NULL);
@ -254,6 +295,14 @@ mpegts_input_create0
return mi;
}
void
mpegts_input_save ( mpegts_input_t *mi, htsmsg_t *m )
{
idnode_save(&mi->mi_id, m);
if (mi->mi_network)
htsmsg_add_str(m, "network", idnode_uuid_as_str(&mi->mi_network->mn_id));
}
/******************************************************************************
* Editor Configuration
*

View file

@ -300,3 +300,9 @@ mpegts_service_save ( mpegts_service_t *s, htsmsg_t *c )
{
service_save((service_t*)s, c);
}
/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/