dvbreorg WIP

Initial scan now works again

We have a new idnode system that can give an entity a UUID which then can
be looked up externally (webui, etc). Good when browsing stuff
The UUID is supposed to be persisted on on disk when saving enteties
This commit is contained in:
Andreas Öman 2013-01-17 16:21:55 +01:00
parent 963a0502d3
commit fef5755fe7
24 changed files with 825 additions and 284 deletions

View file

@ -63,6 +63,7 @@ endif
# Core
#
SRCS = src/main.c \
src/idnode.c \
src/utils.c \
src/wrappers.c \
src/version.c \

View file

@ -26,5 +26,6 @@ void
dvb_init(uint32_t adapter_mask, const char *rawfile)
{
dvb_charset_init();
dvb_network_init();
dvb_adapter_init(adapter_mask, rawfile);
}

View file

@ -24,6 +24,7 @@
#include <pthread.h>
#include "htsmsg.h"
#include "psi.h"
#include "idnode.h"
struct service;
struct th_dvb_table;
@ -35,7 +36,7 @@ struct th_dvb_mux_instance;
(DVB_VER_INT(DVB_API_VERSION, DVB_API_VERSION_MINOR) >= DVB_VER_INT(maj, min))
TAILQ_HEAD(th_dvb_adapter_queue, th_dvb_adapter);
RB_HEAD(th_dvb_mux_instance_tree, th_dvb_mux_instance);
LIST_HEAD(th_dvb_adapter_list, th_dvb_adapter);
TAILQ_HEAD(th_dvb_mux_instance_queue, th_dvb_mux_instance);
LIST_HEAD(th_dvb_mux_instance_list, th_dvb_mux_instance);
TAILQ_HEAD(dvb_satconf_queue, dvb_satconf);
@ -89,11 +90,14 @@ typedef struct dvb_mux_conf {
*
*/
typedef struct dvb_network {
idnode_t dn_id;
LIST_ENTRY(dvb_network) dn_global_link;
struct dvb_mux_queue dn_initial_scan_queue;
int dn_initial_num_mux;
struct dvb_mux_queue dn_initial_scan_pending_queue;
struct dvb_mux_queue dn_initial_scan_current_queue;
int dn_initial_scan_num_mux;
gtimer_t dn_initial_scan_timer;
struct dvb_mux *dn_mux_epg;
@ -101,13 +105,11 @@ typedef struct dvb_network {
struct dvb_mux_list dn_muxes;
gtimer_t dn_mux_scanner_timer;
uint32_t dn_disable_pmt_monitor;
uint32_t dn_autodiscovery;
uint32_t dn_nitoid;
char *dn_uuid;
struct th_dvb_adapter_list dn_adapters;
} dvb_network_t;
@ -117,7 +119,7 @@ typedef struct dvb_network {
*
*/
typedef struct dvb_mux {
idnode_t dm_id;
LIST_ENTRY(dvb_mux) dm_network_link;
dvb_network_t *dm_dn;
@ -132,14 +134,20 @@ typedef struct dvb_mux {
TAILQ_HEAD(, epggrab_ota_mux) dm_epg_grab;
gtimer_t dm_initial_scan_timeout;
TAILQ_ENTRY(dvb_mux) dm_scan_link;
struct dvb_mux_queue *dm_scan_queue;
enum {
DM_SCAN_DONE, // All done
DM_SCAN_PENDING, // Waiting to be tuned for initial scan
DM_SCAN_CURRENT, // Currently tuned for initial scan
} dm_scan_status;
LIST_HEAD(, th_dvb_table) dm_tables;
int dm_num_tables;
TAILQ_HEAD(, th_dvb_table) dm_table_queue;
int dm_table_initial;
// int dm_table_initial;
struct th_dvb_mux_instance *dm_current_tdmi;
@ -148,8 +156,6 @@ typedef struct dvb_mux {
// Derived from dm_conf (more or less)
char *dm_local_identifier;
char *dm_uuid;
int dm_enabled;
} dvb_mux_t;
@ -193,6 +199,8 @@ typedef struct th_dvb_mux_instance {
int tdmi_tune_failed; // Adapter failed to tune this frequency
// Don't try again
int tdmi_weight;
struct th_subscription_list tdmi_subscriptions;
} th_dvb_mux_instance_t;
@ -226,6 +234,7 @@ typedef struct th_dvb_adapter {
TAILQ_ENTRY(th_dvb_adapter) tda_global_link;
dvb_network_t *tda_dn;
LIST_ENTRY(th_dvb_adapter) tda_network_link;
struct th_dvb_mux_instance_list tda_tdmis;
@ -479,6 +488,8 @@ dvb_mux_t *dvb_mux_find(dvb_network_t *dn, const char *netname, uint16_t onid,
uint16_t tsid, int enabled);
void dvb_mux_initial_scan_done(dvb_mux_t *dm);
/**
* DVB Transport (aka DVB service)
*/
@ -507,14 +518,12 @@ void dvb_service_notify(struct service *t);
void dvb_service_notify_by_adapter(th_dvb_adapter_t *tda);
htsmsg_t *dvb_service_build_msg(struct service *t);
/**
* DVB Frontend
*/
int dvb_fe_tune(dvb_mux_t *dm, const char *reason);
int dvb_fe_tune(dvb_mux_t *dm, const char *reason, int weight);
void dvb_fe_stop(th_dvb_adapter_t *tda, int retune);
//void dvb_fe_stop(th_dvb_adapter_t *tda, int retune);
/**
@ -551,9 +560,15 @@ void dvb_table_release(th_dvb_table_t *tdt);
/**
*
*/
dvb_network_t *dvb_network_create(int fe_type);
dvb_network_t *dvb_network_create(int fe_type, const char *uuid);
void dvb_network_mux_scanner(void *aux);
//void dvb_network_mux_scanner(void *aux);
void dvb_network_init(void);
idnode_t **dvb_network_root(void);
void dvb_network_schedule_initial_scan(dvb_network_t *dn);
/**

View file

@ -46,7 +46,6 @@
#include "diseqc.h"
struct th_dvb_adapter_queue dvb_adapters;
struct th_dvb_mux_instance_tree dvb_muxes;
static void *dvb_adapter_input_dvr(void *aux);
@ -280,6 +279,20 @@ dvb_adapter_set_extrapriority(th_dvb_adapter_t *tda, int extrapriority)
tda_save(tda);
}
/**
*
*/
static void
dvb_adapter_set_network(th_dvb_adapter_t *tda, const char *uuid)
{
dvb_network_t *dn = LIST_FIRST(&dvb_networks);
tda->tda_dn = dn;
LIST_INSERT_HEAD(&dn->dn_adapters, tda, tda_network_link);
}
/**
*
*/
@ -402,7 +415,7 @@ tda_add(int adapter_num)
close(fe);
tda->tda_fe_type = tda->tda_fe_info->type;
tda->tda_dn = dvb_network_create(tda->tda_fe_type);
dvb_adapter_set_network(tda, NULL);
snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath,
tda->tda_fe_info->name);

View file

@ -107,6 +107,7 @@ dvb_fe_monitor(void *aux)
/**
* Read out front end status
*/
if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &fe_status))
fe_status = 0;
@ -254,6 +255,7 @@ dvb_fe_monitor(void *aux)
}
#if 0
/**
* Stop the given TDMI
*/
@ -266,16 +268,8 @@ dvb_fe_stop(th_dvb_adapter_t *tda, int retune)
assert(tdmi != NULL);
dvb_mux_t *dm = tdmi->tdmi_mux;
if(dm->dm_table_initial) {
dm->dm_table_initial = 0;
dm->dm_dn->dn_initial_num_mux--;
dvb_mux_save(dm);
}
dvb_table_flush_all(dm);
assert(dm->dm_scan_queue == NULL);
epggrab_mux_stop(dm, 0);
#if 0 /// XXX(dvbreorg)
@ -285,6 +279,9 @@ dvb_fe_stop(th_dvb_adapter_t *tda, int retune)
}
#endif
}
#endif
#if DVB_API_VERSION >= 5
@ -342,9 +339,8 @@ static struct dtv_properties clear_cmdseq = {
*
*/
static int
dvb_fe_tune_s2(th_dvb_mux_instance_t *tdmi, dvb_mux_conf_t *dmc)
dvb_fe_tune_s2(th_dvb_adapter_t *tda, dvb_mux_conf_t *dmc)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
struct dvb_frontend_parameters *p = &dmc->dmc_fe_params;
int r;
@ -388,47 +384,151 @@ dvb_fe_tune_s2(th_dvb_mux_instance_t *tdmi, dvb_mux_conf_t *dmc)
#endif
/**
* These are created on the fly
*/
static void
dvb_create_tdmis(dvb_mux_t *dm)
{
th_dvb_mux_instance_t *tdmi;
dvb_network_t *dn = dm->dm_dn;
th_dvb_adapter_t *tda;
LIST_FOREACH(tda, &dn->dn_adapters, tda_network_link) {
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
if(tdmi->tdmi_adapter != NULL)
break;
}
if(tdmi == NULL) {
tdmi = calloc(1, sizeof(th_dvb_mux_instance_t));
tdmi->tdmi_adapter = tda;
tdmi->tdmi_mux = dm;
LIST_INSERT_HEAD(&tda->tda_tdmis, tdmi, tdmi_adapter_link);
LIST_INSERT_HEAD(&dm->dm_tdmis, tdmi, tdmi_mux_link);
}
}
}
/**
*
*/
static void
dvb_mux_stop(th_dvb_mux_instance_t *tdmi)
{
dvb_mux_t *dm = tdmi->tdmi_mux;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
assert(dm->dm_current_tdmi == tdmi);
assert(tda->tda_current_tdmi == tdmi);
dvb_table_flush_all(dm);
epggrab_mux_stop(dm, 0);
assert(dm->dm_scan_status == DM_SCAN_DONE);
dm->dm_current_tdmi = NULL;
tda->tda_current_tdmi = NULL;
printf("NEED TO TAKE CARE OF SERVICES in dvb_mux_stop\n");
}
/**
*
*/
static int
tdmi_compute_weight(const th_dvb_mux_instance_t *tdmi)
{
const dvb_mux_t *dm = tdmi->tdmi_mux;
if(dm->dm_scan_status == DM_SCAN_CURRENT)
return 1;
return 0;
}
/**
*
*/
static void
dvb_mux_initial_scan_timeout(void *aux)
{
dvb_mux_t *dm = aux;
char buf[100];
dvb_mux_nicename(buf, sizeof(buf), dm);
tvhlog(LOG_DEBUG, "dvb", "Initial scan timed out for \"%s\"", buf);
dvb_mux_initial_scan_done(dm);
}
/**
*
*/
int
dvb_fe_tune(dvb_mux_t *dm, const char *reason)
dvb_fe_tune(dvb_mux_t *dm, const char *reason, int weight)
{
dvb_network_t *dn = dm->dm_dn;
th_dvb_mux_instance_t *tdmi = NULL; // dm->dm_tdmi;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
// copy dmc, cause frequency may be change with FE_QPSK
dvb_mux_conf_t dmc = dm->dm_conf;
dvb_frontend_parameters_t* p = &dmc.dmc_fe_params;
th_dvb_mux_instance_t *tdmi;
char buf[256];
int r;
assert(dm->dm_current_tdmi == NULL);
lock_assert(&global_lock);
dvb_create_tdmis(dm);
retry:
// Figure which adapter to use
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
if(!tdmi->tdmi_tune_failed && tdmi->tdmi_adapter->tda_current_tdmi == NULL)
break;
if(tdmi == NULL) {
// None available, need to strike one out
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
if(tdmi->tdmi_tune_failed)
continue;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
th_dvb_mux_instance_t *t2 = tda->tda_current_tdmi;
assert(t2 != NULL);
assert(t2 != tdmi);
if(tdmi_compute_weight(t2) < weight) {
dvb_mux_stop(t2);
break;
}
}
if(tdmi == NULL)
return SM_CODE_NO_FREE_ADAPTER;
}
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
dvb_adapter_start(tda);
assert(tda->tda_current_tdmi == NULL);
free(tda->tda_tune_reason);
tda->tda_tune_reason = strdup(reason);
if(tda->tda_current_tdmi == tdmi) {
dvb_adapter_notify(tda);
return 0;
}
tdmi->tdmi_weight = weight;
if(dm->dm_scan_queue != NULL) {
TAILQ_REMOVE(dm->dm_scan_queue, dm, dm_scan_link);
dm->dm_scan_queue = NULL;
}
if(tda->tda_current_tdmi != NULL)
dvb_fe_stop(tda, 1);
else
dvb_adapter_start(tda);
if(tda->tda_fe_type == FE_QPSK) {
/* DVB-S */
int port, lowfreq, hifreq, switchfreq, hiband, pol, dbsbs;
@ -486,11 +586,11 @@ dvb_fe_tune(dvb_mux_t *dm, const char *reason)
dvb_mux_fec2str(p->u.qpsk.fec_inner), dvb_mux_delsys2str(dmc.dmc_fe_delsys),
dvb_mux_qam2str(dmc.dmc_fe_modulation), reason);
r = dvb_fe_tune_s2(tdmi, &dmc);
r = dvb_fe_tune_s2(tda, &dmc);
} else
#endif
{
tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning to \"%s\" (%s)", tda->tda_rootpath, buf, reason);
tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning to \"%s\" (%s) fd:%d", tda->tda_rootpath, buf, reason, tda->tda_fe_fd);
r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, p);
}
@ -499,24 +599,26 @@ dvb_fe_tune(dvb_mux_t *dm, const char *reason)
" -- Front configuration failed -- %s, frequency: %u",
tda->tda_rootpath, buf, strerror(errno), p->frequency);
/* Remove from initial scan set */
if(dm->dm_table_initial) {
dm->dm_table_initial = 0;
dn->dn_initial_num_mux--;
}
/* Mark as bad */
tdmi->tdmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
goto retry;
}
tda->tda_current_tdmi = tdmi;
dm->dm_current_tdmi = tdmi;
if(dm->dm_scan_status == DM_SCAN_PENDING) {
TAILQ_REMOVE(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link);
dm->dm_scan_status = DM_SCAN_CURRENT;
TAILQ_INSERT_TAIL(&dn->dn_initial_scan_current_queue, dm, dm_scan_link);
gtimer_arm(&dm->dm_initial_scan_timeout, dvb_mux_initial_scan_timeout, dm, 10);
}
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
dvb_table_add_default(tdmi->tdmi_mux);
epggrab_mux_start(tdmi->tdmi_mux);
dvb_table_add_default(dm);
epggrab_mux_start(dm);
dvb_adapter_notify(tda);
return 0;

View file

@ -59,7 +59,7 @@ open_service(th_dvb_adapter_t *tda, service_t *s)
st->es_demuxer_fd = -1;
tvhlog(LOG_ERR, "dvb",
"\"%s\" unable to open demuxer \"%s\" for pid %d -- %s",
s->s_uuid, tda->tda_demux_path,
s->s_nicename, tda->tda_demux_path,
st->es_pid, strerror(errno));
continue;
}
@ -74,7 +74,7 @@ open_service(th_dvb_adapter_t *tda, service_t *s)
if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) {
tvhlog(LOG_ERR, "dvb",
"\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s",
s->s_uuid, tda->tda_demux_path,
s->s_nicename, tda->tda_demux_path,
st->es_pid, strerror(errno));
close(fd);
fd = -1;

View file

@ -46,8 +46,6 @@
#include "subscriptions.h"
#include "epggrab.h"
struct th_dvb_mux_instance_tree dvb_muxes;
static struct strtab muxfestatustab[] = {
{ "Unknown", TDMI_FE_UNKNOWN },
{ "No signal", TDMI_FE_NO_SIGNAL },
@ -58,18 +56,51 @@ static struct strtab muxfestatustab[] = {
{ "OK", TDMI_FE_OK },
};
static htsmsg_t *dvb_mux_serialize(struct idnode *self, int full);
static idnode_t **dvb_mux_get_childs(struct idnode *self);
static const idclass_t dvb_mux_class = {
.ic_class = "dvbmux",
.ic_serialize = dvb_mux_serialize,
.ic_get_childs = dvb_mux_get_childs,
};
/**
*
*/
static void
mux_link_initial(dvb_network_t *dn, dvb_mux_t *dm)
{
dm->dm_scan_queue = &dn->dn_initial_scan_queue;
TAILQ_INSERT_TAIL(dm->dm_scan_queue, dm, dm_scan_link);
assert(dm->dm_scan_status == DM_SCAN_DONE);
gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 0);
dm->dm_scan_status = DM_SCAN_PENDING;
TAILQ_INSERT_TAIL(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link);
dn->dn_initial_scan_num_mux++;
dvb_network_schedule_initial_scan(dn);
}
/**
*
*/
void
dvb_mux_initial_scan_done(dvb_mux_t *dm)
{
dvb_network_t *dn = dm->dm_dn;
gtimer_disarm(&dm->dm_initial_scan_timeout);
assert(dm->dm_scan_status == DM_SCAN_CURRENT);
dn->dn_initial_scan_num_mux--;
dm->dm_scan_status = DM_SCAN_DONE;
TAILQ_REMOVE(&dn->dn_initial_scan_current_queue, dm, dm_scan_link);
dvb_network_schedule_initial_scan(dn);
dvb_mux_save(dm); // Save to dm_scan_status is persisted
}
/**
* Return a readable status text for the given mux
*/
@ -136,7 +167,7 @@ dcm_compare_conf(int adapter_type,
dvb_mux_t *
dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc,
uint16_t onid, uint16_t tsid, const char *network,
const char *source, int enabled, int initialscan,
const char *source, int enabled, int needscan,
const char *uuid)
{
dvb_mux_t *dm;
@ -186,16 +217,6 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc,
save = 1;
}
#if 0 // XXX(dvbreorg)
/* HACK - load old transports and remove old mux config */
if(identifier) {
save = 1;
dvb_service_load(tdmi, identifier);
hts_settings_remove("dvbmuxes/%s/%s",
tda->tda_identifier, identifier);
}
#endif
if(save) {
char buf[128];
dvb_mux_save(dm);
@ -220,6 +241,8 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc,
dm->dm_dn = dn;
LIST_INSERT_HEAD(&dn->dn_muxes, dm, dm_network_link);
idnode_insert(&dm->dm_id, uuid, &dvb_mux_class);
char identifier[128];
snprintf(identifier, sizeof(identifier),
"%d%s", dmc->dmc_fe_params.frequency,
@ -231,8 +254,6 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc,
memcpy(&dm->dm_conf, dmc, sizeof(struct dvb_mux_conf));
dm->dm_table_initial = initialscan;
if(source != NULL) {
char buf[128];
dvb_mux_nicename(buf, sizeof(buf), dm);
@ -243,8 +264,8 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc,
dvb_service_load(dm);
if(enabled && dm->dm_table_initial) {
dn->dn_initial_num_mux++;
if(enabled && needscan) {
dn->dn_initial_scan_num_mux++;
mux_link_initial(dn, dm);
}
@ -271,6 +292,7 @@ void
dvb_mux_destroy(dvb_mux_t *dm)
{
th_dvb_mux_instance_t *tdmi;
dvb_network_t *dn = dm->dm_dn;
lock_assert(&global_lock);
@ -279,16 +301,25 @@ dvb_mux_destroy(dvb_mux_t *dm)
while((tdmi = LIST_FIRST(&dm->dm_tdmis)) != NULL)
dvb_tdmi_destroy(tdmi);
if(dm->dm_scan_queue != NULL)
TAILQ_REMOVE(dm->dm_scan_queue, dm, dm_scan_link);
switch(dm->dm_scan_status) {
case DM_SCAN_DONE:
break;
case DM_SCAN_CURRENT:
TAILQ_REMOVE(&dn->dn_initial_scan_current_queue, dm, dm_scan_link);
gtimer_disarm(&dm->dm_initial_scan_timeout);
if(0) // Sorry but i can't resist these whenever i get an oppertunity // andoma
case DM_SCAN_PENDING:
TAILQ_REMOVE(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link);
dn->dn_initial_scan_num_mux--;
dvb_network_schedule_initial_scan(dn);
break;
}
if(dm->dm_table_initial)
dm->dm_dn->dn_initial_num_mux--;
epggrab_mux_delete(dm);
free(dm->dm_local_identifier);
free(dm->dm_uuid);
idnode_unlink(&dm->dm_id);
free(dm);
}
@ -492,7 +523,7 @@ dvb_mux_save(dvb_mux_t *dm)
htsmsg_add_u32(m, "frequency", f->frequency);
htsmsg_add_u32(m, "initialscan", dm->dm_table_initial);
htsmsg_add_u32(m, "needscan", dm->dm_scan_status != DM_SCAN_DONE);
if(dm->dm_default_authority)
htsmsg_add_str(m, "default_authority", dm->dm_default_authority);
@ -559,7 +590,7 @@ dvb_mux_save(dvb_mux_t *dm)
}
hts_settings_save(m, "dvb/networks/%s/muxes/%s/config",
dm->dm_dn->dn_uuid,
idnode_uuid_as_str(&dm->dm_dn->dn_id),
dm->dm_local_identifier);
htsmsg_destroy(m);
@ -575,7 +606,7 @@ dvb_mux_create_by_msg(dvb_network_t *dn, htsmsg_t *m, const char *fname)
struct dvb_mux_conf dmc;
const char *s;
int r;
unsigned int onid, tsid, enabled, initscan;
unsigned int onid, tsid, enabled;
memset(&dmc, 0, sizeof(dmc));
dmc.dmc_fe_params.inversion = INVERSION_AUTO;
@ -694,10 +725,9 @@ dvb_mux_create_by_msg(dvb_network_t *dn, htsmsg_t *m, const char *fname)
if(htsmsg_get_u32(m, "enabled", &enabled))
enabled = 1;
initscan = htsmsg_get_u32_or_default(m, "initialscan", 0);
dm = dvb_mux_create(dn, &dmc,
onid, tsid, htsmsg_get_str(m, "network"), NULL, enabled,
initscan,
htsmsg_get_u32_or_default(m, "needscan", 1),
htsmsg_get_str(m, "uuid"));
if(dm != NULL) {
@ -718,13 +748,16 @@ dvb_mux_load(dvb_network_t *dn)
htsmsg_field_t *f;
if((l = hts_settings_load_r(1, "dvb/networks/%s/muxes",
dn->dn_uuid)) == NULL)
idnode_uuid_as_str(&dn->dn_id))) == NULL)
return;
HTSMSG_FOREACH(f, l) {
if((c = htsmsg_get_map_by_field(f)) == NULL)
continue;
if((c = htsmsg_get_map(c, "config")) == NULL)
continue;
dvb_mux_create_by_msg(dn, c, f->hmf_name);
}
htsmsg_destroy(l);
@ -765,7 +798,7 @@ dvb_mux_set_tsid(dvb_mux_t *dm, uint16_t tsid)
dvb_mux_save(dm);
m = htsmsg_create_map();
htsmsg_add_str(m, "uuid", dm->dm_uuid);
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id));
htsmsg_add_u32(m, "muxid", dm->dm_transport_stream_id);
notify_by_msg("dvbMux", m);
}
@ -783,7 +816,7 @@ dvb_mux_set_onid(dvb_mux_t *dm, uint16_t onid)
dvb_mux_save(dm);
m = htsmsg_create_map();
htsmsg_add_str(m, "uuid", dm->dm_uuid);
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id));
htsmsg_add_u32(m, "onid", dm->dm_network_id);
notify_by_msg("dvbMux", m);
}
@ -917,7 +950,7 @@ dvb_mux_build_msg(dvb_mux_t *dm)
htsmsg_t *m = htsmsg_create_map();
char buf[100];
htsmsg_add_str(m, "uuid", dm->dm_uuid);
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id));
htsmsg_add_u32(m, "enabled", dm->dm_enabled);
htsmsg_add_str(m, "network", dm->dm_network_name ?: "");
@ -1200,8 +1233,8 @@ dvb_subscription_create_from_tdmi(th_dvb_mux_instance_t *tdmi,
s->ths_tdmi = tdmi;
LIST_INSERT_HEAD(&tdmi->tdmi_subscriptions, s, ths_tdmi_link);
dvb_fe_tune(tdmi->tdmi_mux, "Full mux subscription");
dvb_fe_tune(tdmi->tdmi_mux, "Full mux subscription", 99999);
abort();
pthread_mutex_lock(&tda->tda_delivery_mutex);
streaming_target_connect(&tda->tda_streaming_pad, &s->ths_input);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
@ -1209,3 +1242,56 @@ dvb_subscription_create_from_tdmi(th_dvb_mux_instance_t *tdmi,
notify_reload("subscriptions");
return s;
}
/**
*
*/
static htsmsg_t *
dvb_mux_serialize(struct idnode *self, int full)
{
dvb_mux_t *dm = (dvb_mux_t *)self;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(&dm->dm_id));
char buf[256];
dvb_mux_nicename(buf, sizeof(buf), dm);
htsmsg_add_str(m, "text", buf);
return m;
}
/**
*
*/
static int
svcsortcmp(const void *A, const void *B)
{
const service_t *a = *(service_t **)A;
const service_t *b = *(service_t **)B;
return (int)a->s_dvb_service_id - (int)b->s_dvb_service_id;
}
/**
*
*/
static idnode_t **
dvb_mux_get_childs(struct idnode *self)
{
dvb_mux_t *dm = (dvb_mux_t *)self;
service_t *s;
int cnt = 1;
LIST_FOREACH(s, &dm->dm_services, s_group_link)
cnt++;
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
cnt = 0;
LIST_FOREACH(s, &dm->dm_services, s_group_link)
v[cnt++] = (idnode_t *)s;
qsort(v, cnt, sizeof(idnode_t *), svcsortcmp);
v[cnt] = NULL;
return v;
}

View file

@ -16,36 +16,129 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "tvheadend.h"
#include "packet.h"
#include "dvb.h"
#include "epggrab.h"
#include "settings.h"
#include "dvb_support.h"
struct dvb_network_list dvb_networks;
static htsmsg_t *dvb_network_serialize(struct idnode *self, int full);
static idnode_t **dvb_network_get_childs(struct idnode *self);
static const idclass_t dvb_network_class = {
.ic_class = "dvbnetwork",
.ic_serialize = dvb_network_serialize,
.ic_get_childs = dvb_network_get_childs,
};
/**
*
*/
dvb_network_t *
dvb_network_create(int fe_type)
dvb_network_create(int fe_type, const char *uuid)
{
printf("Creating network %s\n", uuid);
dvb_network_t *dn = calloc(1, sizeof(dvb_network_t));
if(idnode_insert(&dn->dn_id, uuid, &dvb_network_class)) {
free(dn);
return NULL;
}
printf("Added network %s\n", idnode_uuid_as_str(&dn->dn_id));
dn->dn_fe_type = fe_type;
TAILQ_INIT(&dn->dn_initial_scan_queue);
gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 1);
TAILQ_INIT(&dn->dn_initial_scan_pending_queue);
TAILQ_INIT(&dn->dn_initial_scan_current_queue);
dn->dn_autodiscovery = fe_type != FE_QPSK;
LIST_INSERT_HEAD(&dvb_networks, dn, dn_global_link);
return dn;
}
#if 0
htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery);
htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid);
htsmsg_get_u32(c, "disable_pmt_monitor", &tda->tda_disable_pmt_monitor);
#endif
#if 0
/**
*
*/
static htsmsg_t *
dvb_network_serialize(struct idnode *self, int full)
{
dvb_network_t *dn = (dvb_network_t *)self;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(&dn->dn_id));
htsmsg_add_str(m, "text", idnode_uuid_as_str(&dn->dn_id));
return m;
}
/**
*
*/
static int
muxsortcmp(const void *A, const void *B)
{
const dvb_mux_t *a = *(dvb_mux_t **)A;
const dvb_mux_t *b = *(dvb_mux_t **)B;
if(a->dm_conf.dmc_fe_params.frequency < b->dm_conf.dmc_fe_params.frequency)
return -1;
if(a->dm_conf.dmc_fe_params.frequency > b->dm_conf.dmc_fe_params.frequency)
return 1;
return a->dm_conf.dmc_polarisation - b->dm_conf.dmc_polarisation;
}
/**
*
*/
static idnode_t **
dvb_network_get_childs(struct idnode *self)
{
dvb_network_t *dn = (dvb_network_t *)self;
dvb_mux_t *dm;
int cnt = 1;
LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link)
cnt++;
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
cnt = 0;
LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link)
v[cnt++] = (idnode_t *)dm;
qsort(v, cnt, sizeof(idnode_t *), muxsortcmp);
v[cnt] = NULL;
return v;
}
/**
*
*/
static void
dvb_network_load(htsmsg_t *m, const char *uuid)
{
uint32_t fetype;
if(htsmsg_get_u32(m, "fetype", &fetype))
return;
dvb_network_t *dn = dvb_network_create(fetype, uuid);
if(dn == NULL)
return;
htsmsg_get_u32(m, "autodiscovery", &dn->dn_autodiscovery);
htsmsg_get_u32(m, "nitoid", &dn->dn_nitoid);
htsmsg_get_u32(m, "disable_pmt_monitor", &dn->dn_disable_pmt_monitor);
dvb_mux_load(dn);
dvb_network_schedule_initial_scan(dn);
}
#if 1
/**
*
*/
@ -56,13 +149,18 @@ dvb_network_save(dvb_network_t *dn)
lock_assert(&global_lock);
htsmsg_add_u32(m, "fetype", dn->dn_fe_type);
htsmsg_add_u32(m, "autodiscovery", dn->dn_autodiscovery);
htsmsg_add_u32(m, "nitoid", dn->dn_nitoid);
htsmsg_add_u32(m, "disable_pmt_monitor", dn->dn_disable_pmt_monitor);
abort();
hts_settings_save(m, "dvb/networks/%s/config",
idnode_uuid_as_str(&dn->dn_id));
htsmsg_destroy(m);
}
#endif
#if 0
/**
*
@ -125,65 +223,82 @@ dvb_network_set_disable_pmt_monitor(th_dvb_network_t *dn, int on)
#endif
/**
*
*/
void
dvb_network_mux_scanner(void *aux)
static void
dvb_network_initial_scan(void *aux)
{
dvb_network_t *dn = aux;
dvb_mux_t *dm;
// default period
gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 20);
#if 0
/* No muxes */
if(LIST_FIRST(&dn->dn_mux_instances) == NULL) {
dvb_adapter_poweroff(tda);
return;
while((dm = TAILQ_FIRST(&dn->dn_initial_scan_pending_queue)) != NULL) {
assert(dm->dm_scan_status == DM_SCAN_PENDING);
if(dvb_fe_tune(dm, "initial scan", 1))
break;
assert(dm->dm_scan_status == DM_SCAN_CURRENT);
}
#endif
#if 0
/* Someone is actively using */
if(service_compute_weight(&tda->tda_transports) > 0)
return;
#endif
#if 0
if(tda->tda_mux_current != NULL &&
LIST_FIRST(&tda->tda_mux_current->tdmi_subscriptions) != NULL)
return; // Someone is doing full mux dump
#endif
/* Check if we have muxes pending for quickscan, if so, choose them */
if((dm = TAILQ_FIRST(&dn->dn_initial_scan_queue)) != NULL) {
dvb_fe_tune(dm, "Initial autoscan");
return;
}
/* Check EPG */
if (dn->dn_mux_epg) {
// timeout anything not complete
epggrab_mux_stop(dn->dn_mux_epg, 1);
dn->dn_mux_epg = NULL; // skip this time
} else {
dn->dn_mux_epg = epggrab_mux_next(dn);
}
/* EPG */
if (dn->dn_mux_epg) {
int period = epggrab_mux_period(dn->dn_mux_epg);
if (period > 20)
gtimer_arm(&dn->dn_mux_scanner_timer,
dvb_network_mux_scanner, dn, period);
dvb_fe_tune(dn->dn_mux_epg, "EPG scan");
return;
}
#if 0
/* Ensure we stop current mux and power off (if required) */
if (tda->tda_mux_current)
dvb_fe_stop(tda->tda_mux_current, 0);
#endif
gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 10);
}
/**
*
*/
void
dvb_network_schedule_initial_scan(dvb_network_t *dn)
{
gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 0);
}
/**
*
*/
void
dvb_network_init(void)
{
htsmsg_t *l, *c;
htsmsg_field_t *f;
if(0) {
dvb_network_save(dvb_network_create(FE_QAM, NULL));
exit(0);
}
if((l = hts_settings_load_r(1, "dvb/networks")) == NULL)
return;
htsmsg_print(l);
HTSMSG_FOREACH(f, l) {
if((c = htsmsg_get_map_by_field(f)) == NULL)
continue;
if((c = htsmsg_get_map(c, "config")) == NULL)
continue;
dvb_network_load(c, f->hmf_name);
}
htsmsg_destroy(l);
}
/**
*
*/
idnode_t **
dvb_network_root(void)
{
dvb_network_t *dn;
int cnt = 1;
LIST_FOREACH(dn, &dvb_networks, dn_global_link)
cnt++;
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
cnt = 0;
LIST_FOREACH(dn, &dvb_networks, dn_global_link)
v[cnt++] = &dn->dn_id;
v[cnt] = NULL;
return v;
}

View file

@ -44,15 +44,7 @@
#include "dvb_support.h"
#include "notify.h"
/**
*
*/
static htsmsg_t *dvb_service_serialize(service_t *s, int full);
/**
@ -110,7 +102,7 @@ dvb_service_start(service_t *t, unsigned int weight, int force_start)
return r;
#endif
return SM_CODE_NO_HW_ATTACHED;
return SM_CODE_NO_FREE_ADAPTER;
}
@ -193,7 +185,7 @@ dvb_service_save(service_t *t)
dvb_mux_t *dm = t->s_dvb_mux;
hts_settings_save(m, "dvb/networks/%s/muxes/%s/services/%04x",
dm->dm_dn->dn_uuid,
idnode_uuid_as_str(&dm->dm_dn->dn_id),
dm->dm_local_identifier,
t->s_dvb_service_id);
@ -217,7 +209,8 @@ dvb_service_load(dvb_mux_t *dm)
lock_assert(&global_lock);
l = hts_settings_load("dvb/networks/%s/muxes/%s/services",
dm->dm_dn->dn_uuid, dm->dm_local_identifier);
idnode_uuid_as_str(&dm->dm_dn->dn_id),
dm->dm_local_identifier);
if(l == NULL)
return;
@ -398,6 +391,7 @@ dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid,
t->s_config_save = dvb_service_save;
t->s_setsourceinfo = dvb_service_setsourceinfo;
t->s_grace_period = dvb_grace_period;
t->s_serialize = dvb_service_serialize;
t->s_dvb_mux = dm;
LIST_INSERT_HEAD(&dm->dm_services, t, s_group_link);
@ -412,38 +406,44 @@ dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid,
/**
*
*/
htsmsg_t *
dvb_service_build_msg(service_t *t)
static htsmsg_t *
dvb_service_serialize(service_t *s, int full)
{
dvb_mux_t *dm = t->s_dvb_mux;
dvb_mux_t *dm = s->s_dvb_mux;
htsmsg_t *m = htsmsg_create_map();
char buf[100];
htsmsg_add_str(m, "uuid", t->s_uuid);
htsmsg_add_u32(m, "enabled", t->s_enabled);
htsmsg_add_u32(m, "channel", t->s_channel_number);
htsmsg_add_u32(m, "sid", t->s_dvb_service_id);
htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
htsmsg_add_u32(m, "pcr", t->s_pcr_pid);
htsmsg_add_str(m, "type", service_servicetype_txt(t));
htsmsg_add_str(m, "id", idnode_uuid_as_str(&s->s_id));
htsmsg_add_str(m, "svcname", t->s_svcname ?: "");
htsmsg_add_str(m, "provider", t->s_provider ?: "");
snprintf(buf, sizeof(buf), "%s (0x%04x)",
s->s_svcname ?: "<noname>", s->s_dvb_service_id);
htsmsg_add_str(m, "text", buf);
htsmsg_add_u32(m, "enabled", s->s_enabled);
htsmsg_add_u32(m, "channel", s->s_channel_number);
htsmsg_add_u32(m, "sid", s->s_dvb_service_id);
htsmsg_add_u32(m, "pmt", s->s_pmt_pid);
htsmsg_add_u32(m, "pcr", s->s_pcr_pid);
htsmsg_add_str(m, "type", service_servicetype_txt(s));
htsmsg_add_str(m, "svcname", s->s_svcname ?: "");
htsmsg_add_str(m, "provider", s->s_provider ?: "");
htsmsg_add_str(m, "network", dm->dm_network_name ?: "");
dvb_mux_nicefreq(buf, sizeof(buf), dm);
htsmsg_add_str(m, "mux", buf);
if(t->s_ch != NULL)
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
if(s->s_ch != NULL)
htsmsg_add_str(m, "channelname", s->s_ch->ch_name);
if(t->s_dvb_charset != NULL)
htsmsg_add_str(m, "dvb_charset", t->s_dvb_charset);
if(s->s_dvb_charset != NULL)
htsmsg_add_str(m, "dvb_charset", s->s_dvb_charset);
htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable);
htsmsg_add_u32(m, "dvb_eit_enable", s->s_dvb_eit_enable);
return m;
}

View file

@ -52,25 +52,21 @@ dvb_table_fastswitch(th_dvb_mux_instance_t *tdmi)
th_dvb_table_t *tdt;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
dvb_mux_t *dm = tdmi->tdmi_mux;
dvb_network_t *dn = dm->dm_dn;
char buf[100];
if(!dm->dm_table_initial)
if(dm->dm_scan_status == DM_SCAN_DONE)
return;
LIST_FOREACH(tdt, &dm->dm_tables, tdt_link)
if((tdt->tdt_flags & TDT_QUICKREQ) && tdt->tdt_count == 0)
return;
dm->dm_table_initial = 0;
dn->dn_initial_num_mux--;
dvb_mux_save(dm);
dvb_mux_nicename(buf, sizeof(buf), dm);
tvhlog(LOG_DEBUG, "dvb", "\"%s\" initial scan completed for \"%s\"",
tda->tda_rootpath, buf);
dvb_network_mux_scanner(dn);
dvb_mux_initial_scan_done(dm);
}

View file

@ -369,13 +369,14 @@ void epggrab_ota_complete ( epggrab_ota_mux_t *ota )
TAILQ_FOREACH(ota, &dm->dm_epg_grab, dm_link) {
if (ota->is_reg && ota->state == EPGGRAB_OTA_MUX_RUNNING) break;
}
#if 0 // XXX(dvbreorg)
/* All complete (bring timer forward) */
if (!ota) {
dvb_network_t *dn = dm->dm_dn;
gtimer_arm(&dn->dn_mux_scanner_timer,
dvb_network_mux_scanner, dn, 20);
}
#endif
}
}

View file

@ -305,7 +305,7 @@ int fb_scandir ( const char *path, fb_dirent ***list )
for (i = 0; i < ret; i++) {
(*list)[i] = calloc(1, sizeof(fb_dirent));
strcpy((*list)[i]->name, de[i]->d_name);
(*list)[i]->type = FB_DIRECT;
(*list)[i]->type = de[i]->d_type == DT_DIR ? FB_DIR : FB_FILE;
free(de[i]);
}
free(de);

158
src/idnode.c Normal file
View file

@ -0,0 +1,158 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "idnode.h"
static int randfd = 0;
RB_HEAD(idnode_tree, idnode);
static struct idnode_tree idnodes;
/**
*
*/
static int
hexnibble(char c)
{
switch(c) {
case '0' ... '9': return c - '0';
case 'a' ... 'f': return c - 'a' + 10;
case 'A' ... 'F': return c - 'A' + 10;
default:
return -1;
}
}
/**
*
*/
static int
hex2bin(uint8_t *buf, size_t buflen, const char *str)
{
int hi, lo;
while(*str) {
if(buflen == 0)
return -1;
if((hi = hexnibble(*str++)) == -1)
return -1;
if((lo = hexnibble(*str++)) == -1)
return -1;
*buf++ = hi << 4 | lo;
buflen--;
}
return 0;
}
/**
*
*/
static void
bin2hex(char *dst, size_t dstlen, const uint8_t *src, size_t srclen)
{
while(dstlen > 2 && srclen > 0) {
*dst++ = "0123456789abcdef"[*src >> 4];
*dst++ = "0123456789abcdef"[*src & 0xf];
src++;
srclen--;
dstlen -= 2;
}
*dst = 0;
}
/**
*
*/
void
idnode_init(void)
{
randfd = open("/dev/urandom", O_RDONLY);
if(randfd == -1)
exit(1);
}
/**
*
*/
static int
in_cmp(const idnode_t *a, const idnode_t *b)
{
return memcmp(a->in_uuid, b->in_uuid, 16);
}
/**
*
*/
int
idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class)
{
idnode_t *c;
if(uuid == NULL) {
if(read(randfd, in->in_uuid, 16) != 16) {
perror("read(random for uuid)");
exit(1);
}
} else {
if(hex2bin(in->in_uuid, 16, uuid))
return -1;
}
in->in_class = class;
c = RB_INSERT_SORTED(&idnodes, in, in_link, in_cmp);
if(c != NULL) {
fprintf(stderr, "Id node collision\n");
abort();
}
return 0;
}
/**
*
*/
const char *
idnode_uuid_as_str(const idnode_t *in)
{
static char ret[16][33];
static int p;
char *b = ret[p];
bin2hex(b, 33, in->in_uuid, 16);
p = (p + 1) & 15;
return b;
}
/**
*
*/
idnode_t *
idnode_find(const char *uuid)
{
idnode_t skel, *r;
if(hex2bin(skel.in_uuid, 16, uuid))
return NULL;
r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
return r;
}
/**
*
*/
void
idnode_unlink(idnode_t *in)
{
RB_REMOVE(&idnodes, in, in_link);
}

29
src/idnode.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "tvheadend.h"
struct htsmsg;
struct idnode;
typedef struct idclass {
const char *ic_class;
struct htsmsg *(*ic_serialize)(struct idnode *self, int full);
struct idnode **(*ic_get_childs)(struct idnode *self);
} idclass_t;
typedef struct idnode {
uint8_t in_uuid[16];
RB_ENTRY(idnode) in_link;
const idclass_t *in_class;
} idnode_t;
void idnode_init(void);
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class);
const char *idnode_uuid_as_str(const idnode_t *in);
idnode_t *idnode_find(const char *uuid);
void idnode_unlink(idnode_t *in);

View file

@ -227,7 +227,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0);
}
if(fd == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_uuid);
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_nicename);
return -1;
}
@ -237,7 +237,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
ifr.ifr_name[IFNAMSIZ - 1] = 0;
if(ioctl(fd, SIOCGIFINDEX, &ifr)) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
t->s_uuid, t->s_iptv_iface);
t->s_nicename, t->s_iptv_iface);
close(fd);
return -1;
}
@ -251,7 +251,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m, sizeof(struct ip_mreqn));
if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
t->s_uuid, inet_ntoa(sin.sin_addr), t->s_iptv_port,
t->s_nicename, inet_ntoa(sin.sin_addr), t->s_iptv_port,
strerror(errno));
close(fd);
return -1;
@ -265,7 +265,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m,
sizeof(struct ip_mreqn)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
t->s_uuid, inet_ntoa(m.imr_multiaddr), strerror(errno));
t->s_nicename, inet_ntoa(m.imr_multiaddr), strerror(errno));
close(fd);
return -1;
}
@ -279,7 +279,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1) {
inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
t->s_uuid, straddr, t->s_iptv_port,
t->s_nicename, straddr, t->s_iptv_port,
strerror(errno));
close(fd);
return -1;
@ -294,7 +294,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
t->s_uuid, straddr, strerror(errno));
t->s_nicename, straddr, strerror(errno));
close(fd);
return -1;
}
@ -312,7 +312,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
ev.data.fd = fd;
if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s",
t->s_uuid, strerror(errno));
t->s_nicename, strerror(errno));
close(fd);
return -1;
}
@ -356,7 +356,7 @@ iptv_service_stop(service_t *t)
ifr.ifr_name[IFNAMSIZ - 1] = 0;
if(ioctl(t->s_iptv_fd, SIOCGIFINDEX, &ifr)) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
t->s_uuid, t->s_iptv_iface);
t->s_nicename, t->s_iptv_iface);
}
if(t->s_iptv_group.s_addr != 0) {
@ -371,7 +371,7 @@ iptv_service_stop(service_t *t)
if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m,
sizeof(struct ip_mreqn)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
t->s_uuid, inet_ntoa(m.imr_multiaddr), strerror(errno));
t->s_nicename, inet_ntoa(m.imr_multiaddr), strerror(errno));
}
} else {
char straddr[INET6_ADDRSTRLEN];
@ -388,7 +388,7 @@ iptv_service_stop(service_t *t)
straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
t->s_uuid, straddr, strerror(errno));
t->s_nicename, straddr, strerror(errno));
}
@ -440,8 +440,9 @@ iptv_service_save(service_t *t)
psi_save_service_settings(m, t);
pthread_mutex_unlock(&t->s_stream_mutex);
hts_settings_save(m, "iptvservices/%s",
t->s_uuid);
abort(); // XXX(dvbreorg);
// hts_settings_save(m, "iptvservices/%s", t->s_uuid);
htsmsg_destroy(m);
}
@ -484,7 +485,8 @@ iptv_grace_period(service_t *t)
static void
iptv_service_dtor(service_t *t)
{
hts_settings_remove("iptvservices/%s", t->s_uuid);
abort(); // XXX(dvbreorg);
// hts_settings_remove("iptvservices/%s", t->s_uuid);
}
@ -504,7 +506,7 @@ iptv_service_find(const char *id, int create)
return NULL;
LIST_FOREACH(t, &iptv_all_services, s_group_link)
if(!strcmp(t->s_uuid, id))
if(!strcmp(t->s_nicename, id)) // XXX(dvbreorg)
return t;
}

View file

@ -60,6 +60,7 @@
#include "ffdecsa/FFdecsa.h"
#include "muxes.h"
#include "config2.h"
#include "idnode.h"
int running;
time_t dispatch_clock;
@ -444,6 +445,9 @@ main(int argc, char **argv)
access_init(createdefault);
tcp_server_init();
idnode_init();
#if ENABLE_LINUXDVB
dvb_init(adapter_mask, dvb_rawts_input);
#endif

View file

@ -49,12 +49,15 @@
#include "htsp_server.h"
#include "lang_codes.h"
#define SERVICE_HASH_WIDTH 101
static struct service_list servicehash[SERVICE_HASH_WIDTH];
static void service_data_timeout(void *aux);
static htsmsg_t *service_serialize(struct idnode *self, int full);
static const idclass_t service_class = {
.ic_class = "service",
.ic_serialize = service_serialize,
};
/**
*
*/
@ -391,14 +394,14 @@ service_destroy(service_t *t)
}
LIST_REMOVE(t, s_group_link);
LIST_REMOVE(t, s_hash_link);
idnode_unlink(&t->s_id);
if(t->s_status != SERVICE_IDLE)
service_stop(t);
t->s_status = SERVICE_ZOMBIE;
free(t->s_uuid);
free(t->s_svcname);
free(t->s_provider);
free(t->s_dvb_charset);
@ -429,14 +432,12 @@ service_destroy(service_t *t)
service_t *
service_create(const char *uuid, int source_type)
{
unsigned int hash = tvh_strhash(uuid, SERVICE_HASH_WIDTH);
service_t *t = calloc(1, sizeof(service_t));
lock_assert(&global_lock);
pthread_mutex_init(&t->s_stream_mutex, NULL);
pthread_cond_init(&t->s_tss_cond, NULL);
t->s_uuid = strdup(uuid);
t->s_source_type = source_type;
t->s_refcount = 1;
t->s_enabled = 1;
@ -449,7 +450,8 @@ service_create(const char *uuid, int source_type)
streaming_pad_init(&t->s_streaming_pad);
LIST_INSERT_HEAD(&servicehash[hash], t, s_hash_link);
idnode_insert(&t->s_id, uuid, &service_class);
return t;
}
@ -459,15 +461,8 @@ service_create(const char *uuid, int source_type)
service_t *
service_find_by_identifier(const char *identifier)
{
service_t *t;
unsigned int hash = tvh_strhash(identifier, SERVICE_HASH_WIDTH);
lock_assert(&global_lock);
LIST_FOREACH(t, &servicehash[hash], s_hash_link)
if(!strcmp(t->s_uuid, identifier))
break;
return t;
idnode_t *id = idnode_find(identifier);
return id->in_class == &service_class ? (service_t *)id : NULL;
}
@ -1128,3 +1123,14 @@ htsmsg_t *servicetype_list ( void )
}
return ret;
}
/**
*
*/
static htsmsg_t *
service_serialize(struct idnode *self, int full)
{
service_t *s = (service_t *)self;
return s->s_serialize(s, full);
}

View file

@ -22,7 +22,7 @@
#define PID_TELETEXT_BASE 0x2000
#include "htsmsg.h"
#include "idnode.h"
/**
@ -201,8 +201,7 @@ service_start_cand_t *service_find_cand(struct service_start_cand_list *sscl,
*
*/
typedef struct service {
LIST_ENTRY(service) s_hash_link;
idnode_t s_id;
enum {
/**
@ -305,16 +304,13 @@ typedef struct service {
void (*s_dtor)(struct service *t);
htsmsg_t *(*s_serialize)(struct service *s, int full);
/*
* Per source type structs
*/
struct dvb_mux *s_dvb_mux;
/**
* Unique identifer
*/
char *s_uuid;
/**
* Name usable for displaying to user
*/

View file

@ -401,8 +401,8 @@ streaming_code2txt(int code)
case SM_CODE_SUBSCRIPTION_OVERRIDDEN:
return "Subscription overridden";
case SM_CODE_NO_HW_ATTACHED:
return "No hardware present";
case SM_CODE_NO_FREE_ADAPTER:
return "No free adapter";
case SM_CODE_MUX_NOT_ENABLED:
return "Mux not enabled";
case SM_CODE_NOT_FREE:

View file

@ -284,7 +284,7 @@ typedef enum {
#define SM_CODE_SOURCE_DELETED 102
#define SM_CODE_SUBSCRIPTION_OVERRIDDEN 103
#define SM_CODE_NO_HW_ATTACHED 200
#define SM_CODE_NO_FREE_ADAPTER 200
#define SM_CODE_MUX_NOT_ENABLED 201
#define SM_CODE_NOT_FREE 202
#define SM_CODE_TUNING_FAILED 203

View file

@ -1669,7 +1669,7 @@ build_record_iptv(service_t *t)
htsmsg_t *r = htsmsg_create_map();
char abuf[INET_ADDRSTRLEN];
char abuf6[INET6_ADDRSTRLEN];
htsmsg_add_str(r, "id", t->s_uuid);
// htsmsg_add_str(r, "id", t->s_uuid); // XXX(dvbreorg)
htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : "");
htsmsg_add_str(r, "interface", t->s_iptv_iface ?: "");
@ -1828,7 +1828,7 @@ extjs_tvadapter(http_connection_t *hc, const char *remain, void *opaque)
array = htsmsg_create_list();
#if ENABLE_LINUXDVB
// extjs_list_dvb_adapters(array);
extjs_list_dvb_adapters(array);
#endif
#if ENABLE_V4L

View file

@ -43,7 +43,6 @@
#include "dvb/dvb_preconf.h"
#include "dvr/dvr.h"
#if 0
@ -61,7 +60,7 @@ extjs_dvblocations(http_connection_t *hc, const char *remain, void *opaque)
if(s == NULL || a == NULL)
return HTTP_STATUS_BAD_REQUEST;
pthread_mutex_lock(&global_lock);
if(http_access_verify(hc, ACCESS_ADMIN)) {
@ -85,6 +84,7 @@ extjs_dvblocations(http_connection_t *hc, const char *remain, void *opaque)
return 0;
}
/**
*
*/
@ -115,8 +115,6 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
const char *op = http_arg_get(&hc->hc_req_args, "op");
const char *sibling = http_arg_get(&hc->hc_req_args, "sibling");
const char *s;
th_dvb_mux_instance_t *tdmi;
service_t *t;
pthread_mutex_lock(&global_lock);
@ -151,15 +149,12 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(r, "id", tda->tda_identifier);
htsmsg_add_str(r, "device", tda->tda_rootpath ?: "No hardware attached");
htsmsg_add_str(r, "name", tda->tda_displayname);
htsmsg_add_u32(r, "automux", tda->tda_autodiscovery);
htsmsg_add_u32(r, "skip_initialscan", tda->tda_skip_initialscan);
htsmsg_add_u32(r, "idleclose", tda->tda_idleclose);
htsmsg_add_u32(r, "skip_checksubscr", tda->tda_skip_checksubscr);
htsmsg_add_u32(r, "qmon", tda->tda_qmon);
htsmsg_add_u32(r, "poweroff", tda->tda_poweroff);
htsmsg_add_u32(r, "sidtochan", tda->tda_sidtochan);
htsmsg_add_u32(r, "nitoid", tda->tda_nitoid);
htsmsg_add_u32(r, "disable_pmt_monitor", tda->tda_disable_pmt_monitor);
htsmsg_add_u32(r, "full_mux_rx", tda->tda_full_mux_rx+1);
htsmsg_add_str(r, "diseqcversion",
((const char *[]){"DiSEqC 1.0 / 2.0",
@ -176,9 +171,6 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
dvb_adapter_set_displayname(tda, s);
s = http_arg_get(&hc->hc_req_args, "automux");
dvb_adapter_set_auto_discovery(tda, !!s);
s = http_arg_get(&hc->hc_req_args, "skip_initialscan");
dvb_adapter_set_skip_initialscan(tda, !!s);
@ -197,15 +189,9 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
s = http_arg_get(&hc->hc_req_args, "sidtochan");
dvb_adapter_set_sidtochan(tda, !!s);
s = http_arg_get(&hc->hc_req_args, "disable_pmt_monitor");
dvb_adapter_set_disable_pmt_monitor(tda, !!s);
s = http_arg_get(&hc->hc_req_args, "full_mux_rx");
dvb_adapter_set_full_mux_rx(tda, atoi(s)-1);
if((s = http_arg_get(&hc->hc_req_args, "nitoid")) != NULL)
dvb_adapter_set_nitoid(tda, atoi(s));
if((s = http_arg_get(&hc->hc_req_args, "diseqcversion")) != NULL) {
if(!strcmp(s, "DiSEqC 1.0 / 2.0"))
dvb_adapter_set_diseqc_version(tda, 0);
@ -231,11 +217,11 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
// sc = http_arg_get(&hc->hc_req_args, "satconf");
if((s = http_arg_get(&hc->hc_req_args, "network")) != NULL)
dvb_mux_preconf_add_network(tda, s);
dvb_mux_preconf_add_network(tda->tda_dn, s);
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
#if 0
} else if(!strcmp(op, "serviceprobe")) {
tvhlog(LOG_NOTICE, "web interface",
@ -251,6 +237,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
#endif
} else {
pthread_mutex_unlock(&global_lock);
@ -265,6 +252,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
return 0;
}
#if 0
/**
*
@ -678,6 +666,8 @@ extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque)
}
#endif
#endif
/**
*
*/
@ -689,7 +679,6 @@ extjs_list_dvb_adapters(htsmsg_t *array)
htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
}
#endif
/**
*
@ -711,27 +700,29 @@ extjs_dvbnetworks(http_connection_t *hc, const char *remain, void *opaque)
return HTTP_STATUS_UNAUTHORIZED;
}
printf("s=%s\n", s);
out = htsmsg_create_list();
if(!strcmp(s, "root")) {
htsmsg_t *n = htsmsg_create_map();
htsmsg_add_str(n, "text", "Network1");
htsmsg_add_str(n, "id", "net/1");
htsmsg_add_str(n, "cls", "folder");
htsmsg_add_str(n, "iconCls", "iptv");
htsmsg_add_msg(out, NULL, n);
idnode_t **v;
n = htsmsg_create_map();
htsmsg_add_str(n, "text", "Network2");
htsmsg_add_str(n, "id", "net/2");
htsmsg_add_str(n, "cls", "folder");
htsmsg_add_msg(out, NULL, n);
if(!strcmp(s, "root")) {
v = dvb_network_root();
} else {
idnode_t *n = idnode_find(s);
v = n != NULL && n->in_class->ic_get_childs != NULL ?
n->in_class->ic_get_childs(n) : NULL;
}
int i;
for(i = 0; v[i] != NULL; i++) {
htsmsg_t *m = v[i]->in_class->ic_serialize(v[i], 0);
if(v[i]->in_class->ic_get_childs == NULL)
htsmsg_add_u32(m, "leaf", 1);
htsmsg_add_msg(out, NULL, m);
}
pthread_mutex_unlock(&global_lock);
free(v);
htsmsg_json_serialize(out, hq, 0);
htsmsg_destroy(out);
http_output_content(hc, "text/x-json; charset=UTF-8");
@ -748,14 +739,14 @@ extjs_start_dvb(void)
{
http_path_add("/dvb/networks",
NULL, extjs_dvbnetworks, ACCESS_WEB_INTERFACE);
#if 0
http_path_add("/dvb/locations",
NULL, extjs_dvblocations, ACCESS_WEB_INTERFACE);
http_path_add("/dvb/adapter",
NULL, extjs_dvbadapter, ACCESS_ADMIN);
#if 0
http_path_add("/dvb/muxes",
NULL, extjs_dvbmuxes, ACCESS_ADMIN);

View file

@ -0,0 +1,25 @@
/**
*
*/
tvheadend.dvb_networks = function() {
var loader = new Ext.tree.TreeLoader({
dataUrl: 'dvb/networks'
});
var tree = new Ext.tree.TreePanel({
title: 'DVB Networks',
loader: loader,
root : new Ext.tree.AsyncTreeNode({
id : 'root',
text: 'DVB Networks'
})
});
tree.on('render', function() {
tree.getRootNode().expand();
});
return tree;
}

View file

@ -606,7 +606,7 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi)
streaming_queue_init(&sq, SMT_PACKET);
s = dvb_subscription_create_from_tdmi(tdmi, "HTTP", &sq.sq_st);
name = strdupa(tdmi->tdmi_mux->dm_uuid);
name = "foo"; // strdupa(tdmi->tdmi_mux->dm_uuid); XXX(dvbreorg)
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, name, MC_PASS);
pthread_mutex_lock(&global_lock);