* Redesigned the DVB configuration tab in the web userinterface:
- Each adapter have three (or four) tabs o General setup and information o Grid of multiplexes o Grid of services o For sattelite adapters, a sattelite configuration tab. * Add support for disabling / enabling an entire DVB multiplex * Add support for multiple DiSEqC switchports on a single adapter * Add support for different sattelite LNBs * Graceful handling of DVB adapters that does not support many table filters in hardware. Tvheadend will rotate among the available ones. * Add support for enabling / disabling transports from the DVB configuration * Make it possible to remove DVB multiplexes from the web ui * Add 'Revert changes' button to all editable grids in the web ui * Make it possible to disable the idle scan on per-DVB adapter basis. The idle scan is a process to cycles through all multiplex to check the quality for each mux continously.
3
Makefile
|
@ -77,7 +77,8 @@ SRCS += src/dvb/dvb.c \
|
|||
src/dvb/dvb_adapter.c \
|
||||
src/dvb/dvb_multiplex.c \
|
||||
src/dvb/dvb_transport.c \
|
||||
src/dvb/dvb_preconf.c
|
||||
src/dvb/dvb_preconf.c \
|
||||
src/dvb/dvb_satconf.c \
|
||||
|
||||
#
|
||||
# cwc
|
||||
|
|
30
debian/changelog
vendored
|
@ -1,3 +1,33 @@
|
|||
hts-tvheadend (2.3) hts; urgency=low
|
||||
|
||||
* Redesigned the DVB configuration tab in the web userinterface:
|
||||
- Each adapter have three (or four) tabs
|
||||
o General setup and information
|
||||
o Grid of multiplexes
|
||||
o Grid of services
|
||||
o For sattelite adapters, a sattelite configuration tab.
|
||||
|
||||
* Add support for disabling / enabling an entire DVB multiplex
|
||||
|
||||
* Add support for multiple DiSEqC switchports on a single adapter
|
||||
|
||||
* Add support for different sattelite LNBs
|
||||
|
||||
* Graceful handling of DVB adapters that does not support many
|
||||
table filters in hardware. Tvheadend will rotate among the available
|
||||
ones.
|
||||
|
||||
* Add support for enabling / disabling transports from the DVB configuration
|
||||
|
||||
* Make it possible to remove DVB multiplexes from the web ui
|
||||
|
||||
* Add 'Revert changes' button to all editable grids in the web ui
|
||||
|
||||
* Make it possible to disable the idle scan on per-DVB adapter basis.
|
||||
The idle scan is a process to cycles through all multiplex to check
|
||||
the quality for each mux continously.
|
||||
|
||||
|
||||
hts-tvheadend (2.2) hts; urgency=low
|
||||
|
||||
* Set $HOME so forked processes (XMLTV) will have correct environment
|
||||
|
|
|
@ -351,8 +351,6 @@ channel_rename(channel_t *ch, const char *newname)
|
|||
channel_set_name(ch, newname);
|
||||
|
||||
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) {
|
||||
free(t->tht_chname);
|
||||
t->tht_chname = strdup(newname);
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
|
@ -387,12 +385,8 @@ channel_delete(channel_t *ch)
|
|||
|
||||
dvr_destroy_by_channel(ch);
|
||||
|
||||
while((t = LIST_FIRST(&ch->ch_transports)) != NULL) {
|
||||
transport_unmap_channel(t);
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
while((t = LIST_FIRST(&ch->ch_transports)) != NULL)
|
||||
transport_map_channel(t, NULL, 1);
|
||||
|
||||
while((s = LIST_FIRST(&ch->ch_subscriptions)) != NULL) {
|
||||
LIST_REMOVE(s, ths_channel_link);
|
||||
|
@ -434,13 +428,8 @@ channel_merge(channel_t *dst, channel_t *src)
|
|||
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" merged into \"%s\"",
|
||||
src->ch_name, dst->ch_name);
|
||||
|
||||
while((t = LIST_FIRST(&src->ch_transports)) != NULL) {
|
||||
transport_unmap_channel(t);
|
||||
transport_map_channel(t, dst);
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
while((t = LIST_FIRST(&src->ch_transports)) != NULL)
|
||||
transport_map_channel(t, dst, 1);
|
||||
|
||||
channel_delete(src);
|
||||
}
|
||||
|
|
|
@ -37,9 +37,6 @@ void msleep(uint32_t msec)
|
|||
;
|
||||
}
|
||||
|
||||
#define printf(x...)
|
||||
|
||||
|
||||
int diseqc_send_msg (int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
|
||||
fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
|
||||
{
|
||||
|
|
115
src/dvb/dvb.h
|
@ -20,10 +20,32 @@
|
|||
#define DVB_H_
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "htsmsg.h"
|
||||
|
||||
TAILQ_HEAD(th_dvb_adapter_queue, th_dvb_adapter);
|
||||
RB_HEAD(th_dvb_mux_instance_tree, th_dvb_mux_instance);
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* Satconf
|
||||
*/
|
||||
|
||||
typedef struct dvb_satconf {
|
||||
char *sc_id;
|
||||
TAILQ_ENTRY(dvb_satconf) sc_adapter_link;
|
||||
int sc_port; // diseqc switchport (0 - 15)
|
||||
|
||||
char *sc_name;
|
||||
char *sc_comment;
|
||||
char *sc_lnb;
|
||||
|
||||
struct th_dvb_mux_instance_list sc_tdmis;
|
||||
|
||||
} dvb_satconf_t;
|
||||
|
||||
|
||||
|
||||
enum polarisation {
|
||||
|
@ -42,8 +64,9 @@ enum polarisation {
|
|||
typedef struct th_dvb_mux_instance {
|
||||
|
||||
RB_ENTRY(th_dvb_mux_instance) tdmi_global_link;
|
||||
RB_ENTRY(th_dvb_mux_instance) tdmi_adapter_link;
|
||||
|
||||
LIST_ENTRY(th_dvb_mux_instance) tdmi_adapter_link;
|
||||
LIST_ENTRY(th_dvb_mux_instance) tdmi_adapter_hash_link;
|
||||
|
||||
struct th_dvb_adapter *tdmi_adapter;
|
||||
|
||||
|
@ -55,8 +78,12 @@ typedef struct th_dvb_mux_instance {
|
|||
int tdmi_fec_err_ptr;
|
||||
|
||||
time_t tdmi_time;
|
||||
|
||||
|
||||
LIST_HEAD(, th_dvb_table) tdmi_tables;
|
||||
TAILQ_HEAD(, th_dvb_table) tdmi_table_queue;
|
||||
int64_t tdmi_table_start;
|
||||
int tdmi_table_initial;
|
||||
|
||||
enum {
|
||||
TDMI_FE_UNKNOWN,
|
||||
|
@ -70,12 +97,13 @@ typedef struct th_dvb_mux_instance {
|
|||
|
||||
int tdmi_quality;
|
||||
|
||||
int tdmi_enabled;
|
||||
|
||||
time_t tdmi_got_adapter;
|
||||
time_t tdmi_lost_adapter;
|
||||
|
||||
struct dvb_frontend_parameters tdmi_fe_params;
|
||||
uint8_t tdmi_polarisation; /* for DVB-S */
|
||||
uint8_t tdmi_switchport; /* for DVB-S */
|
||||
|
||||
uint16_t tdmi_transport_stream_id;
|
||||
|
||||
|
@ -88,29 +116,28 @@ typedef struct th_dvb_mux_instance {
|
|||
TAILQ_ENTRY(th_dvb_mux_instance) tdmi_scan_link;
|
||||
struct th_dvb_mux_instance_queue *tdmi_scan_queue;
|
||||
|
||||
LIST_ENTRY(th_dvb_mux_instance) tdmi_satconf_link;
|
||||
dvb_satconf_t *tdmi_satconf;
|
||||
|
||||
} th_dvb_mux_instance_t;
|
||||
|
||||
|
||||
#define DVB_MUX_SCAN_BAD 0 /* On the bad queue */
|
||||
#define DVB_MUX_SCAN_OK 1 /* Ok, don't need to scan that often */
|
||||
#define DVB_MUX_SCAN_INITIAL 2 /* To get a scan directly when a mux
|
||||
is discovered */
|
||||
|
||||
/**
|
||||
* DVB Adapter (one of these per physical adapter)
|
||||
*/
|
||||
#define TDA_MUX_HASH_WIDTH 101
|
||||
|
||||
typedef struct th_dvb_adapter {
|
||||
|
||||
TAILQ_ENTRY(th_dvb_adapter) tda_global_link;
|
||||
|
||||
struct th_dvb_mux_instance_tree tda_muxes;
|
||||
struct th_dvb_mux_instance_list tda_muxes;
|
||||
|
||||
/**
|
||||
* We keep our muxes on three queues in order to select how
|
||||
* they are to be idle-scanned
|
||||
*/
|
||||
struct th_dvb_mux_instance_queue tda_scan_queues[3];
|
||||
int tda_scan_selector; /* To alternate between bad and ok queue */
|
||||
struct th_dvb_mux_instance_queue tda_scan_queues[2];
|
||||
int tda_scan_selector;
|
||||
|
||||
struct th_dvb_mux_instance_queue tda_initial_scan_queue;
|
||||
int tda_initial_num_mux;
|
||||
|
||||
th_dvb_mux_instance_t *tda_mux_current;
|
||||
|
||||
|
@ -119,6 +146,9 @@ typedef struct th_dvb_adapter {
|
|||
const char *tda_rootpath;
|
||||
char *tda_identifier;
|
||||
uint32_t tda_autodiscovery;
|
||||
uint32_t tda_idlescan;
|
||||
uint32_t tda_logging;
|
||||
|
||||
char *tda_displayname;
|
||||
|
||||
int tda_fe_fd;
|
||||
|
@ -137,6 +167,13 @@ typedef struct th_dvb_adapter {
|
|||
gtimer_t tda_fe_monitor_timer;
|
||||
int tda_fe_monitor_hold;
|
||||
|
||||
int tda_sat; // Set if this adapter is a satellite receiver (DVB-S, etc)
|
||||
|
||||
struct dvb_satconf_queue tda_satconfs;
|
||||
|
||||
|
||||
struct th_dvb_mux_instance_list tda_mux_hash[TDA_MUX_HASH_WIDTH];
|
||||
|
||||
} th_dvb_adapter_t;
|
||||
|
||||
|
||||
|
@ -153,18 +190,24 @@ void dvb_adapter_init(void);
|
|||
|
||||
void dvb_adapter_mux_scanner(void *aux);
|
||||
|
||||
void dvb_adapter_notify_reload(th_dvb_adapter_t *tda);
|
||||
|
||||
void dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s);
|
||||
|
||||
void dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on);
|
||||
|
||||
void dvb_adapter_set_idlescan(th_dvb_adapter_t *tda, int on);
|
||||
|
||||
void dvb_adapter_set_logging(th_dvb_adapter_t *tda, int on);
|
||||
|
||||
void dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src);
|
||||
|
||||
void dvb_adapter_clean(th_dvb_adapter_t *tda);
|
||||
|
||||
int dvb_adapter_destroy(th_dvb_adapter_t *tda);
|
||||
|
||||
void dvb_adapter_notify(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_adapter_build_msg(th_dvb_adapter_t *tda);
|
||||
|
||||
/**
|
||||
* DVB Multiplex
|
||||
*/
|
||||
|
@ -176,19 +219,38 @@ void dvb_mux_destroy(th_dvb_mux_instance_t *tdmi);
|
|||
|
||||
th_dvb_mux_instance_t *dvb_mux_create(th_dvb_adapter_t *tda,
|
||||
struct dvb_frontend_parameters *fe_param,
|
||||
int polarisation, int switchport,
|
||||
int polarisation, dvb_satconf_t *sc,
|
||||
uint16_t tsid, const char *network,
|
||||
const char *logprefix);
|
||||
const char *logprefix, int enabled,
|
||||
const char *identifier);
|
||||
|
||||
void dvb_mux_set_networkname(th_dvb_mux_instance_t *tdmi, const char *name);
|
||||
|
||||
void dvb_mux_set_tsid(th_dvb_mux_instance_t *tdmi, uint16_t tsid);
|
||||
|
||||
void dvb_mux_set_enable(th_dvb_mux_instance_t *tdmi, int enabled);
|
||||
|
||||
void dvb_mux_set_satconf(th_dvb_mux_instance_t *tdmi, const char *scid,
|
||||
int save);
|
||||
|
||||
htsmsg_t *dvb_mux_build_msg(th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
void dvb_mux_notify(th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
/**
|
||||
* DVB Transport (aka DVB service)
|
||||
*/
|
||||
void dvb_transport_load(th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
th_transport_t *dvb_transport_find(th_dvb_mux_instance_t *tdmi,
|
||||
uint16_t sid, int pmt_pid);
|
||||
uint16_t sid, int pmt_pid,
|
||||
const char *identifier);
|
||||
|
||||
void dvb_transport_notify(th_transport_t *t);
|
||||
|
||||
void dvb_transport_notify_by_adapter(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_transport_build_msg(th_transport_t *t);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -211,4 +273,19 @@ void dvb_table_add_transport(th_dvb_mux_instance_t *tdmi, th_transport_t *t,
|
|||
|
||||
void dvb_table_flush_all(th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
/**
|
||||
* Satellite configuration
|
||||
*/
|
||||
void dvb_satconf_init(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_satconf_list(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_lnblist_get(void);
|
||||
|
||||
dvb_satconf_t *dvb_satconf_entry_find(th_dvb_adapter_t *tda,
|
||||
const char *id, int create);
|
||||
|
||||
void dvb_lnb_get_frequencies(const char *id,
|
||||
int *f_low, int *f_hi, int *f_switch);
|
||||
|
||||
#endif /* DVB_H_ */
|
||||
|
|
|
@ -53,12 +53,13 @@ static void *dvb_adapter_input_dvr(void *aux);
|
|||
static th_dvb_adapter_t *
|
||||
tda_alloc(void)
|
||||
{
|
||||
int i;
|
||||
th_dvb_adapter_t *tda = calloc(1, sizeof(th_dvb_adapter_t));
|
||||
pthread_mutex_init(&tda->tda_delivery_mutex, NULL);
|
||||
|
||||
for(i = 0; i < 3; i++)
|
||||
TAILQ_INIT(&tda->tda_scan_queues[i]);
|
||||
TAILQ_INIT(&tda->tda_scan_queues[0]);
|
||||
TAILQ_INIT(&tda->tda_scan_queues[1]);
|
||||
TAILQ_INIT(&tda->tda_initial_scan_queue);
|
||||
TAILQ_INIT(&tda->tda_satconfs);
|
||||
return tda;
|
||||
}
|
||||
|
||||
|
@ -76,6 +77,8 @@ tda_save(th_dvb_adapter_t *tda)
|
|||
htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type));
|
||||
htsmsg_add_str(m, "displayname", tda->tda_displayname);
|
||||
htsmsg_add_u32(m, "autodiscovery", tda->tda_autodiscovery);
|
||||
htsmsg_add_u32(m, "idlescan", tda->tda_idlescan);
|
||||
htsmsg_add_u32(m, "logging", tda->tda_logging);
|
||||
hts_settings_save(m, "dvbadapters/%s", tda->tda_identifier);
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
@ -87,8 +90,6 @@ tda_save(th_dvb_adapter_t *tda)
|
|||
void
|
||||
dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s)
|
||||
{
|
||||
htsmsg_t *m;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(!strcmp(s, tda->tda_displayname))
|
||||
|
@ -97,17 +98,12 @@ dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s)
|
|||
tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" renamed to \"%s\"",
|
||||
tda->tda_displayname, s);
|
||||
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tda->tda_identifier);
|
||||
|
||||
free(tda->tda_displayname);
|
||||
tda->tda_displayname = strdup(s);
|
||||
|
||||
tda_save(tda);
|
||||
|
||||
htsmsg_add_str(m, "name", tda->tda_displayname);
|
||||
|
||||
notify_by_msg("dvbadapter", m);
|
||||
dvb_adapter_notify(tda);
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,7 +118,7 @@ dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" mux autodiscovery set to %s",
|
||||
tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" mux autodiscovery set to: %s",
|
||||
tda->tda_displayname, on ? "On" : "Off");
|
||||
|
||||
tda->tda_autodiscovery = on;
|
||||
|
@ -130,6 +126,44 @@ dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_set_idlescan(th_dvb_adapter_t *tda, int on)
|
||||
{
|
||||
if(tda->tda_idlescan == on)
|
||||
return;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" idle mux scanning set to: %s",
|
||||
tda->tda_displayname, on ? "On" : "Off");
|
||||
|
||||
tda->tda_idlescan = on;
|
||||
tda_save(tda);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_set_logging(th_dvb_adapter_t *tda, int on)
|
||||
{
|
||||
if(tda->tda_logging == on)
|
||||
return;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" detailed logging set to: %s",
|
||||
tda->tda_displayname, on ? "On" : "Off");
|
||||
|
||||
tda->tda_logging = on;
|
||||
tda_save(tda);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -185,6 +219,9 @@ tda_add(const char *path)
|
|||
tda->tda_identifier = strdup(buf);
|
||||
|
||||
tda->tda_autodiscovery = tda->tda_type != FE_QPSK;
|
||||
tda->tda_idlescan = 1;
|
||||
|
||||
tda->tda_sat = tda->tda_type == FE_QPSK;
|
||||
|
||||
/* Come up with an initial displayname, user can change it and it will
|
||||
be overridden by any stored settings later on */
|
||||
|
@ -199,6 +236,11 @@ tda_add(const char *path)
|
|||
pthread_create(&ptid, NULL, dvb_adapter_input_dvr, tda);
|
||||
|
||||
dvb_table_init(tda);
|
||||
|
||||
if(tda->tda_sat)
|
||||
dvb_satconf_init(tda);
|
||||
|
||||
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -250,6 +292,8 @@ dvb_adapter_init(void)
|
|||
tda->tda_displayname = strdup(name);
|
||||
|
||||
htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery);
|
||||
htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan);
|
||||
htsmsg_get_u32(c, "logging", &tda->tda_logging);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
@ -259,20 +303,6 @@ dvb_adapter_init(void)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_notify_reload(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tda->tda_identifier);
|
||||
|
||||
htsmsg_add_u32(m, "reload", 1);
|
||||
notify_by_msg("dvbadapter", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If nobody is subscribing, cycle thru all muxes to get some stats
|
||||
* and EIT updates
|
||||
|
@ -284,35 +314,38 @@ dvb_adapter_mux_scanner(void *aux)
|
|||
th_dvb_mux_instance_t *tdmi;
|
||||
int i;
|
||||
|
||||
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 10);
|
||||
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 20);
|
||||
|
||||
if(LIST_FIRST(&tda->tda_muxes) == NULL)
|
||||
return; // No muxes configured
|
||||
|
||||
if(transport_compute_weight(&tda->tda_transports) > 0)
|
||||
return; /* someone is here */
|
||||
|
||||
/* Check if we have muxes pending for quickscan, if so, choose them */
|
||||
tdmi = TAILQ_FIRST(&tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL]);
|
||||
|
||||
/* If not, alternate between the other two (bad and OK) */
|
||||
if(tdmi == NULL) {
|
||||
for(i = 0; i < 2; i++) {
|
||||
tda->tda_scan_selector = !tda->tda_scan_selector;
|
||||
tdmi = TAILQ_FIRST(&tda->tda_scan_queues[tda->tda_scan_selector]);
|
||||
if(tdmi != NULL) {
|
||||
assert(tdmi->tdmi_scan_queue ==
|
||||
&tda->tda_scan_queues[tda->tda_scan_selector]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(tdmi->tdmi_scan_queue ==
|
||||
&tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL]);
|
||||
if((tdmi = TAILQ_FIRST(&tda->tda_initial_scan_queue)) != NULL) {
|
||||
dvb_fe_tune(tdmi, "Initial autoscan");
|
||||
return;
|
||||
}
|
||||
|
||||
if(tdmi != NULL) {
|
||||
/* Push to tail of queue */
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
dvb_fe_tune(tdmi, "Autoscan");
|
||||
if(!tda->tda_idlescan && TAILQ_FIRST(&tda->tda_scan_queues[0]) == NULL) {
|
||||
/* Idlescan is disabled and no muxes are bad.
|
||||
If the currently tuned mux is ok, we can stick to it */
|
||||
|
||||
tdmi = tda->tda_mux_current;
|
||||
|
||||
if(tdmi != NULL && tdmi->tdmi_quality > 90)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Alternate between the other two (bad and OK) */
|
||||
for(i = 0; i < 2; i++) {
|
||||
tda->tda_scan_selector = !tda->tda_scan_selector;
|
||||
tdmi = TAILQ_FIRST(&tda->tda_scan_queues[tda->tda_scan_selector]);
|
||||
if(tdmi != NULL) {
|
||||
dvb_fe_tune(tdmi, "Autoscan");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,18 +361,19 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
while((tdmi_dst = RB_FIRST(&dst->tda_muxes)) != NULL)
|
||||
while((tdmi_dst = LIST_FIRST(&dst->tda_muxes)) != NULL)
|
||||
dvb_mux_destroy(tdmi_dst);
|
||||
|
||||
RB_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link) {
|
||||
LIST_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link) {
|
||||
|
||||
tdmi_dst = dvb_mux_create(dst,
|
||||
&tdmi_src->tdmi_fe_params,
|
||||
tdmi_src->tdmi_polarisation,
|
||||
tdmi_src->tdmi_switchport,
|
||||
tdmi_src->tdmi_satconf,
|
||||
tdmi_src->tdmi_transport_stream_id,
|
||||
tdmi_src->tdmi_network,
|
||||
"copy operation");
|
||||
"copy operation", tdmi_src->tdmi_enabled,
|
||||
NULL);
|
||||
|
||||
|
||||
assert(tdmi_dst != NULL);
|
||||
|
@ -347,10 +381,10 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, tht_mux_link) {
|
||||
t_dst = dvb_transport_find(tdmi_dst,
|
||||
t_src->tht_dvb_service_id,
|
||||
t_src->tht_pmt_pid);
|
||||
t_src->tht_pmt_pid, NULL);
|
||||
|
||||
t_dst->tht_pcr_pid = t_src->tht_pcr_pid;
|
||||
t_dst->tht_disabled = t_src->tht_disabled;
|
||||
t_dst->tht_enabled = t_src->tht_enabled;
|
||||
t_dst->tht_servicetype = t_src->tht_servicetype;
|
||||
t_dst->tht_scrambled = t_src->tht_scrambled;
|
||||
|
||||
|
@ -360,11 +394,8 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
if(t_src->tht_svcname != NULL)
|
||||
t_dst->tht_svcname = strdup(t_src->tht_svcname);
|
||||
|
||||
if(t_src->tht_chname != NULL)
|
||||
t_dst->tht_chname = strdup(t_src->tht_chname);
|
||||
|
||||
if(t_src->tht_ch != NULL)
|
||||
transport_map_channel(t_dst, t_src->tht_ch);
|
||||
transport_map_channel(t_dst, t_src->tht_ch, 0);
|
||||
|
||||
pthread_mutex_lock(&t_src->tht_stream_mutex);
|
||||
|
||||
|
@ -381,6 +412,7 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
st_dst->st_caid = st_src->st_caid;
|
||||
}
|
||||
|
||||
t_dst->tht_config_change(t_dst); // Save config
|
||||
pthread_mutex_unlock(&t_src->tht_stream_mutex);
|
||||
|
||||
}
|
||||
|
@ -404,7 +436,7 @@ dvb_adapter_destroy(th_dvb_adapter_t *tda)
|
|||
|
||||
hts_settings_remove("dvbadapters/%s", tda->tda_identifier);
|
||||
|
||||
while((tdmi = RB_FIRST(&tda->tda_muxes)) != NULL)
|
||||
while((tdmi = LIST_FIRST(&tda->tda_muxes)) != NULL)
|
||||
dvb_mux_destroy(tdmi);
|
||||
|
||||
TAILQ_REMOVE(&dvb_adapters, tda, tda_global_link);
|
||||
|
@ -464,3 +496,53 @@ dvb_adapter_input_dvr(void *aux)
|
|||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_adapter_build_msg(th_dvb_adapter_t *tda)
|
||||
{
|
||||
char buf[100];
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_transport_t *t;
|
||||
|
||||
int nummux = 0;
|
||||
int numsvc = 0;
|
||||
|
||||
htsmsg_add_str(m, "identifier", tda->tda_identifier);
|
||||
htsmsg_add_str(m, "name", tda->tda_displayname);
|
||||
htsmsg_add_str(m, "path", tda->tda_rootpath);
|
||||
htsmsg_add_str(m, "devicename", tda->tda_fe_info->name);
|
||||
|
||||
// XXX: bad bad bad slow slow slow
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
nummux++;
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
numsvc++;
|
||||
}
|
||||
}
|
||||
|
||||
htsmsg_add_u32(m, "services", numsvc);
|
||||
htsmsg_add_u32(m, "muxes", nummux);
|
||||
htsmsg_add_u32(m, "initialMuxes", tda->tda_initial_num_mux);
|
||||
|
||||
if(tda->tda_mux_current != NULL) {
|
||||
dvb_mux_nicename(buf, sizeof(buf), tda->tda_mux_current);
|
||||
htsmsg_add_str(m, "currentMux", buf);
|
||||
}
|
||||
|
||||
htsmsg_add_u32(m, "satConf", tda->tda_sat);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_notify(th_dvb_adapter_t *tda)
|
||||
{
|
||||
notify_by_msg("dvbAdapter", dvb_adapter_build_msg(tda));
|
||||
}
|
||||
|
|
112
src/dvb/dvb_fe.c
|
@ -39,33 +39,6 @@
|
|||
#include "notify.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_notify_mux_quality(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
|
||||
htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
|
||||
notify_by_msg("dvbmux", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_notify_mux_status(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
|
||||
htsmsg_add_str(m, "status", dvb_mux_status(tdmi));
|
||||
notify_by_msg("dvbmux", m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front end monitor
|
||||
*
|
||||
|
@ -76,14 +49,15 @@ dvb_fe_monitor(void *aux)
|
|||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
fe_status_t fe_status;
|
||||
int status, v, savemux = 0, vv, i, fec, q;
|
||||
int status, v, update = 0, vv, i, fec, q;
|
||||
th_dvb_mux_instance_t *tdmi = tda->tda_mux_current;
|
||||
char buf[50];
|
||||
|
||||
assert(tdmi != NULL);
|
||||
|
||||
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
|
||||
|
||||
if(tdmi == NULL)
|
||||
return;
|
||||
|
||||
/**
|
||||
* Read out front end status
|
||||
*/
|
||||
|
@ -140,13 +114,14 @@ dvb_fe_monitor(void *aux)
|
|||
|
||||
if(status != tdmi->tdmi_fe_status) {
|
||||
tdmi->tdmi_fe_status = status;
|
||||
dvb_notify_mux_status(tdmi);
|
||||
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
|
||||
DEBUGLOG("dvb", "\"%s\" on adapter \"%s\", status changed to %s",
|
||||
buf, tda->tda_displayname, dvb_mux_status(tdmi));
|
||||
savemux = 1;
|
||||
if(tda->tda_logging) {
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
tvhlog(LOG_INFO,
|
||||
"dvb", "\"%s\" on adapter \"%s\", status changed to %s",
|
||||
buf, tda->tda_displayname, dvb_mux_status(tdmi));
|
||||
}
|
||||
update = 1;
|
||||
}
|
||||
|
||||
if(status != TDMI_FE_UNKNOWN) {
|
||||
|
@ -154,20 +129,22 @@ dvb_fe_monitor(void *aux)
|
|||
q = MAX(MIN(q, 100), 0);
|
||||
if(q != tdmi->tdmi_quality) {
|
||||
tdmi->tdmi_quality = q;
|
||||
dvb_notify_mux_quality(tdmi);
|
||||
savemux = 1;
|
||||
update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(savemux)
|
||||
if(update) {
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
|
||||
notify_by_msg("dvbMux", m);
|
||||
|
||||
dvb_mux_save(tdmi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Stop the given TDMI
|
||||
*/
|
||||
|
@ -175,19 +152,23 @@ void
|
|||
dvb_fe_stop(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
|
||||
assert(tdmi == tda->tda_mux_current);
|
||||
tda->tda_mux_current = NULL;
|
||||
|
||||
if(tdmi->tdmi_table_initial) {
|
||||
tdmi->tdmi_table_initial = 0;
|
||||
tda->tda_initial_num_mux--;
|
||||
}
|
||||
|
||||
dvb_table_flush_all(tdmi);
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL)
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
assert(tdmi->tdmi_scan_queue == NULL);
|
||||
|
||||
if(tdmi->tdmi_quality == 100) {
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_OK];
|
||||
} else {
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_BAD];
|
||||
if(tdmi->tdmi_enabled) {
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[tdmi->tdmi_quality == 100];
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
}
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
|
||||
time(&tdmi->tdmi_lost_adapter);
|
||||
}
|
||||
|
@ -204,12 +185,18 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
|
|||
struct dvb_frontend_parameters p = tdmi->tdmi_fe_params;
|
||||
char buf[256];
|
||||
int r;
|
||||
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(tda->tda_mux_current == tdmi)
|
||||
return;
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL) {
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
tdmi->tdmi_scan_queue = NULL;
|
||||
}
|
||||
|
||||
if(tda->tda_mux_current != NULL)
|
||||
dvb_fe_stop(tda->tda_mux_current);
|
||||
|
||||
|
@ -217,20 +204,25 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
|
|||
if(tda->tda_type == FE_QPSK) {
|
||||
|
||||
/* DVB-S */
|
||||
int lowfreq, hifreq, switchfreq, hiband;
|
||||
|
||||
// lowfreq = atoi(config_get_str("lnb_lowfreq", "9750000" ));
|
||||
// hifreq = atoi(config_get_str("lnb_hifreq", "10600000"));
|
||||
// switchfreq = atoi(config_get_str("lnb_switchfreq", "11700000"));
|
||||
dvb_satconf_t *sc;
|
||||
int port, lowfreq, hifreq, switchfreq, hiband;
|
||||
|
||||
lowfreq = 9750000;
|
||||
hifreq = 10600000;
|
||||
switchfreq = 11700000;
|
||||
port = 0;
|
||||
|
||||
if((sc = tdmi->tdmi_satconf) != NULL) {
|
||||
port = sc->sc_port;
|
||||
|
||||
if(sc->sc_lnb != NULL)
|
||||
dvb_lnb_get_frequencies(sc->sc_lnb, &lowfreq, &hifreq, &switchfreq);
|
||||
}
|
||||
|
||||
hiband = switchfreq && p.frequency > switchfreq;
|
||||
|
||||
diseqc_setup(tda->tda_fe_fd,
|
||||
0, /* switch position */
|
||||
port,
|
||||
tdmi->tdmi_polarisation == POLARISATION_HORIZONTAL,
|
||||
hiband);
|
||||
|
||||
|
@ -246,8 +238,10 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
|
|||
|
||||
tda->tda_fe_monitor_hold = 4;
|
||||
|
||||
DEBUGLOG("dvb", "\"%s\" tuning to \"%s\" (%s)", tda->tda_rootpath, buf,
|
||||
reason);
|
||||
if(tda->tda_logging)
|
||||
tvhlog(LOG_INFO,
|
||||
"dvb", "\"%s\" tuning to \"%s\" (%s)", tda->tda_rootpath, buf,
|
||||
reason);
|
||||
|
||||
r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, &p);
|
||||
if(r != 0) {
|
||||
|
@ -261,4 +255,6 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
|
|||
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
|
||||
|
||||
dvb_table_add_default(tdmi);
|
||||
|
||||
dvb_adapter_notify(tda);
|
||||
}
|
||||
|
|
|
@ -57,6 +57,24 @@ static struct strtab muxfestatustab[] = {
|
|||
{ "OK", TDMI_FE_OK },
|
||||
};
|
||||
|
||||
static void tdmi_set_enable(th_dvb_mux_instance_t *tdmi, int enabled);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
mux_link_initial(th_dvb_adapter_t *tda, th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
int was_empty = TAILQ_FIRST(&tda->tda_initial_scan_queue) == NULL;
|
||||
|
||||
tdmi->tdmi_scan_queue = &tda->tda_initial_scan_queue;
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
|
||||
if(was_empty && (tda->tda_mux_current == NULL ||
|
||||
tda->tda_mux_current->tdmi_table_initial == 0))
|
||||
dvb_adapter_mux_scanner(tda);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a readable status text for the given mux
|
||||
|
@ -68,23 +86,6 @@ dvb_mux_status(th_dvb_mux_instance_t *tdmi)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
tdmi_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b)
|
||||
{
|
||||
if(a->tdmi_switchport != b->tdmi_switchport)
|
||||
return a->tdmi_switchport - b->tdmi_switchport;
|
||||
|
||||
if(a->tdmi_fe_params.frequency != b->tdmi_fe_params.frequency)
|
||||
return a->tdmi_fe_params.frequency - b->tdmi_fe_params.frequency;
|
||||
|
||||
return a->tdmi_polarisation - b->tdmi_polarisation;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -100,34 +101,63 @@ tdmi_global_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b)
|
|||
*/
|
||||
th_dvb_mux_instance_t *
|
||||
dvb_mux_create(th_dvb_adapter_t *tda, struct dvb_frontend_parameters *fe_param,
|
||||
int polarisation, int switchport,
|
||||
uint16_t tsid, const char *network, const char *source)
|
||||
int polarisation, dvb_satconf_t *sc,
|
||||
uint16_t tsid, const char *network, const char *source,
|
||||
int enabled, const char *identifier)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
static th_dvb_mux_instance_t *skel;
|
||||
th_dvb_mux_instance_t *tdmi, *c;
|
||||
unsigned int hash;
|
||||
char buf[200];
|
||||
char qpsktxt[20];
|
||||
int entries_before = tda->tda_muxes.entries;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(skel == NULL)
|
||||
skel = calloc(1, sizeof(th_dvb_mux_instance_t));
|
||||
hash = (fe_param->frequency + polarisation) % TDA_MUX_HASH_WIDTH;
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_mux_hash[hash], tdmi_adapter_hash_link) {
|
||||
if(tdmi->tdmi_fe_params.frequency == fe_param->frequency &&
|
||||
tdmi->tdmi_polarisation == polarisation &&
|
||||
tdmi->tdmi_satconf == sc)
|
||||
/* Mux already exist */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
skel->tdmi_polarisation = polarisation;
|
||||
skel->tdmi_switchport = switchport;
|
||||
skel->tdmi_fe_params.frequency = fe_param->frequency;
|
||||
tdmi = calloc(1, sizeof(th_dvb_mux_instance_t));
|
||||
|
||||
tdmi = RB_INSERT_SORTED(&tda->tda_muxes, skel, tdmi_adapter_link, tdmi_cmp);
|
||||
if(tdmi != NULL)
|
||||
if(identifier == NULL) {
|
||||
char qpsktxt[20];
|
||||
|
||||
if(tda->tda_sat)
|
||||
snprintf(qpsktxt, sizeof(qpsktxt), "_%s",
|
||||
dvb_polarisation_to_str(polarisation));
|
||||
else
|
||||
qpsktxt[0] = 0;
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%d%s%s%s",
|
||||
tda->tda_identifier,fe_param->frequency, qpsktxt,
|
||||
sc ? "_satconf_" : "", sc ? sc->sc_id : "");
|
||||
|
||||
tdmi->tdmi_identifier = strdup(buf);
|
||||
} else {
|
||||
tdmi->tdmi_identifier = strdup(identifier);
|
||||
}
|
||||
|
||||
c = RB_INSERT_SORTED(&dvb_muxes, tdmi, tdmi_global_link, tdmi_global_cmp);
|
||||
|
||||
if(c != NULL) {
|
||||
/* Global identifier collision, not good, not good at all */
|
||||
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"Multiple DVB multiplexes with same identifier \"%s\" "
|
||||
"one is skipped", tdmi->tdmi_identifier);
|
||||
free(tdmi->tdmi_identifier);
|
||||
free(tdmi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tdmi = skel;
|
||||
skel = NULL;
|
||||
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL];
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
|
||||
tdmi->tdmi_enabled = enabled;
|
||||
|
||||
TAILQ_INIT(&tdmi->tdmi_table_queue);
|
||||
|
||||
tdmi->tdmi_transport_stream_id = tsid;
|
||||
|
@ -135,36 +165,34 @@ dvb_mux_create(th_dvb_adapter_t *tda, struct dvb_frontend_parameters *fe_param,
|
|||
tdmi->tdmi_network = network ? strdup(network) : NULL;
|
||||
tdmi->tdmi_quality = 100;
|
||||
|
||||
if(entries_before == 0 && tda->tda_rootpath != NULL) {
|
||||
/* First mux on adapter with backing hardware, start scanner */
|
||||
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
|
||||
}
|
||||
|
||||
memcpy(&tdmi->tdmi_fe_params, fe_param,
|
||||
sizeof(struct dvb_frontend_parameters));
|
||||
|
||||
if(tda->tda_type == FE_QPSK)
|
||||
snprintf(qpsktxt, sizeof(qpsktxt), "_%s_%d",
|
||||
dvb_polarisation_to_str(polarisation), switchport);
|
||||
else
|
||||
qpsktxt[0] = 0;
|
||||
if(sc != NULL) {
|
||||
tdmi->tdmi_satconf = sc;
|
||||
LIST_INSERT_HEAD(&sc->sc_tdmis, tdmi, tdmi_satconf_link);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%d%s",
|
||||
tda->tda_identifier,fe_param->frequency, qpsktxt);
|
||||
|
||||
tdmi->tdmi_identifier = strdup(buf);
|
||||
|
||||
RB_INSERT_SORTED(&dvb_muxes, tdmi, tdmi_global_link, tdmi_global_cmp);
|
||||
LIST_INSERT_HEAD(&tda->tda_mux_hash[hash], tdmi, tdmi_adapter_hash_link);
|
||||
LIST_INSERT_HEAD(&tda->tda_muxes, tdmi, tdmi_adapter_link);
|
||||
|
||||
if(source != NULL) {
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
tvhlog(LOG_NOTICE, "dvb", "New mux \"%s\" created by %s", buf, source);
|
||||
|
||||
dvb_mux_save(tdmi);
|
||||
dvb_adapter_notify_reload(tda);
|
||||
dvb_adapter_notify(tda);
|
||||
}
|
||||
|
||||
dvb_transport_load(tdmi);
|
||||
dvb_mux_notify(tdmi);
|
||||
|
||||
if(enabled) {
|
||||
tda->tda_initial_num_mux++;
|
||||
tdmi->tdmi_table_initial = 1;
|
||||
mux_link_initial(tda, tdmi);
|
||||
}
|
||||
|
||||
return tdmi;
|
||||
}
|
||||
|
@ -181,25 +209,40 @@ dvb_mux_destroy(th_dvb_mux_instance_t *tdmi)
|
|||
lock_assert(&global_lock);
|
||||
|
||||
hts_settings_remove("dvbmuxes/%s/%s",
|
||||
tda->tda_identifier, tdmi->tdmi_identifier);
|
||||
tda->tda_identifier, tdmi->tdmi_identifier);
|
||||
|
||||
while((t = LIST_FIRST(&tdmi->tdmi_transports)) != NULL)
|
||||
while((t = LIST_FIRST(&tdmi->tdmi_transports)) != NULL) {
|
||||
hts_settings_remove("dvbtransports/%s/%s",
|
||||
t->tht_dvb_mux_instance->tdmi_identifier,
|
||||
t->tht_identifier);
|
||||
transport_destroy(t);
|
||||
}
|
||||
|
||||
dvb_transport_notify_by_adapter(tda);
|
||||
|
||||
if(tda->tda_mux_current == tdmi)
|
||||
dvb_fe_stop(tda->tda_mux_current);
|
||||
|
||||
if(tdmi->tdmi_satconf != NULL)
|
||||
LIST_REMOVE(tdmi, tdmi_satconf_link);
|
||||
|
||||
RB_REMOVE(&dvb_muxes, tdmi, tdmi_global_link);
|
||||
RB_REMOVE(&tda->tda_muxes, tdmi, tdmi_adapter_link);
|
||||
LIST_REMOVE(tdmi, tdmi_adapter_link);
|
||||
LIST_REMOVE(tdmi, tdmi_adapter_hash_link);
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL)
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
|
||||
if(tdmi->tdmi_table_initial)
|
||||
tda->tda_initial_num_mux--;
|
||||
|
||||
hts_settings_remove("dvbmuxes/%s", tdmi->tdmi_identifier);
|
||||
|
||||
free(tdmi->tdmi_network);
|
||||
free(tdmi->tdmi_identifier);
|
||||
free(tdmi);
|
||||
|
||||
dvb_adapter_notify(tda);
|
||||
}
|
||||
|
||||
|
||||
|
@ -293,6 +336,7 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi)
|
|||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
|
||||
htsmsg_add_u32(m, "enabled", tdmi->tdmi_enabled);
|
||||
htsmsg_add_str(m, "status", dvb_mux_status(tdmi));
|
||||
|
||||
htsmsg_add_u32(m, "transportstreamid", tdmi->tdmi_transport_stream_id);
|
||||
|
@ -333,9 +377,7 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi)
|
|||
|
||||
htsmsg_add_str(m, "polarisation",
|
||||
val2str(tdmi->tdmi_polarisation, poltab));
|
||||
|
||||
htsmsg_add_u32(m, "switchport", tdmi->tdmi_switchport);
|
||||
break;
|
||||
break;
|
||||
|
||||
case FE_QAM:
|
||||
htsmsg_add_u32(m, "symbol_rate", f->u.qam.symbol_rate);
|
||||
|
@ -351,6 +393,9 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi)
|
|||
break;
|
||||
}
|
||||
|
||||
if(tdmi->tdmi_satconf != NULL)
|
||||
htsmsg_add_str(m, "satconf", tdmi->tdmi_satconf->sc_id);
|
||||
|
||||
hts_settings_save(m, "dvbmuxes/%s/%s",
|
||||
tdmi->tdmi_adapter->tda_identifier, tdmi->tdmi_identifier);
|
||||
htsmsg_destroy(m);
|
||||
|
@ -361,7 +406,7 @@ dvb_mux_save(th_dvb_mux_instance_t *tdmi)
|
|||
*
|
||||
*/
|
||||
static const char *
|
||||
tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m)
|
||||
tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
struct dvb_frontend_parameters f;
|
||||
|
@ -369,7 +414,8 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m)
|
|||
int r;
|
||||
int polarisation = 0;
|
||||
unsigned int switchport = 0;
|
||||
unsigned int tsid, u32;
|
||||
unsigned int tsid, u32, enabled;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
|
||||
|
@ -456,27 +502,24 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m)
|
|||
if(htsmsg_get_u32(m, "transportstreamid", &tsid))
|
||||
tsid = 0xffff;
|
||||
|
||||
tdmi = dvb_mux_create(tda, &f, polarisation, switchport,
|
||||
tsid, htsmsg_get_str(m, "network"), NULL);
|
||||
if(htsmsg_get_u32(m, "enabled", &enabled))
|
||||
enabled = 1;
|
||||
|
||||
if((s = htsmsg_get_str(m, "satconf")) != NULL)
|
||||
sc = dvb_satconf_entry_find(tda, s, 0);
|
||||
else
|
||||
sc = NULL;
|
||||
|
||||
tdmi = dvb_mux_create(tda, &f, polarisation, sc,
|
||||
tsid, htsmsg_get_str(m, "network"), NULL, enabled,
|
||||
identifier);
|
||||
if(tdmi != NULL) {
|
||||
|
||||
if((s = htsmsg_get_str(m, "status")) != NULL)
|
||||
tdmi->tdmi_fe_status = str2val(s, muxfestatustab);
|
||||
|
||||
if(!htsmsg_get_u32(m, "quality", &u32)) {
|
||||
if(!htsmsg_get_u32(m, "quality", &u32))
|
||||
tdmi->tdmi_quality = u32;
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL)
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
|
||||
if(tdmi->tdmi_quality == 100) {
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_OK];
|
||||
} else {
|
||||
tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_BAD];
|
||||
}
|
||||
TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
}
|
||||
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -499,27 +542,122 @@ dvb_mux_load(th_dvb_adapter_t *tda)
|
|||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
|
||||
tdmi_create_by_msg(tda, c);
|
||||
tdmi_create_by_msg(tda, c, f->hmf_name);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_mux_set_networkname(th_dvb_mux_instance_t *tdmi, const char *networkname)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
char buf[100];
|
||||
htsmsg_t *m;
|
||||
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
|
||||
free((void *)tdmi->tdmi_network);
|
||||
free(tdmi->tdmi_network);
|
||||
tdmi->tdmi_network = strdup(networkname);
|
||||
dvb_mux_save(tdmi);
|
||||
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
htsmsg_add_str(m, "name", buf);
|
||||
notify_by_msg("dvbmux", m);
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
htsmsg_add_str(m, "network", tdmi->tdmi_network ?: "");
|
||||
notify_by_msg("dvbMux", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_mux_set_tsid(th_dvb_mux_instance_t *tdmi, uint16_t tsid)
|
||||
{
|
||||
htsmsg_t *m;
|
||||
|
||||
tdmi->tdmi_transport_stream_id = tsid;
|
||||
|
||||
dvb_mux_save(tdmi);
|
||||
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
htsmsg_add_u32(m, "muxid", tdmi->tdmi_transport_stream_id);
|
||||
notify_by_msg("dvbMux", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
tdmi_set_enable(th_dvb_mux_instance_t *tdmi, int enabled)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
|
||||
if(tdmi->tdmi_enabled == enabled)
|
||||
return;
|
||||
|
||||
if(tdmi->tdmi_enabled) {
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL) {
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
tdmi->tdmi_scan_queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tdmi->tdmi_enabled = enabled;
|
||||
|
||||
if(enabled)
|
||||
mux_link_initial(tda, tdmi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configurable by user
|
||||
*/
|
||||
void
|
||||
dvb_mux_set_enable(th_dvb_mux_instance_t *tdmi, int enabled)
|
||||
{
|
||||
tdmi_set_enable(tdmi, enabled);
|
||||
dvb_mux_save(tdmi);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_mux_build_msg(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
char buf[100];
|
||||
|
||||
m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
htsmsg_add_u32(m, "enabled", tdmi->tdmi_enabled);
|
||||
htsmsg_add_str(m, "network", tdmi->tdmi_network ?: "");
|
||||
dvb_mux_nicefreq(buf, sizeof(buf), tdmi);
|
||||
|
||||
htsmsg_add_str(m, "freq", buf);
|
||||
htsmsg_add_str(m, "pol",
|
||||
dvb_polarisation_to_str_long(tdmi->tdmi_polarisation));
|
||||
|
||||
if(tdmi->tdmi_satconf != NULL)
|
||||
htsmsg_add_str(m, "satconf", tdmi->tdmi_satconf->sc_id);
|
||||
|
||||
if(tdmi->tdmi_transport_stream_id != 0xffff)
|
||||
htsmsg_add_u32(m, "muxid", tdmi->tdmi_transport_stream_id);
|
||||
|
||||
htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_mux_notify(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
notify_by_msg("dvbMux", dvb_mux_build_msg(tdmi));
|
||||
}
|
||||
|
|
|
@ -40,17 +40,17 @@
|
|||
*/
|
||||
static void
|
||||
dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
|
||||
const char *source)
|
||||
const char *source, const char *satconf)
|
||||
{
|
||||
struct dvb_frontend_parameters f;
|
||||
int i;
|
||||
int polarisation;
|
||||
int switchport;
|
||||
int i, polarisation;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
sc = dvb_satconf_entry_find(tda, satconf, 0);
|
||||
|
||||
for(i = 0; i < num; i++) {
|
||||
|
||||
polarisation = 0;
|
||||
switchport = 0;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
|
||||
|
@ -92,8 +92,7 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
|
|||
break;
|
||||
}
|
||||
|
||||
dvb_mux_create(tda, &f, polarisation, switchport, 0xffff, NULL,
|
||||
source);
|
||||
dvb_mux_create(tda, &f, polarisation, sc, 0xffff, NULL, source, 1, NULL);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +102,8 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
|
|||
*
|
||||
*/
|
||||
int
|
||||
dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id)
|
||||
dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id,
|
||||
const char *satconf)
|
||||
{
|
||||
const struct region *r;
|
||||
const struct network *n;
|
||||
|
@ -135,7 +135,7 @@ dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id)
|
|||
|
||||
for(j = 0; j < nn; j++) {
|
||||
if(!strcmp(n[j].name, id)) {
|
||||
dvb_mux_preconf_add(tda, n[j].muxes, n[j].nmuxes, source);
|
||||
dvb_mux_preconf_add(tda, n[j].muxes, n[j].nmuxes, source, satconf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
htsmsg_t *dvb_mux_preconf_get_node(int fetype, const char *node);
|
||||
|
||||
int dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id);
|
||||
int dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id,
|
||||
const char *satconf);
|
||||
|
||||
#endif /* DVB_MUXCONFIG_H */
|
||||
|
|
331
src/dvb/dvb_satconf.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Satconf
|
||||
* Copyright (C) 2009 Andreas Öman
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "dvb.h"
|
||||
#include "dtable.h"
|
||||
#include "notify.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
satconf_notify(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "adapterId", tda->tda_identifier);
|
||||
notify_by_msg("dvbSatConf", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
dvb_satconf_t *
|
||||
dvb_satconf_entry_find(th_dvb_adapter_t *tda, const char *id, int create)
|
||||
{
|
||||
char buf[20];
|
||||
dvb_satconf_t *sc;
|
||||
static int tally;
|
||||
|
||||
if(id != NULL) {
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link)
|
||||
if(!strcmp(sc->sc_id, id))
|
||||
return sc;
|
||||
}
|
||||
if(create == 0)
|
||||
return NULL;
|
||||
|
||||
if(id == NULL) {
|
||||
tally++;
|
||||
snprintf(buf, sizeof(buf), "%d", tally);
|
||||
id = buf;
|
||||
} else {
|
||||
tally = MAX(atoi(id), tally);
|
||||
}
|
||||
|
||||
sc = calloc(1, sizeof(dvb_satconf_t));
|
||||
sc->sc_id = strdup(id);
|
||||
sc->sc_lnb = strdup("Universal");
|
||||
TAILQ_INSERT_TAIL(&tda->tda_satconfs, sc, sc_adapter_link);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
satconf_destroy(th_dvb_adapter_t *tda, dvb_satconf_t *sc)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
||||
while((tdmi = LIST_FIRST(&sc->sc_tdmis)) != NULL) {
|
||||
tdmi->tdmi_satconf = NULL;
|
||||
LIST_REMOVE(tdmi, tdmi_satconf_link);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&tda->tda_satconfs, sc, sc_adapter_link);
|
||||
free(sc->sc_id);
|
||||
free(sc->sc_name);
|
||||
free(sc->sc_comment);
|
||||
free(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_record_build(dvb_satconf_t *sc)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "id", sc->sc_id);
|
||||
htsmsg_add_u32(m, "port", sc->sc_port);
|
||||
htsmsg_add_str(m, "name", sc->sc_name ?: "");
|
||||
htsmsg_add_str(m, "comment", sc->sc_comment ?: "");
|
||||
htsmsg_add_str(m, "lnb", sc->sc_lnb);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_update(void *opaque, const char *id, htsmsg_t *values,
|
||||
int maycreate)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
uint32_t u32;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
if((sc = dvb_satconf_entry_find(tda, id, maycreate)) == NULL)
|
||||
return NULL;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvh_str_update(&sc->sc_name, htsmsg_get_str(values, "name"));
|
||||
tvh_str_update(&sc->sc_comment, htsmsg_get_str(values, "comment"));
|
||||
tvh_str_update(&sc->sc_lnb, htsmsg_get_str(values, "lnb"));
|
||||
|
||||
if(!htsmsg_get_u32(values, "port", &u32))
|
||||
sc->sc_port = u32;
|
||||
|
||||
satconf_notify(tda);
|
||||
|
||||
return satconf_record_build(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
satconf_entry_delete(void *opaque, const char *id)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
if((sc = dvb_satconf_entry_find(tda, id, 0)) == NULL)
|
||||
return -1;
|
||||
satconf_destroy(tda, sc);
|
||||
satconf_notify(tda);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_get_all(void *opaque)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
htsmsg_t *r = htsmsg_create_list();
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link)
|
||||
htsmsg_add_msg(r, NULL, satconf_record_build(sc));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_get(void *opaque, const char *id)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
dvb_satconf_t *sc;
|
||||
if((sc = dvb_satconf_entry_find(tda, id, 0)) == NULL)
|
||||
return NULL;
|
||||
return satconf_record_build(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_create(void *opaque)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
return satconf_record_build(dvb_satconf_entry_find(tda, NULL, 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const dtable_class_t satconf_dtc = {
|
||||
.dtc_record_get = satconf_entry_get,
|
||||
.dtc_record_get_all = satconf_entry_get_all,
|
||||
.dtc_record_create = satconf_entry_create,
|
||||
.dtc_record_update = satconf_entry_update,
|
||||
.dtc_record_delete = satconf_entry_delete,
|
||||
.dtc_read_access = ACCESS_ADMIN,
|
||||
.dtc_write_access = ACCESS_ADMIN,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_satconf_init(th_dvb_adapter_t *tda)
|
||||
{
|
||||
dtable_t *dt;
|
||||
char name[256];
|
||||
dvb_satconf_t *sc;
|
||||
htsmsg_t *r;
|
||||
|
||||
snprintf(name, sizeof(name), "dvbsatconf/%s", tda->tda_identifier);
|
||||
|
||||
dt = dtable_create(&satconf_dtc, name, tda);
|
||||
if(!dtable_load(dt)) {
|
||||
sc = dvb_satconf_entry_find(tda, NULL, 1);
|
||||
sc->sc_comment = strdup("Default satconf entry");
|
||||
sc->sc_name = strdup("Default (Port 0, Universal LNB)");
|
||||
|
||||
r = satconf_record_build(sc);
|
||||
dtable_record_store(dt, sc->sc_id, r);
|
||||
htsmsg_destroy(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_satconf_list(th_dvb_adapter_t *tda)
|
||||
{
|
||||
dvb_satconf_t *sc;
|
||||
htsmsg_t *array = htsmsg_create_list();
|
||||
htsmsg_t *m;
|
||||
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link) {
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "identifier", sc->sc_id);
|
||||
htsmsg_add_str(m, "name", sc->sc_name);
|
||||
htsmsg_add_msg(array, NULL, m);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
add_to_lnblist(htsmsg_t *array, const char *n)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "identifier", n);
|
||||
htsmsg_add_msg(array, NULL, m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_lnblist_get(void)
|
||||
{
|
||||
htsmsg_t *array = htsmsg_create_list();
|
||||
|
||||
add_to_lnblist(array, "Universal");
|
||||
add_to_lnblist(array, "DBS");
|
||||
add_to_lnblist(array, "Standard");
|
||||
add_to_lnblist(array, "Enhanced");
|
||||
add_to_lnblist(array, "C-Band");
|
||||
add_to_lnblist(array, "C-Multi");
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_lnb_get_frequencies(const char *id, int *f_low, int *f_hi, int *f_switch)
|
||||
{
|
||||
if(!strcmp(id, "Universal")) {
|
||||
*f_low = 9750000;
|
||||
*f_hi = 10600000;
|
||||
*f_switch = 11700000;
|
||||
} else if(!strcmp(id, "DBS")) {
|
||||
*f_low = 11250000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Standard")) {
|
||||
*f_low = 10000000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Enhanced")) {
|
||||
*f_low = 9750000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "C-Band")) {
|
||||
*f_low = 5150000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "C-Multi")) {
|
||||
*f_low = 5150000;
|
||||
*f_hi = 5750000;
|
||||
*f_switch = 0;
|
||||
}
|
||||
}
|
|
@ -266,7 +266,7 @@ dvb_polarisation_to_str(int pol)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
const char *
|
||||
dvb_polarisation_to_str_long(int pol)
|
||||
{
|
||||
switch(pol) {
|
||||
|
@ -309,6 +309,25 @@ nicenum(char *x, size_t siz, unsigned int v)
|
|||
return x;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_mux_nicefreq(char *buf, size_t size, th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
char freq[50];
|
||||
|
||||
if(tdmi->tdmi_adapter->tda_type == FE_QPSK) {
|
||||
nicenum(freq, sizeof(freq), tdmi->tdmi_fe_params.frequency);
|
||||
snprintf(buf, size, "%s kHz", freq);
|
||||
} else {
|
||||
nicenum(freq, sizeof(freq), tdmi->tdmi_fe_params.frequency / 1000);
|
||||
snprintf(buf, size, "%s kHz", freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -320,10 +339,11 @@ dvb_mux_nicename(char *buf, size_t size, th_dvb_mux_instance_t *tdmi)
|
|||
|
||||
if(tdmi->tdmi_adapter->tda_type == FE_QPSK) {
|
||||
nicenum(freq, sizeof(freq), tdmi->tdmi_fe_params.frequency);
|
||||
snprintf(buf, size, "%s%s%s kHz %s port %d",
|
||||
snprintf(buf, size, "%s%s%s kHz %s (%s)",
|
||||
n?:"", n ? ": ":"", freq,
|
||||
dvb_polarisation_to_str_long(tdmi->tdmi_polarisation),
|
||||
tdmi->tdmi_switchport);
|
||||
tdmi->tdmi_satconf ? tdmi->tdmi_satconf->sc_name : "No satconf");
|
||||
|
||||
} else {
|
||||
nicenum(freq, sizeof(freq), tdmi->tdmi_fe_params.frequency / 1000);
|
||||
snprintf(buf, size, "%s%s%s kHz", n?:"", n ? ": ":"", freq);
|
||||
|
|
|
@ -59,11 +59,13 @@ time_t dvb_convert_date(uint8_t *dvb_buf);
|
|||
const char *dvb_adaptertype_to_str(int type);
|
||||
int dvb_str_to_adaptertype(const char *str);
|
||||
const char *dvb_polarisation_to_str(int pol);
|
||||
const char *dvb_polarisation_to_str_long(int pol);
|
||||
th_dvb_adapter_t *dvb_adapter_find_by_identifier(const char *identifier);
|
||||
th_dvb_mux_instance_t *dvb_mux_find_by_identifier(const char *identifier);
|
||||
void dvb_mux_nicename(char *buf, size_t size, th_dvb_mux_instance_t *tdmi);
|
||||
int dvb_mux_badness(th_dvb_mux_instance_t *tdmi);
|
||||
const char *dvb_mux_status(th_dvb_mux_instance_t *tdmi);
|
||||
void dvb_conversion_init(void);
|
||||
void dvb_mux_nicefreq(char *buf, size_t size, th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
#endif /* DVB_SUPPORT_H */
|
||||
|
|
|
@ -76,8 +76,8 @@ typedef struct th_dvb_table {
|
|||
char *tdt_name;
|
||||
|
||||
void *tdt_opaque;
|
||||
void (*tdt_callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
|
||||
uint8_t tableid, void *opaque);
|
||||
int (*tdt_callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
|
||||
uint8_t tableid, void *opaque);
|
||||
|
||||
|
||||
int tdt_count;
|
||||
|
@ -102,27 +102,33 @@ dvb_fparams_alloc(void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_table_fastswitch(th_dvb_mux_instance_t *tdmi)
|
||||
{
|
||||
#if 0
|
||||
th_dvb_table_t *tdt;
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
char buf[100];
|
||||
|
||||
if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_NONE)
|
||||
if(!tdmi->tdmi_table_initial)
|
||||
return;
|
||||
|
||||
LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
|
||||
if(tdt->tdt_quickreq && tdt->tdt_count == 0)
|
||||
if((tdt->tdt_flags & TDT_QUICKREQ) && tdt->tdt_count == 0)
|
||||
return;
|
||||
|
||||
tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE;
|
||||
dvb_adapter_mux_scanner(tdmi->tdmi_adapter);
|
||||
#endif
|
||||
tdmi->tdmi_table_initial = 0;
|
||||
tda->tda_initial_num_mux--;
|
||||
|
||||
|
||||
if(tda->tda_logging) {
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
tvhlog(LOG_INFO, "dvb", "\"%s\" initial scan completed for \"%s\"",
|
||||
tda->tda_rootpath, buf);
|
||||
}
|
||||
dvb_adapter_mux_scanner(tda);
|
||||
}
|
||||
|
||||
|
||||
|
@ -188,9 +194,10 @@ static void
|
|||
dvb_proc_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt, uint8_t *sec,
|
||||
int r)
|
||||
{
|
||||
int chkcrc = tdt->tdt_flags & TDT_INC_TABLE_HDR;
|
||||
int chkcrc = tdt->tdt_flags & TDT_CRC;
|
||||
int tableid, len;
|
||||
uint8_t *ptr;
|
||||
int ret;
|
||||
|
||||
/* It seems some hardware (or is it the dvb API?) does not
|
||||
honour the DMX_CHECK_CRC flag, so we check it again */
|
||||
|
@ -208,11 +215,15 @@ dvb_proc_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt, uint8_t *sec,
|
|||
if(chkcrc) len -= 4; /* Strip trailing CRC */
|
||||
|
||||
if(tdt->tdt_flags & TDT_INC_TABLE_HDR)
|
||||
tdt->tdt_callback(tdmi, sec, len + 3, tableid, tdt->tdt_opaque);
|
||||
ret = tdt->tdt_callback(tdmi, sec, len + 3, tableid, tdt->tdt_opaque);
|
||||
else
|
||||
tdt->tdt_callback(tdmi, ptr, len, tableid, tdt->tdt_opaque);
|
||||
ret = tdt->tdt_callback(tdmi, ptr, len, tableid, tdt->tdt_opaque);
|
||||
|
||||
dvb_table_fastswitch(tdmi);
|
||||
if(ret == 0)
|
||||
tdt->tdt_count++;
|
||||
|
||||
if(tdt->tdt_flags & TDT_QUICKREQ)
|
||||
dvb_table_fastswitch(tdmi);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,6 +238,7 @@ dvb_table_input(void *aux)
|
|||
uint8_t sec[4096];
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_dvb_table_t *tdt;
|
||||
int64_t t;
|
||||
|
||||
while(1) {
|
||||
x = epoll_wait(tda->tda_table_epollfd, ev, sizeof(ev) / sizeof(ev[0]), -1);
|
||||
|
@ -243,26 +255,36 @@ dvb_table_input(void *aux)
|
|||
continue;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
tdmi = tda->tda_mux_current;
|
||||
if((tdmi = tda->tda_mux_current) != NULL) {
|
||||
t = getclock_hires();
|
||||
/*
|
||||
* Supress first 250ms of table info. It seems that sometimes
|
||||
* the tuners not have actually tuned once they have returned
|
||||
* from the ioctl(). So we will wait some time before we start
|
||||
* accepting tables.
|
||||
* Not a perfect tix...
|
||||
*/
|
||||
if(t - tdmi->tdmi_table_start >= 250000) {
|
||||
|
||||
LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
|
||||
if(tdt->tdt_id == tid)
|
||||
break;
|
||||
LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
|
||||
if(tdt->tdt_id == tid)
|
||||
break;
|
||||
|
||||
if(tdt != NULL) {
|
||||
dvb_proc_table(tdmi, tdt, sec, r);
|
||||
if(tdt != NULL) {
|
||||
dvb_proc_table(tdmi, tdt, sec, r);
|
||||
|
||||
/* Any tables pending (that wants a filter/fd) */
|
||||
if(TAILQ_FIRST(&tdmi->tdmi_table_queue) != NULL) {
|
||||
tdt_close_fd(tdmi, tdt);
|
||||
/* Any tables pending (that wants a filter/fd) */
|
||||
if(TAILQ_FIRST(&tdmi->tdmi_table_queue) != NULL) {
|
||||
tdt_close_fd(tdmi, tdt);
|
||||
|
||||
tdt = TAILQ_FIRST(&tdmi->tdmi_table_queue);
|
||||
assert(tdt != NULL);
|
||||
tdt = TAILQ_FIRST(&tdmi->tdmi_table_queue);
|
||||
assert(tdt != NULL);
|
||||
|
||||
tdt_open_fd(tdmi, tdt);
|
||||
tdt_open_fd(tdmi, tdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +334,7 @@ dvb_tdt_destroy(th_dvb_adapter_t *tda, th_dvb_mux_instance_t *tdmi,
|
|||
*/
|
||||
static void
|
||||
tdt_add(th_dvb_mux_instance_t *tdmi, struct dmx_sct_filter_params *fparams,
|
||||
void (*callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
|
||||
int (*callback)(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
|
||||
uint8_t tableid, void *opaque), void *opaque,
|
||||
const char *name, int flags, int pid, th_dvb_table_t *tdt)
|
||||
{
|
||||
|
@ -408,7 +430,7 @@ dvb_desc_service(uint8_t *ptr, int len, uint8_t *typep,
|
|||
/**
|
||||
* DVB EIT (Event Information Table)
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
|
@ -444,7 +466,7 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
// printf("EIT!, tid = %x\n", tableid);
|
||||
|
||||
if(tableid < 0x4e || tableid > 0x6f || len < 11)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
serviceid = ptr[0] << 8 | ptr[1];
|
||||
version = ptr[2] >> 1 & 0x1f;
|
||||
|
@ -460,20 +482,20 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
ptr += 11;
|
||||
|
||||
/* Search all muxes on adapter */
|
||||
RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
|
||||
if(tdmi->tdmi_transport_stream_id == transport_stream_id)
|
||||
break;
|
||||
|
||||
if(tdmi == NULL)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
t = dvb_transport_find(tdmi, serviceid, 0);
|
||||
t = dvb_transport_find(tdmi, serviceid, 0, NULL);
|
||||
if(t == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
ch = t->tht_ch;
|
||||
if(ch == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
while(len >= 12) {
|
||||
event_id = ptr[0] << 8 | ptr[1];
|
||||
|
@ -537,13 +559,14 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
len -= dlen; ptr += dlen; dllen -= dlen;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DVB SDT (Service Description Table)
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
|
@ -567,7 +590,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
int l;
|
||||
|
||||
if(len < 8)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
transport_stream_id = ptr[0] << 8 | ptr[1];
|
||||
version = ptr[2] >> 1 & 0x1f;
|
||||
|
@ -629,7 +652,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
snprintf(chname0, sizeof(chname0), "noname-sid-0x%x", service_id);
|
||||
}
|
||||
|
||||
t = dvb_transport_find(tdmi, service_id, 0);
|
||||
t = dvb_transport_find(tdmi, service_id, 0, NULL);
|
||||
if(t == NULL)
|
||||
break;
|
||||
|
||||
|
@ -651,10 +674,6 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
t->tht_config_change(t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
|
||||
if(t->tht_chname == NULL)
|
||||
t->tht_chname = strdup(chname);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -662,28 +681,27 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
len -= dlen; ptr += dlen; dllen -= dlen;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PAT - Program Allocation table
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_pat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
uint16_t service, pmt, tid;
|
||||
uint16_t service, pmt, tsid;
|
||||
th_transport_t *t;
|
||||
|
||||
if(len < 5)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
tid = (ptr[0] << 8) | ptr[1];
|
||||
tsid = (ptr[0] << 8) | ptr[1];
|
||||
|
||||
if(tdmi->tdmi_transport_stream_id != tid) {
|
||||
tdmi->tdmi_transport_stream_id = tid;
|
||||
dvb_mux_save(tdmi);
|
||||
}
|
||||
if(tdmi->tdmi_transport_stream_id != tsid)
|
||||
dvb_mux_set_tsid(tdmi, tsid);
|
||||
|
||||
ptr += 5;
|
||||
len -= 5;
|
||||
|
@ -693,12 +711,13 @@ dvb_pat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
pmt = (ptr[2] & 0x1f) << 8 | ptr[3];
|
||||
|
||||
if(service != 0) {
|
||||
t = dvb_transport_find(tdmi, service, pmt);
|
||||
t = dvb_transport_find(tdmi, service, pmt, NULL);
|
||||
dvb_table_add_transport(tdmi, t, pmt);
|
||||
}
|
||||
ptr += 4;
|
||||
len -= 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -712,16 +731,17 @@ typedef struct ca_stream {
|
|||
/**
|
||||
* CA - Conditional Access
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_ca_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* CAT - Conditional Access Table
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
|
@ -758,6 +778,7 @@ dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
ptr += tlen;
|
||||
len -= tlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -777,7 +798,7 @@ static const fe_modulation_t qam_tab [6] = {
|
|||
/**
|
||||
* Cable delivery descriptor
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_table_cable_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint16_t tsid)
|
||||
{
|
||||
|
@ -785,11 +806,11 @@ dvb_table_cable_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
struct dvb_frontend_parameters fe_param;
|
||||
|
||||
if(!tdmi->tdmi_adapter->tda_autodiscovery)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if(len < 11) {
|
||||
printf("Invalid CABLE DESCRIPTOR\n");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
memset(&fe_param, 0, sizeof(fe_param));
|
||||
fe_param.inversion = INVERSION_AUTO;
|
||||
|
@ -815,13 +836,14 @@ dvb_table_cable_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
fe_param.u.qam.fec_inner = fec_tab[ptr[10] & 0x07];
|
||||
|
||||
dvb_mux_create(tdmi->tdmi_adapter, &fe_param, 0, 0, tsid, NULL,
|
||||
"automatic mux discovery");
|
||||
"automatic mux discovery", 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Satellite delivery descriptor
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint16_t tsid)
|
||||
{
|
||||
|
@ -829,10 +851,10 @@ dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
struct dvb_frontend_parameters fe_param;
|
||||
|
||||
if(!tdmi->tdmi_adapter->tda_autodiscovery)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if(len < 11)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
memset(&fe_param, 0, sizeof(fe_param));
|
||||
fe_param.inversion = INVERSION_AUTO;
|
||||
|
@ -851,9 +873,10 @@ dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
|
||||
pol = (ptr[6] >> 5) & 0x03;
|
||||
|
||||
dvb_mux_create(tdmi->tdmi_adapter, &fe_param, pol, tdmi->tdmi_switchport,
|
||||
dvb_mux_create(tdmi->tdmi_adapter, &fe_param, pol, tdmi->tdmi_satconf,
|
||||
tsid, NULL,
|
||||
"automatic mux discovery");
|
||||
"automatic mux discovery", 1, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -861,7 +884,7 @@ dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
/**
|
||||
* NIT - Network Information Table
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
|
@ -874,13 +897,13 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
len -= 5;
|
||||
|
||||
if(tableid != 0x40)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
ntl = ((ptr[0] & 0xf) << 8) | ptr[1];
|
||||
ptr += 2;
|
||||
len -= 2;
|
||||
if(ntl > len)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
while(ntl > 2) {
|
||||
tag = *ptr++;
|
||||
|
@ -891,7 +914,7 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
switch(tag) {
|
||||
case DVB_DESC_NETWORK_NAME:
|
||||
if(dvb_get_string(networkname, sizeof(networkname), ptr, tlen))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if(strcmp(tdmi->tdmi_network ?: "", networkname))
|
||||
dvb_mux_set_networkname(tdmi, networkname);
|
||||
|
@ -904,14 +927,14 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
}
|
||||
|
||||
if(len < 2)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
ntl = ((ptr[0] & 0xf) << 8) | ptr[1];
|
||||
ptr += 2;
|
||||
len -= 2;
|
||||
|
||||
if(len < ntl)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
while(len >= 6) {
|
||||
tsid = ( ptr[0] << 8) | ptr[1];
|
||||
|
@ -942,6 +965,7 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
ntl -= tlen;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -949,7 +973,7 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
/**
|
||||
* PMT - Program Mapping Table
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
|
@ -958,23 +982,7 @@ dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
|||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
psi_parse_pmt(t, ptr, len, 1);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RST - Running Status Table
|
||||
*/
|
||||
static void
|
||||
dvb_rst_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque)
|
||||
{
|
||||
int i;
|
||||
|
||||
// printf("Got RST on %s\t", tdmi->tdmi_uniquename);
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
printf("%02x.", ptr[i]);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -986,6 +994,8 @@ dvb_table_add_default(th_dvb_mux_instance_t *tdmi)
|
|||
{
|
||||
struct dmx_sct_filter_params *fp;
|
||||
|
||||
tdmi->tdmi_table_start = getclock_hires();
|
||||
|
||||
/* Program Allocation Table */
|
||||
|
||||
fp = dvb_fparams_alloc();
|
||||
|
@ -1023,15 +1033,6 @@ dvb_table_add_default(th_dvb_mux_instance_t *tdmi)
|
|||
fp = dvb_fparams_alloc();
|
||||
tdt_add(tdmi, fp, dvb_eit_callback, NULL, "eit",
|
||||
TDT_CRC, 0x12, NULL);
|
||||
|
||||
/* Running Status Table */
|
||||
|
||||
fp = dvb_fparams_alloc();
|
||||
fp->filter.filter[0] = 0x71;
|
||||
fp->filter.mask[0] = 0xff;
|
||||
tdt_add(tdmi, fp, dvb_rst_callback, NULL, "rst",
|
||||
TDT_CRC, 0x13, NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int status,
|
|||
if(tda->tda_rootpath == NULL)
|
||||
return 1; /* hardware not present */
|
||||
|
||||
if(!tdmi->tdmi_enabled)
|
||||
return 1; /* Mux is disabled */
|
||||
|
||||
/* Check if adapter is idle, or already tuned */
|
||||
|
||||
if(tdmi != NULL && tdmi != t->tht_dvb_mux_instance && !force_start) {
|
||||
|
@ -178,7 +181,7 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
|||
if(htsmsg_get_u32(c, "pmt", &pmt))
|
||||
continue;
|
||||
|
||||
t = dvb_transport_find(tdmi, sid, pmt);
|
||||
t = dvb_transport_find(tdmi, sid, pmt, f->hmf_name);
|
||||
|
||||
htsmsg_get_u32(c, "stype", &t->tht_servicetype);
|
||||
if(htsmsg_get_u32(c, "scrambled", &u32))
|
||||
|
@ -191,19 +194,16 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
|||
s = htsmsg_get_str(c, "servicename") ?: "unknown";
|
||||
t->tht_svcname = strdup(s);
|
||||
|
||||
s = htsmsg_get_str(c, "channelname");
|
||||
if(s != NULL) {
|
||||
t->tht_chname = strdup(s);
|
||||
} else {
|
||||
t->tht_chname = strdup(t->tht_svcname);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
psi_load_transport_settings(c, t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
|
||||
if(!htsmsg_get_u32(c, "mapped", &u32) && u32)
|
||||
transport_map_channel(t, NULL);
|
||||
|
||||
s = htsmsg_get_str(c, "channelname");
|
||||
if(htsmsg_get_u32(c, "mapped", &u32))
|
||||
u32 = 0;
|
||||
|
||||
if(s && u32)
|
||||
transport_map_channel(t, channel_find_by_name(s, 1), 0);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
@ -229,10 +229,10 @@ dvb_transport_save(th_transport_t *t)
|
|||
if(t->tht_svcname != NULL)
|
||||
htsmsg_add_str(m, "servicename", t->tht_svcname);
|
||||
|
||||
if(t->tht_chname != NULL)
|
||||
htsmsg_add_str(m, "channelname", t->tht_chname);
|
||||
|
||||
htsmsg_add_u32(m, "mapped", !!t->tht_ch);
|
||||
if(t->tht_ch != NULL) {
|
||||
htsmsg_add_str(m, "channelname", t->tht_ch->ch_name);
|
||||
htsmsg_add_u32(m, "mapped", 1);
|
||||
}
|
||||
|
||||
psi_save_transport_settings(m, t);
|
||||
|
||||
|
@ -241,6 +241,7 @@ dvb_transport_save(th_transport_t *t)
|
|||
t->tht_identifier);
|
||||
|
||||
htsmsg_destroy(m);
|
||||
dvb_transport_notify(t);
|
||||
}
|
||||
|
||||
|
||||
|
@ -257,7 +258,7 @@ dvb_transport_quality(th_transport_t *t)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
return tdmi->tdmi_quality;
|
||||
return tdmi->tdmi_enabled ? tdmi->tdmi_quality : 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -297,10 +298,12 @@ dvb_transport_networkname(th_transport_t *t)
|
|||
* If it cannot be found we create it if 'pmt_pid' is also set
|
||||
*/
|
||||
th_transport_t *
|
||||
dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid)
|
||||
dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid,
|
||||
const char *identifier)
|
||||
{
|
||||
th_transport_t *t;
|
||||
char tmp[200];
|
||||
char buf[200];
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
|
@ -312,9 +315,16 @@ dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid)
|
|||
if(pmt_pid == 0)
|
||||
return NULL;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%s_%04x", tdmi->tdmi_identifier, sid);
|
||||
if(identifier == NULL) {
|
||||
snprintf(tmp, sizeof(tmp), "%s_%04x", tdmi->tdmi_identifier, sid);
|
||||
identifier = tmp;
|
||||
}
|
||||
|
||||
t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS);
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
if(tdmi->tdmi_adapter->tda_logging)
|
||||
tvhlog(LOG_INFO, "dvb", "Add service \"%s\" on \"%s\"", identifier, buf);
|
||||
|
||||
t = transport_create(identifier, TRANSPORT_DVB, THT_MPEG_TS);
|
||||
|
||||
t->tht_dvb_service_id = sid;
|
||||
t->tht_pmt_pid = pmt_pid;
|
||||
|
@ -328,5 +338,67 @@ dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid)
|
|||
t->tht_quality_index = dvb_transport_quality;
|
||||
|
||||
LIST_INSERT_HEAD(&tdmi->tdmi_transports, t, tht_mux_link);
|
||||
|
||||
dvb_adapter_notify(tdmi->tdmi_adapter);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_transport_build_msg(th_transport_t *t)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
char buf[100];
|
||||
|
||||
htsmsg_add_str(m, "id", t->tht_identifier);
|
||||
htsmsg_add_u32(m, "enabled", t->tht_enabled);
|
||||
|
||||
htsmsg_add_u32(m, "sid", t->tht_dvb_service_id);
|
||||
htsmsg_add_u32(m, "pmt", t->tht_pmt_pid);
|
||||
htsmsg_add_u32(m, "pcr", t->tht_pcr_pid);
|
||||
|
||||
htsmsg_add_str(m, "type", transport_servicetype_txt(t));
|
||||
|
||||
htsmsg_add_str(m, "svcname", t->tht_svcname ?: "");
|
||||
htsmsg_add_str(m, "provider", t->tht_provider ?: "");
|
||||
|
||||
htsmsg_add_str(m, "network", tdmi->tdmi_network ?: "");
|
||||
|
||||
dvb_mux_nicefreq(buf, sizeof(buf), tdmi);
|
||||
htsmsg_add_str(m, "mux", buf);
|
||||
|
||||
if(t->tht_ch != NULL)
|
||||
htsmsg_add_str(m, "channelname", t->tht_ch->ch_name);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_transport_notify_by_adapter(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "adapterId", tda->tda_identifier);
|
||||
notify_by_msg("dvbService", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_transport_notify(th_transport_t *t)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "adapterId", tdmi->tdmi_adapter->tda_identifier);
|
||||
notify_by_msg("dvbService", m);
|
||||
}
|
||||
|
|
|
@ -211,6 +211,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
lock_assert(&t->tht_stream_mutex);
|
||||
|
||||
sid = ptr[0] << 8 | ptr[1];
|
||||
|
||||
pcr_pid = (ptr[5] & 0x1f) << 8 | ptr[6];
|
||||
dllen = (ptr[7] & 0xf) << 8 | ptr[8];
|
||||
|
||||
|
@ -609,7 +610,7 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
|
|||
|
||||
htsmsg_add_u32(m, "pcr", t->tht_pcr_pid);
|
||||
|
||||
htsmsg_add_u32(m, "disabled", !!t->tht_disabled);
|
||||
htsmsg_add_u32(m, "disabled", !t->tht_enabled);
|
||||
|
||||
lock_assert(&t->tht_stream_mutex);
|
||||
|
||||
|
@ -651,7 +652,9 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
|
|||
t->tht_pcr_pid = u32;
|
||||
|
||||
if(!htsmsg_get_u32(m, "disabled", &u32))
|
||||
t->tht_disabled = u32;
|
||||
t->tht_enabled = !u32;
|
||||
else
|
||||
t->tht_enabled = 1;
|
||||
|
||||
HTSMSG_FOREACH(f, m) {
|
||||
if(strcmp(f->hmf_name, "stream"))
|
||||
|
|
|
@ -141,7 +141,7 @@ rawts_transport_add(rawts_t *rt, uint16_t sid, int pmt_pid)
|
|||
|
||||
ch = channel_find_by_name(tmp, 1);
|
||||
|
||||
transport_map_channel(t, ch);
|
||||
transport_map_channel(t, ch, 0);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,9 @@ serviceprobe_thread(void *aux)
|
|||
was_doing_work = 1;
|
||||
}
|
||||
|
||||
tvhlog(LOG_INFO, "serviceprobe", "%20s: checking...",
|
||||
t->tht_svcname);
|
||||
|
||||
s = subscription_create_from_transport(t, "serviceprobe", &sq.sq_st);
|
||||
|
||||
transport_ref(t);
|
||||
|
@ -154,13 +157,9 @@ serviceprobe_thread(void *aux)
|
|||
t->tht_svcname, err);
|
||||
} else if(t->tht_ch == NULL) {
|
||||
ch = channel_find_by_name(t->tht_svcname, 1);
|
||||
transport_map_channel(t, ch);
|
||||
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t);
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
transport_map_channel(t, ch, 1);
|
||||
|
||||
tvhlog(LOG_INFO, "serviceprobe", "\"%s\" mapped to channel \"%s\"",
|
||||
tvhlog(LOG_INFO, "serviceprobe", "%20s: mapped to channel \"%s\"",
|
||||
t->tht_svcname, t->tht_svcname);
|
||||
}
|
||||
|
||||
|
|
|
@ -298,13 +298,13 @@ transport_find(channel_t *ch, unsigned int weight)
|
|||
/* First, sort all transports in order */
|
||||
|
||||
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
|
||||
if(!t->tht_disabled && t->tht_quality_index(t) > 10)
|
||||
if(t->tht_enabled && t->tht_quality_index(t) > 10)
|
||||
cnt++;
|
||||
|
||||
vec = alloca(cnt * sizeof(th_transport_t *));
|
||||
i = 0;
|
||||
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
|
||||
if(!t->tht_disabled && t->tht_quality_index(t) > 10)
|
||||
if(t->tht_enabled && t->tht_quality_index(t) > 10)
|
||||
vec[i++] = t;
|
||||
|
||||
assert(i == cnt);
|
||||
|
@ -415,7 +415,6 @@ transport_destroy(th_transport_t *t)
|
|||
|
||||
free(t->tht_identifier);
|
||||
free(t->tht_svcname);
|
||||
free(t->tht_chname);
|
||||
free(t->tht_provider);
|
||||
|
||||
while((st = LIST_FIRST(&t->tht_components)) != NULL) {
|
||||
|
@ -443,6 +442,7 @@ transport_create(const char *identifier, int type, int source_type)
|
|||
t->tht_type = type;
|
||||
t->tht_source_type = source_type;
|
||||
t->tht_refcount = 1;
|
||||
t->tht_enabled = 1;
|
||||
|
||||
streaming_pad_init(&t->tht_streaming_pad);
|
||||
|
||||
|
@ -533,41 +533,31 @@ transport_stream_find(th_transport_t *t, int pid)
|
|||
*
|
||||
*/
|
||||
void
|
||||
transport_map_channel(th_transport_t *t, channel_t *ch)
|
||||
transport_map_channel(th_transport_t *t, channel_t *ch, int save)
|
||||
{
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
assert(t->tht_ch == NULL);
|
||||
|
||||
if(ch == NULL) {
|
||||
if(t->tht_chname == NULL)
|
||||
return;
|
||||
ch = channel_find_by_name(t->tht_chname, 1);
|
||||
} else {
|
||||
free(t->tht_chname);
|
||||
t->tht_chname = strdup(ch->ch_name);
|
||||
if(t->tht_ch != NULL) {
|
||||
t->tht_ch = NULL;
|
||||
LIST_REMOVE(t, tht_ch_link);
|
||||
}
|
||||
|
||||
avgstat_init(&t->tht_cc_errors, 3600);
|
||||
avgstat_init(&t->tht_rate, 10);
|
||||
|
||||
assert(t->tht_identifier != NULL);
|
||||
t->tht_ch = ch;
|
||||
if(ch != NULL) {
|
||||
|
||||
LIST_INSERT_HEAD(&ch->ch_transports, t, tht_ch_link);
|
||||
}
|
||||
avgstat_init(&t->tht_cc_errors, 3600);
|
||||
avgstat_init(&t->tht_rate, 10);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
transport_unmap_channel(th_transport_t *t)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
t->tht_ch = ch;
|
||||
LIST_INSERT_HEAD(&ch->ch_transports, t, tht_ch_link);
|
||||
}
|
||||
|
||||
t->tht_ch = NULL;
|
||||
LIST_REMOVE(t, tht_ch_link);
|
||||
if(!save)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t); // Save config
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -602,7 +592,7 @@ static struct strtab stypetab[] = {
|
|||
const char *
|
||||
transport_servicetype_txt(th_transport_t *t)
|
||||
{
|
||||
return val2str(t->tht_servicetype, stypetab);
|
||||
return val2str(t->tht_servicetype, stypetab) ?: "Other";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -618,14 +608,6 @@ transport_is_tv(th_transport_t *t)
|
|||
t->tht_servicetype == ST_AC_HDTV;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
transport_is_available(th_transport_t *t)
|
||||
{
|
||||
return transport_servicetype_txt(t) && LIST_FIRST(&t->tht_components);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -719,3 +701,18 @@ transport_feed_status_to_text(transport_feed_status_t status)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
transport_set_enable(th_transport_t *t, int enabled)
|
||||
{
|
||||
if(t->tht_enabled == enabled)
|
||||
return;
|
||||
|
||||
t->tht_enabled = enabled;
|
||||
|
||||
pthread_mutex_lock(&t->tht_stream_mutex);
|
||||
t->tht_config_change(t); // Save config
|
||||
pthread_mutex_unlock(&t->tht_stream_mutex);
|
||||
}
|
||||
|
|
|
@ -36,9 +36,7 @@ void transport_ref(th_transport_t *t);
|
|||
|
||||
th_transport_t *transport_find_by_identifier(const char *identifier);
|
||||
|
||||
void transport_map_channel(th_transport_t *t, channel_t *ch);
|
||||
|
||||
void transport_unmap_channel(th_transport_t *t);
|
||||
void transport_map_channel(th_transport_t *t, channel_t *ch, int save);
|
||||
|
||||
th_transport_t *transport_find(channel_t *ch, unsigned int weight);
|
||||
|
||||
|
@ -55,8 +53,6 @@ const char *transport_servicetype_txt(th_transport_t *t);
|
|||
|
||||
int transport_is_tv(th_transport_t *t);
|
||||
|
||||
int transport_is_available(th_transport_t *t);
|
||||
|
||||
void transport_destroy(th_transport_t *t);
|
||||
|
||||
void transport_set_feed_status(th_transport_t *t,
|
||||
|
@ -80,5 +76,6 @@ transport_find_stream_by_pid(th_transport_t *t, int pid)
|
|||
|
||||
htsmsg_t *transport_build_stream_start_msg(th_transport_t *t);
|
||||
|
||||
void transport_set_enable(th_transport_t *t, int enabled);
|
||||
|
||||
#endif /* TRANSPORTS_H */
|
||||
|
|
|
@ -348,7 +348,7 @@ typedef enum {
|
|||
* A Transport (or in MPEG TS terms: a 'service')
|
||||
*/
|
||||
typedef struct th_transport {
|
||||
|
||||
|
||||
const char *tht_name;
|
||||
|
||||
LIST_ENTRY(th_transport) tht_hash_link;
|
||||
|
@ -422,11 +422,11 @@ typedef struct th_transport {
|
|||
uint16_t tht_pmt_pid;
|
||||
|
||||
/**
|
||||
* Set if transport is disabled. If disabled it should not be
|
||||
* considered when chasing for available transports during
|
||||
* Set if transport is enabled (the default). If disabled it should
|
||||
* not be considered when chasing for available transports during
|
||||
* subscription scheduling.
|
||||
*/
|
||||
int tht_disabled;
|
||||
int tht_enabled;
|
||||
|
||||
|
||||
LIST_ENTRY(th_transport) tht_mux_link;
|
||||
|
@ -497,7 +497,6 @@ typedef struct th_transport {
|
|||
*/
|
||||
LIST_ENTRY(th_transport) tht_ch_link;
|
||||
struct channel *tht_ch;
|
||||
char *tht_chname;
|
||||
|
||||
/**
|
||||
* Service probe, see serviceprobe.c for details
|
||||
|
|
|
@ -107,6 +107,7 @@ extjs_root(http_connection_t *hc, const char *remain, void *opaque)
|
|||
/**
|
||||
* Load all components
|
||||
*/
|
||||
extjs_load(hq, "static/app/comet.js");
|
||||
extjs_load(hq, "static/app/tableeditor.js");
|
||||
extjs_load(hq, "static/app/cteditor.js");
|
||||
extjs_load(hq, "static/app/acleditor.js");
|
||||
|
@ -167,13 +168,13 @@ page_about(http_connection_t *hc, const char *remain, void *opaque)
|
|||
"<div class=\"about-title\">"
|
||||
"HTS Tvheadend %s"
|
||||
"</div><br>"
|
||||
"© 2006 - 2008 Andreas \303\226man, et al.<br><br>"
|
||||
"© 2006 - 2009 Andreas \303\226man, et al.<br><br>"
|
||||
"<img src=\"docresources/tvheadendlogo.png\"><br>"
|
||||
"<a href=\"http://hts.lonelycoder.com/\">"
|
||||
"http://hts.lonelycoder.com/</a><br><br>"
|
||||
"Based on software from "
|
||||
"<a href=\"http://www.ffmpeg.org/\">FFmpeg</a> and "
|
||||
"<a href=\"http://www.extjs.org/\">ExtJS</a>.<br>"
|
||||
"<a href=\"http://www.extjs.com/\">ExtJS</a>.<br>"
|
||||
"<br>"
|
||||
"Build: %s"
|
||||
"</center>",
|
||||
|
@ -329,102 +330,6 @@ extjs_ecglist(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
extjs_dvbtree_node(htsmsg_t *array, int leaf, const char *id, const char *name,
|
||||
const char *type, const char *status, int quality,
|
||||
const char *itype)
|
||||
{
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(e, "uiProvider", "col");
|
||||
htsmsg_add_str(e, "id", id);
|
||||
htsmsg_add_u32(e, "leaf", leaf);
|
||||
htsmsg_add_str(e, "itype", itype);
|
||||
|
||||
htsmsg_add_str(e, "name", name);
|
||||
htsmsg_add_str(e, "type", type);
|
||||
htsmsg_add_str(e, "status", status);
|
||||
htsmsg_add_u32(e, "quality", quality);
|
||||
|
||||
htsmsg_add_msg(array, NULL, e);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbtree(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *s = http_arg_get(&hc->hc_req_args, "node");
|
||||
htsmsg_t *out = NULL;
|
||||
char buf[200];
|
||||
th_dvb_adapter_t *tda;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_transport_t *t;
|
||||
|
||||
if(s == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
out = htsmsg_create_list();
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(http_access_verify(hc, ACCESS_ADMIN)) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
if(!strcmp(s, "root")) {
|
||||
/**
|
||||
* List of all adapters
|
||||
*/
|
||||
|
||||
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s adapter",
|
||||
dvb_adaptertype_to_str(tda->tda_type));
|
||||
|
||||
extjs_dvbtree_node(out, 0,
|
||||
tda->tda_identifier, tda->tda_displayname,
|
||||
buf, tda->tda_rootpath != NULL ? "OK" : "No H/W",
|
||||
100, "adapter");
|
||||
}
|
||||
} else if((tda = dvb_adapter_find_by_identifier(s)) != NULL) {
|
||||
|
||||
RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
|
||||
extjs_dvbtree_node(out, 0,
|
||||
tdmi->tdmi_identifier, buf, "DVB Mux",
|
||||
dvb_mux_status(tdmi),
|
||||
tdmi->tdmi_quality, "mux");
|
||||
}
|
||||
} else if((tdmi = dvb_mux_find_by_identifier(s)) != NULL) {
|
||||
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
|
||||
if(transport_servicetype_txt(t) == NULL)
|
||||
continue;
|
||||
|
||||
extjs_dvbtree_node(out, 1,
|
||||
t->tht_identifier, t->tht_svcname,
|
||||
transport_servicetype_txt(t),
|
||||
t->tht_ch ? "Mapped" : "Unmapped",
|
||||
100, "transport");
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -479,85 +384,6 @@ json_single_record(htsmsg_t *rec, const char *root)
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *s = http_arg_get(&hc->hc_req_args, "adapterId");
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
th_dvb_adapter_t *tda = s ? dvb_adapter_find_by_identifier(s) : NULL;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_transport_t *t;
|
||||
|
||||
htsmsg_t *r, *out;
|
||||
|
||||
if(tda == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(http_access_verify(hc, ACCESS_ADMIN)) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
if(!strcmp(op, "load")) {
|
||||
r = htsmsg_create_map();
|
||||
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);
|
||||
|
||||
out = json_single_record(r, "dvbadapters");
|
||||
} else if(!strcmp(op, "save")) {
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
|
||||
dvb_adapter_set_displayname(tda, s);
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "automux")) != NULL)
|
||||
dvb_adapter_set_auto_discovery(tda, 1);
|
||||
else
|
||||
dvb_adapter_set_auto_discovery(tda, 0);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
} else if(!strcmp(op, "addnetwork")) {
|
||||
if((s = http_arg_get(&hc->hc_req_args, "network")) != NULL)
|
||||
dvb_mux_preconf_add_network(tda, s);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else if(!strcmp(op, "serviceprobe")) {
|
||||
|
||||
tvhlog(LOG_NOTICE, "web interface",
|
||||
"Service probe started on \"%s\"", tda->tda_displayname);
|
||||
|
||||
RB_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
serviceprobe_enqueue(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -573,7 +399,7 @@ build_transport_msg(th_transport_t *t)
|
|||
char subtitles[200];
|
||||
char scrambling[200];
|
||||
|
||||
htsmsg_add_u32(r, "enabled", !t->tht_disabled);
|
||||
htsmsg_add_u32(r, "enabled", t->tht_enabled);
|
||||
htsmsg_add_str(r, "name", t->tht_svcname);
|
||||
|
||||
htsmsg_add_str(r, "provider", t->tht_provider ?: "");
|
||||
|
@ -1236,6 +1062,459 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
th_dvb_adapter_t *tda;
|
||||
htsmsg_t *out, *array, *r;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *s, *sc;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_transport_t *t;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL) {
|
||||
/* Just list all adapters */
|
||||
|
||||
array = htsmsg_create_list();
|
||||
|
||||
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link)
|
||||
htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_msg(out, "entries", array);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
if(!strcmp(op, "load")) {
|
||||
r = htsmsg_create_map();
|
||||
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, "idlescan", tda->tda_idlescan);
|
||||
htsmsg_add_u32(r, "logging", tda->tda_logging);
|
||||
|
||||
out = json_single_record(r, "dvbadapters");
|
||||
} else if(!strcmp(op, "save")) {
|
||||
|
||||
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, "idlescan");
|
||||
dvb_adapter_set_idlescan(tda, !!s);
|
||||
|
||||
s = http_arg_get(&hc->hc_req_args, "logging");
|
||||
dvb_adapter_set_logging(tda, !!s);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
} else if(!strcmp(op, "addnetwork")) {
|
||||
|
||||
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, sc);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else if(!strcmp(op, "serviceprobe")) {
|
||||
|
||||
tvhlog(LOG_NOTICE, "web interface",
|
||||
"Service probe started on \"%s\"", tda->tda_displayname);
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
if(t->tht_enabled)
|
||||
serviceprobe_enqueue(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
mux_update(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *c;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
uint32_t u32;
|
||||
const char *id;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
(id = htsmsg_get_str(c, "id")) == NULL)
|
||||
continue;
|
||||
|
||||
if((tdmi = dvb_mux_find_by_identifier(id)) == NULL)
|
||||
continue;
|
||||
|
||||
if(!htsmsg_get_u32(c, "enabled", &u32))
|
||||
dvb_mux_set_enable(tdmi, u32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
mux_delete(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
const char *id;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((id = htsmsg_field_get_string(f)) != NULL &&
|
||||
(tdmi = dvb_mux_find_by_identifier(id)) != NULL)
|
||||
dvb_mux_destroy(tdmi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbmuxes(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
th_dvb_adapter_t *tda;
|
||||
htsmsg_t *out, *array, *in;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL ||
|
||||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
if(!strcmp(op, "get")) {
|
||||
array = htsmsg_create_list();
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
|
||||
htsmsg_add_msg(array, NULL, dvb_mux_build_msg(tdmi));
|
||||
|
||||
htsmsg_add_msg(out, "entries", array);
|
||||
} else if(!strcmp(op, "update")) {
|
||||
if(in != NULL)
|
||||
mux_update(in);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
} else if(!strcmp(op, "delete")) {
|
||||
if(in != NULL)
|
||||
mux_delete(in);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
if(in != NULL)
|
||||
htsmsg_destroy(in);
|
||||
htsmsg_destroy(out);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
|
||||
if(in != NULL)
|
||||
htsmsg_destroy(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
transport_update(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *c;
|
||||
th_transport_t *t;
|
||||
uint32_t u32;
|
||||
const char *id;
|
||||
const char *chname;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
(id = htsmsg_get_str(c, "id")) == NULL)
|
||||
continue;
|
||||
|
||||
if((t = transport_find_by_identifier(id)) == NULL)
|
||||
continue;
|
||||
|
||||
if(!htsmsg_get_u32(c, "enabled", &u32))
|
||||
transport_set_enable(t, u32);
|
||||
|
||||
if((chname = htsmsg_get_str(c, "channelname")) != NULL)
|
||||
transport_map_channel(t, channel_find_by_name(chname, 1), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
transportcmp(const void *A, const void *B)
|
||||
{
|
||||
th_transport_t *a = *(th_transport_t **)A;
|
||||
th_transport_t *b = *(th_transport_t **)B;
|
||||
|
||||
return strcasecmp(a->tht_svcname ?: "\0377", b->tht_svcname ?: "\0377");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
th_dvb_adapter_t *tda;
|
||||
htsmsg_t *out, *array, *in;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_transport_t *t, **tvec;
|
||||
int count = 0, i = 0;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL ||
|
||||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
|
||||
|
||||
if(!strcmp(op, "get")) {
|
||||
|
||||
out = htsmsg_create_map();
|
||||
array = htsmsg_create_list();
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
tvec = alloca(sizeof(th_transport_t *) * count);
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
|
||||
LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) {
|
||||
tvec[i++] = t;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(tvec, count, sizeof(th_transport_t *), transportcmp);
|
||||
|
||||
for(i = 0; i < count; i++)
|
||||
htsmsg_add_msg(array, NULL, dvb_transport_build_msg(tvec[i]));
|
||||
|
||||
htsmsg_add_msg(out, "entries", array);
|
||||
|
||||
} else if(!strcmp(op, "update")) {
|
||||
if(in != NULL)
|
||||
transport_update(in);
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
} else {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_destroy(in);
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
htsmsg_destroy(in);
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_lnbtypes(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *out;
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_msg(out, "entries", dvb_lnblist_get());
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbsatconf(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
th_dvb_adapter_t *tda;
|
||||
htsmsg_t *out;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL ||
|
||||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_msg(out, "entries", dvb_satconf_list(tda));
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_dvbservicedetails(http_connection_t *hc,
|
||||
const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *out, *streams, *c;
|
||||
th_transport_t *t;
|
||||
th_stream_t *st;
|
||||
char buf[20];
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
streams = htsmsg_create_list();
|
||||
|
||||
LIST_FOREACH(st, &t->tht_components, st_link) {
|
||||
c = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_u32(c, "pid", st->st_pid);
|
||||
|
||||
htsmsg_add_str(c, "type", streaming_component_type2txt(st->st_type));
|
||||
|
||||
switch(st->st_type) {
|
||||
default:
|
||||
htsmsg_add_str(c, "details", "");
|
||||
break;
|
||||
|
||||
case SCT_CA:
|
||||
htsmsg_add_str(c, "details", psi_caid2name(st->st_caid));
|
||||
break;
|
||||
|
||||
case SCT_AC3:
|
||||
case SCT_AAC:
|
||||
case SCT_MPEG2AUDIO:
|
||||
htsmsg_add_str(c, "details", st->st_lang);
|
||||
break;
|
||||
|
||||
case SCT_MPEG2VIDEO:
|
||||
case SCT_H264:
|
||||
buf[0] = 0;
|
||||
if(st->st_frame_duration)
|
||||
snprintf(buf, sizeof(buf), "%2.2f Hz",
|
||||
90000.0 / st->st_frame_duration);
|
||||
htsmsg_add_str(c, "details", buf);
|
||||
break;
|
||||
}
|
||||
|
||||
htsmsg_add_msg(streams, NULL, c);
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_str(out, "title", t->tht_svcname ?: "unnamed transport");
|
||||
|
||||
htsmsg_add_msg(out, "streams", streams);
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* WEB user interface
|
||||
*/
|
||||
|
@ -1245,8 +1524,6 @@ extjs_start(void)
|
|||
http_path_add("/about.html", NULL, page_about, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/extjs.html", NULL, extjs_root, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/tablemgr", NULL, extjs_tablemgr, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/dvbtree", NULL, extjs_dvbtree, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/dvbadapter", NULL, extjs_dvbadapter, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/dvbnetworks", NULL, extjs_dvbnetworks, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/chlist", NULL, extjs_chlist, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/channel", NULL, extjs_channel, ACCESS_WEB_INTERFACE);
|
||||
|
@ -1256,4 +1533,22 @@ extjs_start(void)
|
|||
http_path_add("/dvr", NULL, extjs_dvr, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/dvrlist", NULL, extjs_dvrlist, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/ecglist", NULL, extjs_ecglist, ACCESS_WEB_INTERFACE);
|
||||
|
||||
http_path_add("/dvb/adapter",
|
||||
NULL, extjs_dvbadapter, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/muxes",
|
||||
NULL, extjs_dvbmuxes, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/services",
|
||||
NULL, extjs_dvbservices, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/lnbtypes",
|
||||
NULL, extjs_lnbtypes, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/satconf",
|
||||
NULL, extjs_dvbsatconf, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/dvb/servicedetails",
|
||||
NULL, extjs_dvbservicedetails, ACCESS_ADMIN);
|
||||
}
|
||||
|
|
|
@ -5,21 +5,35 @@
|
|||
tvheadend.channelTags = new Ext.data.JsonStore({
|
||||
autoLoad:true,
|
||||
root:'entries',
|
||||
fields: [{name: 'identifier'}, {name: 'name'}],
|
||||
fields: ['identifier', 'name'],
|
||||
id: 'identifier',
|
||||
url:'channeltags',
|
||||
baseParams: {op: 'listTags'}
|
||||
});
|
||||
|
||||
tvheadend.comet.on('channeltags', function(m) {
|
||||
if(m.reload != null)
|
||||
tvheadend.channelTags.reload();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Channels
|
||||
*/
|
||||
tvheadend.channels = new Ext.data.JsonStore({
|
||||
autoLoad: true,
|
||||
root:'entries',
|
||||
fields: [{name: 'name'}, {name: 'chid'}],
|
||||
fields: ['name', 'chid'],
|
||||
id: 'chid',
|
||||
url: "chlist"
|
||||
});
|
||||
|
||||
tvheadend.comet.on('channels', function(m) {
|
||||
if(m.reload != null)
|
||||
tvheadend.channels.reload();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Channel details
|
||||
*/
|
||||
|
|
55
src/webui/static/app/comet.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
|
||||
/**
|
||||
* Comet interfaces
|
||||
*/
|
||||
Ext.extend(Comet = function() {
|
||||
this.addEvents({
|
||||
accessUpdate: true,
|
||||
dvbAdapter: true,
|
||||
dvbMux: true,
|
||||
dvbStore: true,
|
||||
dvbSatConf: true,
|
||||
logmessage: true,
|
||||
channeltags: true,
|
||||
autorec: true,
|
||||
dvrdb: true,
|
||||
channels: true,
|
||||
})
|
||||
}, Ext.util.Observable);
|
||||
|
||||
tvheadend.comet = new Comet();
|
||||
|
||||
|
||||
tvheadend.cometPoller = function() {
|
||||
|
||||
function parse_comet_response(responsetxt) {
|
||||
response = Ext.util.JSON.decode(responsetxt);
|
||||
for(x = 0; x < response.messages.length; x++) {
|
||||
m = response.messages[x];
|
||||
tvheadend.comet.fireEvent(m.notificationClass, m);
|
||||
}
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '/comet',
|
||||
params : { boxid: response.boxid },
|
||||
success: function(result, request) {
|
||||
parse_comet_response(result.responseText);
|
||||
},
|
||||
failure: function(result, request) {
|
||||
tvheadend.log('Connection to server lost' +
|
||||
', please reload user interface',
|
||||
'font-weight: bold; color: #f00');
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '/comet',
|
||||
success: function(result, request) {
|
||||
parse_comet_response(result.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -284,6 +284,11 @@ tvheadend.dvr = function() {
|
|||
remoteSort: true
|
||||
});
|
||||
|
||||
tvheadend.comet.on('dvrdb', function(m) {
|
||||
if(m.reload != null)
|
||||
tvheadend.dvrStore.reload();
|
||||
});
|
||||
|
||||
|
||||
tvheadend.autorecRecord = Ext.data.Record.create([
|
||||
'enabled','title','channel','tag','creator','contentgrp','comment'
|
||||
|
@ -299,6 +304,12 @@ tvheadend.dvr = function() {
|
|||
baseParams: {table: "autorec", op: "get"}
|
||||
});
|
||||
|
||||
tvheadend.comet.on('autorec', function(m) {
|
||||
if(m.reload != null)
|
||||
tvheadend.autorecStore.reload();
|
||||
});
|
||||
|
||||
|
||||
var panel = new Ext.TabPanel({
|
||||
activeTab:0,
|
||||
autoScroll:true,
|
||||
|
|
|
@ -7,27 +7,6 @@
|
|||
*/
|
||||
|
||||
|
||||
.x-column-tree .x-tree-node {
|
||||
zoom:1;
|
||||
}
|
||||
.x-column-tree .x-tree-node-el {
|
||||
/*border-bottom:1px solid #eee; borders? */
|
||||
zoom:1;
|
||||
}
|
||||
.x-column-tree .x-tree-selected {
|
||||
background: #d9e8fb;
|
||||
}
|
||||
.x-column-tree .x-tree-node a {
|
||||
line-height:18px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
.x-column-tree .x-tree-node a span{
|
||||
|
||||
}
|
||||
.x-column-tree .x-tree-node .x-tree-selected a span{
|
||||
background:transparent;
|
||||
color:#000;
|
||||
}
|
||||
.x-tree-col {
|
||||
float:left;
|
||||
overflow:hidden;
|
||||
|
@ -85,6 +64,56 @@
|
|||
}
|
||||
|
||||
|
||||
.x-grid3-progresscol .x-grid3-cell-inner {
|
||||
padding: 0px 0px 0px 5px;
|
||||
}
|
||||
|
||||
.x-grid3-progresscol .x-progress-bar {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.x-grid3-progresscol .x-progress-inner {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.x-grid3-progresscol .x-progress-text-front-ie6 {
|
||||
padding: 2.5px 5px;
|
||||
}
|
||||
|
||||
.x-grid3-progresscol .x-progress-text-front {
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
.x-progress-bar-red,.x-progress-bar-orange,.x-progress-bar-green {
|
||||
border-bottom: 1px solid #7fa9e4;
|
||||
float: left;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.x-progress-bar-red {
|
||||
background: #ff0000 url(../icons/progress-bg-red.gif) repeat-x scroll left
|
||||
center;
|
||||
border-top: 1px solid #ecb7ad;
|
||||
}
|
||||
|
||||
.x-progress-bar-orange {
|
||||
background: #9cbfee url(../icons/progress-bg-orange.gif) repeat-x scroll
|
||||
left center;
|
||||
border-right: 1px solid #deab7e;
|
||||
border-top: 1px solid #d7b290;
|
||||
}
|
||||
|
||||
.x-progress-bar-green {
|
||||
background: #00ff00 url(../icons/progress-bg-green.gif) repeat-x scroll
|
||||
left center;
|
||||
border-right: 1px solid #5bd976;
|
||||
border-top: 1px solid #79e18f;
|
||||
}
|
||||
|
||||
.tvh-grid-unset {
|
||||
color: #888;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
.add {
|
||||
background-image:url(../icons/add.gif) !important;
|
||||
|
@ -101,6 +130,12 @@
|
|||
.rec {
|
||||
background-image:url(../icons/rec.png) !important;
|
||||
}
|
||||
.info {
|
||||
background-image:url(../icons/information.png) !important;
|
||||
}
|
||||
.undo {
|
||||
background-image:url(../icons/undo.png) !important;
|
||||
}
|
||||
|
||||
.x-smallhdr {
|
||||
float:left;
|
||||
|
@ -127,6 +162,11 @@
|
|||
}
|
||||
|
||||
|
||||
.hts-t-info {
|
||||
float:left;
|
||||
width:100px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.hts-doc-text {
|
||||
|
@ -155,3 +195,82 @@
|
|||
font:normal 24px verdana;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/** vim: ts=4:sw=4:nu:fdc=4:nospell
|
||||
*
|
||||
* Ext.ux.grid.RowActions.css
|
||||
*
|
||||
* Style sheets for Grid RowActions Plugin
|
||||
*
|
||||
* @author Ing. Jozef Sakáloš
|
||||
* @date 27. March 2008
|
||||
* @verson $Id: Ext.ux.grid.RowActions.css 140 2008-04-06 01:24:10Z jozo $
|
||||
*
|
||||
* @license Ext.ux.grid.RowActions.css is licensed under the terms of
|
||||
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
|
||||
* that the code/component(s) do NOT become part of another Open Source or Commercially
|
||||
* licensed development library or toolkit without explicit permission.
|
||||
*
|
||||
* License details: http://www.gnu.org/licenses/lgpl.html
|
||||
*/
|
||||
|
||||
/* styles for rows */
|
||||
.ux-row-action-cell .x-grid3-cell-inner {
|
||||
padding:1px 0 0 0;
|
||||
}
|
||||
.ux-row-action-item {
|
||||
float:left;
|
||||
min-width:16px;
|
||||
height:16px;
|
||||
background-repeat:no-repeat;
|
||||
margin: 0 5px 0 0;
|
||||
cursor:pointer;
|
||||
overflow:hidden;
|
||||
}
|
||||
.ext-ie .ux-row-action-item {
|
||||
width:16px;
|
||||
}
|
||||
.ext-ie .ux-row-action-text {
|
||||
width:auto;
|
||||
}
|
||||
.ux-row-action-item span {
|
||||
vertical-align:middle;
|
||||
padding:0 0 0 20px;
|
||||
line-height:18px;
|
||||
}
|
||||
.ext-ie .ux-row-action-item span {
|
||||
width:auto;
|
||||
}
|
||||
|
||||
/* styles for groups */
|
||||
.x-grid-group-hd div {
|
||||
position:relative;
|
||||
height:16px;
|
||||
}
|
||||
.ux-grow-action-item {
|
||||
min-width:16px;
|
||||
height:16px;
|
||||
background-repeat:no-repeat;
|
||||
background-position: 0 50% ! important;
|
||||
margin: 0 0 0 4px;
|
||||
padding: 0 ! important;
|
||||
cursor:pointer;
|
||||
float:left;
|
||||
}
|
||||
.ext-ie .ux-grow-action-item {
|
||||
width:16px;
|
||||
}
|
||||
.ux-action-right {
|
||||
float:right;
|
||||
margin: 0 3px 0 2px;
|
||||
padding: 0 ! important;
|
||||
}
|
||||
.ux-grow-action-text {
|
||||
padding: 0 ! important;
|
||||
margin:0 ! important;
|
||||
background:transparent none ! important;
|
||||
float:left;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
|
|
|
@ -46,107 +46,8 @@ Ext.grid.CheckColumn.prototype ={
|
|||
|
||||
|
||||
/**
|
||||
* ColumnTree
|
||||
* Rowexpander
|
||||
*/
|
||||
|
||||
|
||||
Ext.tree.ColumnTree = Ext.extend(Ext.tree.TreePanel, {
|
||||
lines:false,
|
||||
borderWidth: Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
|
||||
cls:'x-column-tree',
|
||||
|
||||
onRender : function(){
|
||||
Ext.tree.ColumnTree.superclass.onRender.apply(this, arguments);
|
||||
this.headers = this.body.createChild(
|
||||
{cls:'x-tree-headers'},this.innerCt.dom);
|
||||
|
||||
var cols = this.columns, c;
|
||||
var totalWidth = 0;
|
||||
|
||||
for(var i = 0, len = cols.length; i < len; i++){
|
||||
c = cols[i];
|
||||
totalWidth += c.width;
|
||||
this.headers.createChild({
|
||||
cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
|
||||
cn: {
|
||||
cls:'x-tree-hd-text',
|
||||
html: c.header
|
||||
},
|
||||
style:'width:'+(c.width-this.borderWidth)+'px;'
|
||||
});
|
||||
}
|
||||
this.headers.createChild({cls:'x-clear'});
|
||||
// prevent floats from wrapping when clipped
|
||||
this.headers.setWidth(totalWidth);
|
||||
this.innerCt.setWidth(totalWidth);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.tree.ColumnNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
|
||||
|
||||
focus: Ext.emptyFn, // prevent odd scrolling behavior
|
||||
|
||||
setColText : function(colidx, text) {
|
||||
this.colNode[colidx].innerHTML = text;
|
||||
},
|
||||
|
||||
renderElements : function(n, a, targetNode, bulkRender){
|
||||
this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
|
||||
this.colNode = [];
|
||||
|
||||
|
||||
var t = n.getOwnerTree();
|
||||
var cols = t.columns;
|
||||
var bw = t.borderWidth;
|
||||
var c = cols[0];
|
||||
|
||||
var buf = [
|
||||
'<li class="x-tree-node"><div ext:tree-node-id="',n.id,'" class="x-tree-node-el x-tree-node-leaf ', a.cls,'">',
|
||||
'<div class="x-tree-col" style="width:',c.width-bw,'px;">',
|
||||
'<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
|
||||
'<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
|
||||
'<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on">',
|
||||
'<a hidefocus="on" class="x-tree-node-anchor" href="',a.href ? a.href : "#",'" tabIndex="1" ',
|
||||
a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "", '>',
|
||||
'<span unselectable="on">', n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</span></a>",
|
||||
"</div>"];
|
||||
for(var i = 1, len = cols.length; i < len; i++){
|
||||
c = cols[i];
|
||||
|
||||
buf.push('<div class="x-tree-col ',(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
|
||||
'<div class="x-tree-col-text">',(c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]),"</div>",
|
||||
"</div>");
|
||||
}
|
||||
buf.push(
|
||||
'<div class="x-clear"></div></div>',
|
||||
'<ul class="x-tree-node-ct" style="display:none;"></ul>',
|
||||
"</li>");
|
||||
|
||||
if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
|
||||
this.wrap = Ext.DomHelper.insertHtml("beforeBegin",
|
||||
n.nextSibling.ui.getEl(), buf.join(""));
|
||||
}else{
|
||||
this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
|
||||
}
|
||||
|
||||
this.elNode = this.wrap.childNodes[0];
|
||||
this.ctNode = this.wrap.childNodes[1];
|
||||
var cs = this.elNode.firstChild.childNodes;
|
||||
this.indentNode = cs[0];
|
||||
this.ecNode = cs[1];
|
||||
this.iconNode = cs[2];
|
||||
this.anchor = cs[3];
|
||||
this.textNode = cs[3].firstChild;
|
||||
|
||||
for(var i = 1, len = cols.length; i < len; i++) {
|
||||
this.colNode[i] = this.elNode.childNodes[i].firstChild;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
Ext.grid.RowExpander = function(config){
|
||||
Ext.apply(this, config);
|
||||
|
||||
|
@ -1201,3 +1102,504 @@ Ext.ux.Multiselect = Ext.extend(Ext.form.Field, {
|
|||
});
|
||||
|
||||
Ext.reg("multiselect", Ext.ux.Multiselect);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Ext.ux.grid.ProgressColumn - Ext.ux.grid.ProgressColumn is a grid plugin that
|
||||
* shows a progress bar for a number between 0 and 100 to indicate some sort of
|
||||
* progress. The plugin supports all the normal cell/column operations including
|
||||
* sorting, editing, dragging, and hiding. It also supports special progression
|
||||
* coloring or standard Ext.ProgressBar coloring for the bar.
|
||||
*
|
||||
* @author Benjamin Runnels <kraven@kraven.org>
|
||||
* @copyright (c) 2008, by Benjamin Runnels
|
||||
* @date 06 June 2008
|
||||
* @version 1.1
|
||||
*
|
||||
* @license Ext.ux.grid.ProgressColumn is licensed under the terms of the Open
|
||||
* Source LGPL 3.0 license. Commercial use is permitted to the extent
|
||||
* that the code/component(s) do NOT become part of another Open Source
|
||||
* or Commercially licensed development library or toolkit without
|
||||
* explicit permission.
|
||||
*
|
||||
* License details: http://www.gnu.org/licenses/lgpl.html
|
||||
*/
|
||||
|
||||
Ext.namespace('Ext.ux.grid');
|
||||
|
||||
Ext.ux.grid.ProgressColumn = function(config) {
|
||||
Ext.apply(this, config);
|
||||
this.renderer = this.renderer.createDelegate(this);
|
||||
this.addEvents('action');
|
||||
Ext.ux.grid.ProgressColumn.superclass.constructor.call(this);
|
||||
};
|
||||
|
||||
Ext.extend(Ext.ux.grid.ProgressColumn, Ext.util.Observable, {
|
||||
/**
|
||||
* @cfg {String} colored determines whether use special progression coloring
|
||||
* or the standard Ext.ProgressBar coloring for the bar (defaults to
|
||||
* false)
|
||||
*/
|
||||
textPst : '%',
|
||||
/**
|
||||
* @cfg {String} colored determines whether use special progression coloring
|
||||
* or the standard Ext.ProgressBar coloring for the bar (defaults to
|
||||
* false)
|
||||
*/
|
||||
colored : false,
|
||||
/**
|
||||
* @cfg {String} actionEvent Event to trigger actions, e.g. click, dblclick,
|
||||
* mouseover (defaults to 'dblclick')
|
||||
*/
|
||||
actionEvent : 'dblclick',
|
||||
|
||||
init : function(grid) {
|
||||
this.grid = grid;
|
||||
this.view = grid.getView();
|
||||
|
||||
if (this.editor && grid.isEditor) {
|
||||
var cfg = {
|
||||
scope : this
|
||||
};
|
||||
cfg[this.actionEvent] = this.onClick;
|
||||
grid.afterRender = grid.afterRender.createSequence(function() {
|
||||
this.view.mainBody.on(cfg);
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
onClick : function(e, target) {
|
||||
var rowIndex = e.getTarget('.x-grid3-row').rowIndex;
|
||||
var colIndex = this.view.findCellIndex(target.parentNode.parentNode);
|
||||
|
||||
var t = e.getTarget('.x-progress-text');
|
||||
if (t) {
|
||||
this.grid.startEditing(rowIndex, colIndex);
|
||||
}
|
||||
},
|
||||
|
||||
renderer : function(v, p, record) {
|
||||
var style = '';
|
||||
var textClass = (v < 55) ? 'x-progress-text-back' : 'x-progress-text-front' + (Ext.isIE6 ? '-ie6' : '');
|
||||
|
||||
//ugly hack to deal with IE6 issue
|
||||
var text = String.format('</div><div class="x-progress-text {0}" style="width:100%;" id="{1}">{2}</div></div>',
|
||||
textClass, Ext.id(), v + this.textPst
|
||||
);
|
||||
text = (v<96) ? text.substring(0, text.length - 6) : text.substr(6);
|
||||
|
||||
if (this.colored == true) {
|
||||
if (v <= 100 && v > 66)
|
||||
style = '-green';
|
||||
if (v < 67 && v > 33)
|
||||
style = '-orange';
|
||||
if (v < 34)
|
||||
style = '-red';
|
||||
}
|
||||
|
||||
p.css += ' x-grid3-progresscol';
|
||||
return String.format(
|
||||
'<div class="x-progress-wrap"><div class="x-progress-inner"><div class="x-progress-bar{0}" style="width:{1}%;">{2}</div>' +
|
||||
'</div>', style, v, text
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// vim: ts=4:sw=4:nu:fdc=4:nospell
|
||||
/**
|
||||
* RowActions plugin for Ext grid
|
||||
*
|
||||
* Contains renderer for icons and fires events when an icon is clicked
|
||||
*
|
||||
* @author Ing. Jozef Sakáloš
|
||||
* @date 22. March 2008
|
||||
* @version $Id: Ext.ux.grid.RowActions.js 150 2008-04-08 21:50:58Z jozo $
|
||||
*
|
||||
* @license Ext.ux.grid.RowActions is licensed under the terms of
|
||||
* the Open Source LGPL 3.0 license. Commercial use is permitted to the extent
|
||||
* that the code/component(s) do NOT become part of another Open Source or Commercially
|
||||
* licensed development library or toolkit without explicit permission.
|
||||
*
|
||||
* License details: http://www.gnu.org/licenses/lgpl.html
|
||||
*/
|
||||
|
||||
/*global Ext */
|
||||
|
||||
Ext.ns('Ext.ux.grid');
|
||||
|
||||
/**
|
||||
* @class Ext.ux.grid.RowActions
|
||||
* @extends Ext.util.Observable
|
||||
*
|
||||
* CSS rules from Ext.ux.RowActions.css are mandatory
|
||||
*
|
||||
* Important general information: Actions are identified by iconCls. Wherever an <i>action</i>
|
||||
* is referenced (event argument, callback argument), the iconCls of clicked icon is used.
|
||||
* In another words, action identifier === iconCls.
|
||||
*
|
||||
* Creates new RowActions plugin
|
||||
* @constructor
|
||||
* @param {Object} config The config object
|
||||
*/
|
||||
Ext.ux.grid.RowActions = function(config) {
|
||||
Ext.apply(this, config);
|
||||
|
||||
// {{{
|
||||
this.addEvents(
|
||||
/**
|
||||
* @event beforeaction
|
||||
* Fires before action event. Return false to cancel the subsequent action event.
|
||||
* @param {Ext.grid.GridPanel} grid
|
||||
* @param {Ext.data.Record} record Record corresponding to row clicked
|
||||
* @param {String} action Identifies the action icon clicked. Equals to icon css class name.
|
||||
* @param {Integer} rowIndex Index of clicked grid row
|
||||
* @param {Integer} colIndex Index of clicked grid column that contains all action icons
|
||||
*/
|
||||
'beforeaction'
|
||||
/**
|
||||
* @event action
|
||||
* Fires when icon is clicked
|
||||
* @param {Ext.grid.GridPanel} grid
|
||||
* @param {Ext.data.Record} record Record corresponding to row clicked
|
||||
* @param {String} action Identifies the action icon clicked. Equals to icon css class name.
|
||||
* @param {Integer} rowIndex Index of clicked grid row
|
||||
* @param {Integer} colIndex Index of clicked grid column that contains all action icons
|
||||
*/
|
||||
,'action'
|
||||
/**
|
||||
* @event beforegroupaction
|
||||
* Fires before group action event. Return false to cancel the subsequent groupaction event.
|
||||
* @param {Ext.grid.GridPanel} grid
|
||||
* @param {Array} records Array of records in this group
|
||||
* @param {String} action Identifies the action icon clicked. Equals to icon css class name.
|
||||
* @param {String} groupId Identifies the group clicked
|
||||
*/
|
||||
,'beforegroupaction'
|
||||
/**
|
||||
* @event groupaction
|
||||
* Fires when icon in a group header is clicked
|
||||
* @param {Ext.grid.GridPanel} grid
|
||||
* @param {Array} records Array of records in this group
|
||||
* @param {String} action Identifies the action icon clicked. Equals to icon css class name.
|
||||
* @param {String} groupId Identifies the group clicked
|
||||
*/
|
||||
,'groupaction'
|
||||
);
|
||||
// }}}
|
||||
|
||||
// call parent
|
||||
Ext.ux.grid.RowActions.superclass.constructor.call(this);
|
||||
};
|
||||
|
||||
Ext.extend(Ext.ux.grid.RowActions, Ext.util.Observable, {
|
||||
|
||||
// configuration options
|
||||
// {{{
|
||||
/**
|
||||
* @cfg {Array} actions Mandatory. Array of action configuration objects. The following
|
||||
* configuration options of action are recognized:
|
||||
*
|
||||
* - @cfg {Function} callback Optional. Function to call if the action icon is clicked.
|
||||
* This function is called with same signature as action event and in its original scope.
|
||||
* If you need to call it in different scope or with another signature use
|
||||
* createCallback or createDelegate functions. Works for statically defined actions. Use
|
||||
* callbacks configuration options for store bound actions.
|
||||
*
|
||||
* - @cfg {Function} cb Shortcut for callback.
|
||||
*
|
||||
* - @cfg {String} iconIndex Optional, however either iconIndex or iconCls must be
|
||||
* configured. Field name of the field of the grid store record that contains
|
||||
* css class of the icon to show. If configured, shown icons can vary depending
|
||||
* of the value of this field.
|
||||
*
|
||||
* - @cfg {String} iconCls. css class of the icon to show. It is ignored if iconIndex is
|
||||
* configured. Use this if you want static icons that are not base on the values in the record.
|
||||
*
|
||||
* - @cfg {Boolean} hide Optional. True to hide this action while still have a space in
|
||||
* the grid column allocated to it. IMO, it doesn't make too much sense, use hideIndex instead.
|
||||
*
|
||||
* - @cfg (string} hideIndex Optional. Field name of the field of the grid store record that
|
||||
* contains hide flag (falsie [null, '', 0, false, undefined] to show, anything else to hide).
|
||||
*
|
||||
* - @cfg {String} qtipIndex Optional. Field name of the field of the grid store record that
|
||||
* contains tooltip text. If configured, the tooltip texts are taken from the store.
|
||||
*
|
||||
* - @cfg {String} tooltip Optional. Tooltip text to use as icon tooltip. It is ignored if
|
||||
* qtipIndex is configured. Use this if you want static tooltips that are not taken from the store.
|
||||
*
|
||||
* - @cfg {String} qtip Synonym for tooltip
|
||||
*
|
||||
* - @cfg {String} textIndex Optional. Field name of the field of the grids store record
|
||||
* that contains text to display on the right side of the icon. If configured, the text
|
||||
* shown is taken from record.
|
||||
*
|
||||
* - @cfg {String} text Optional. Text to display on the right side of the icon. Use this
|
||||
* if you want static text that are not taken from record. Ignored if textIndex is set.
|
||||
*
|
||||
* - @cfg {String} style Optional. Style to apply to action icon container.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} actionEvnet Event to trigger actions, e.g. click, dblclick, mouseover (defaults to 'click')
|
||||
*/
|
||||
actionEvent:'click'
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} autoWidth true to calculate field width for iconic actions only.
|
||||
*/
|
||||
,autoWidth:true
|
||||
|
||||
/**
|
||||
* @cfg {Array} groupActions Array of action to use for group headers of grouping grids.
|
||||
* These actions support static icons, texts and tooltips same way as actions. There is one
|
||||
* more action config recognized:
|
||||
* - @cfg {String} align Set it to 'left' to place action icon next to the group header text.
|
||||
* (defaults to undefined = icons are placed at the right side of the group header.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Object} callbacks iconCls keyed object that contains callback functions. For example:
|
||||
* callbacks:{
|
||||
* 'icon-open':function(...) {...}
|
||||
* ,'icon-save':function(...) {...}
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} header Actions column header
|
||||
*/
|
||||
,header:''
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} menuDisabled No sense to display header menu for this column
|
||||
*/
|
||||
,menuDisabled:true
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} sortable Usually it has no sense to sort by this column
|
||||
*/
|
||||
,sortable:false
|
||||
|
||||
/**
|
||||
* @cfg {String} tplGroup Template for group actions
|
||||
* @private
|
||||
*/
|
||||
,tplGroup:
|
||||
'<tpl for="actions">'
|
||||
+'<div class="ux-grow-action-item<tpl if="\'right\'===align"> ux-action-right</tpl> '
|
||||
+'{cls}" style="{style}" qtip="{qtip}">{text}</div>'
|
||||
+'</tpl>'
|
||||
|
||||
/**
|
||||
* @cfg {String} tplRow Template for row actions
|
||||
* @private
|
||||
*/
|
||||
,tplRow:
|
||||
'<div class="ux-row-action">'
|
||||
+'<tpl for="actions">'
|
||||
+'<div class="ux-row-action-item {cls} <tpl if="text">'
|
||||
+'ux-row-action-text</tpl>" style="{hide}{style}" qtip="{qtip}">'
|
||||
+'<tpl if="text"><span qtip="{qtip}">{text}</span></tpl></div>'
|
||||
+'</tpl>'
|
||||
+'</div>'
|
||||
|
||||
/**
|
||||
* @private {Number} widthIntercept constant used for auto-width calculation
|
||||
*/
|
||||
,widthIntercept:4
|
||||
|
||||
/**
|
||||
* @private {Number} widthSlope constant used for auto-width calculation
|
||||
*/
|
||||
,widthSlope:21
|
||||
// }}}
|
||||
|
||||
// methods
|
||||
// {{{
|
||||
/**
|
||||
* Init function
|
||||
* @param {Ext.grid.GridPanel} grid Grid this plugin is in
|
||||
*/
|
||||
,init:function(grid) {
|
||||
this.grid = grid;
|
||||
|
||||
// {{{
|
||||
// setup template
|
||||
if(!this.tpl) {
|
||||
this.tpl = this.processActions(this.actions);
|
||||
|
||||
} // eo template setup
|
||||
// }}}
|
||||
|
||||
// calculate width
|
||||
if(this.autoWidth) {
|
||||
this.width = this.widthSlope * this.actions.length + this.widthIntercept;
|
||||
this.fixed = true;
|
||||
}
|
||||
|
||||
// body click handler
|
||||
var view = grid.getView();
|
||||
var cfg = {scope:this};
|
||||
cfg[this.actionEvent] = this.onClick;
|
||||
grid.on({
|
||||
render:{scope:this, fn:function() {
|
||||
view.mainBody.on(cfg);
|
||||
}}
|
||||
});
|
||||
|
||||
// setup renderer
|
||||
if(!this.renderer) {
|
||||
this.renderer = function(value, cell, record, row, col, store) {
|
||||
cell.css += (cell.css ? ' ' : '') + 'ux-row-action-cell';
|
||||
return this.tpl.apply(this.getData(value, cell, record, row, col, store));
|
||||
}.createDelegate(this);
|
||||
}
|
||||
|
||||
// actions in grouping grids support
|
||||
if(view.groupTextTpl && this.groupActions) {
|
||||
view.interceptMouse = view.interceptMouse.createInterceptor(function(e) {
|
||||
if(e.getTarget('.ux-grow-action-item')) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
view.groupTextTpl =
|
||||
'<div class="ux-grow-action-text">' + view.groupTextTpl +'</div>'
|
||||
+this.processActions(this.groupActions, this.tplGroup).apply()
|
||||
;
|
||||
}
|
||||
|
||||
} // eo function init
|
||||
// }}}
|
||||
// {{{
|
||||
/**
|
||||
* Returns data to apply to template. Override this if needed.
|
||||
* @param {Mixed} value
|
||||
* @param {Object} cell object to set some attributes of the grid cell
|
||||
* @param {Ext.data.Record} record from which the data is extracted
|
||||
* @param {Number} row row index
|
||||
* @param {Number} col col index
|
||||
* @param {Ext.data.Store} store object from which the record is extracted
|
||||
* @returns {Object} data to apply to template
|
||||
*/
|
||||
,getData:function(value, cell, record, row, col, store) {
|
||||
return record.data || {};
|
||||
} // eo function getData
|
||||
// }}}
|
||||
// {{{
|
||||
/**
|
||||
* Processes actions configs and returns template.
|
||||
* @param {Array} actions
|
||||
* @param {String} template Optional. Template to use for one action item.
|
||||
* @return {String}
|
||||
* @private
|
||||
*/
|
||||
,processActions:function(actions, template) {
|
||||
var acts = [];
|
||||
|
||||
// actions loop
|
||||
Ext.each(actions, function(a, i) {
|
||||
// save callback
|
||||
if(a.iconCls && 'function' === typeof (a.callback || a.cb)) {
|
||||
this.callbacks = this.callbacks || {};
|
||||
this.callbacks[a.iconCls] = a.callback || a.cb;
|
||||
}
|
||||
|
||||
// data for intermediate template
|
||||
var o = {
|
||||
cls:a.iconIndex ? '{' + a.iconIndex + '}' : (a.iconCls ? a.iconCls : '')
|
||||
,qtip:a.qtipIndex ? '{' + a.qtipIndex + '}' : (a.tooltip || a.qtip ? a.tooltip || a.qtip : '')
|
||||
,text:a.textIndex ? '{' + a.textIndex + '}' : (a.text ? a.text : '')
|
||||
,hide:a.hideIndex ? '<tpl if="' + a.hideIndex + '">visibility:hidden;</tpl>' : (a.hide ? 'visibility:hidden;' : '')
|
||||
,align:a.align || 'right'
|
||||
,style:a.style ? a.style : ''
|
||||
};
|
||||
acts.push(o);
|
||||
|
||||
}, this); // eo actions loop
|
||||
|
||||
var xt = new Ext.XTemplate(template || this.tplRow);
|
||||
return new Ext.XTemplate(xt.apply({actions:acts}));
|
||||
|
||||
} // eo function processActions
|
||||
// }}}
|
||||
// {{{
|
||||
/**
|
||||
* Grid body actionEvent event handler
|
||||
* @private
|
||||
*/
|
||||
,onClick:function(e, target) {
|
||||
|
||||
var view = this.grid.getView();
|
||||
var action = false;
|
||||
|
||||
// handle row action click
|
||||
var row = e.getTarget('.x-grid3-row');
|
||||
var col = view.findCellIndex(target.parentNode.parentNode);
|
||||
|
||||
var t = e.getTarget('.ux-row-action-item');
|
||||
if(t) {
|
||||
action = t.className.replace(/ux-row-action-item /, '');
|
||||
if(action) {
|
||||
action = action.replace(/ ux-row-action-text/, '');
|
||||
action = action.trim();
|
||||
}
|
||||
}
|
||||
if(false !== row && false !== col && false !== action) {
|
||||
var record = this.grid.store.getAt(row.rowIndex);
|
||||
|
||||
// call callback if any
|
||||
if(this.callbacks && 'function' === typeof this.callbacks[action]) {
|
||||
this.callbacks[action](this.grid, record, action, row.rowIndex, col);
|
||||
}
|
||||
|
||||
// fire events
|
||||
if(true !== this.eventsSuspended && false === this.fireEvent('beforeaction', this.grid, record, action, row.rowIndex, col)) {
|
||||
return;
|
||||
}
|
||||
else if(true !== this.eventsSuspended) {
|
||||
this.fireEvent('action', this.grid, record, action, row.rowIndex, col);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// handle group action click
|
||||
t = e.getTarget('.ux-grow-action-item');
|
||||
if(t) {
|
||||
// get groupId
|
||||
var group = view.findGroup(target);
|
||||
var groupId = group ? group.id.replace(/ext-gen[0-9]+-gp-/, '') : null;
|
||||
|
||||
// get matching records
|
||||
var records;
|
||||
if(groupId) {
|
||||
var re = new RegExp(groupId);
|
||||
records = this.grid.store.queryBy(function(r) {
|
||||
return r._groupId.match(re);
|
||||
});
|
||||
records = records ? records.items : [];
|
||||
}
|
||||
action = t.className.replace(/ux-grow-action-item (ux-action-right )*/, '');
|
||||
|
||||
// call callback if any
|
||||
if('function' === typeof this.callbacks[action]) {
|
||||
this.callbacks[action](this.grid, records, action, groupId);
|
||||
}
|
||||
|
||||
// fire events
|
||||
if(true !== this.eventsSuspended && false === this.fireEvent('beforegroupaction', this.grid, records, action, groupId)) {
|
||||
return false;
|
||||
}
|
||||
this.fireEvent('groupaction', this.grid, records, action, groupId);
|
||||
}
|
||||
} // eo function onClick
|
||||
// }}}
|
||||
|
||||
});
|
||||
|
||||
// registre xtype
|
||||
Ext.reg('rowactions', Ext.ux.grid.RowActions);
|
||||
|
||||
// eof
|
||||
|
|
|
@ -95,6 +95,30 @@ tvheadend.tableEditor = function(title, dtable, cm, rec, plugins, store,
|
|||
disabled: true
|
||||
});
|
||||
|
||||
var saveBtn = new Ext.Toolbar.Button({
|
||||
tooltip: 'Save any changes made (Changed cells have red borders)',
|
||||
iconCls:'save',
|
||||
text: "Save changes",
|
||||
handler: saveChanges,
|
||||
disabled: true
|
||||
});
|
||||
|
||||
var rejectBtn = new Ext.Toolbar.Button({
|
||||
tooltip: 'Revert any changes made (Changed cells have red borders)',
|
||||
iconCls:'undo',
|
||||
text: "Revert changes",
|
||||
handler: function() {
|
||||
store.rejectChanges();
|
||||
},
|
||||
disabled: true
|
||||
});
|
||||
|
||||
store.on('update', function(s, r, o) {
|
||||
d = s.getModifiedRecords().length == 0
|
||||
saveBtn.setDisabled(d);
|
||||
rejectBtn.setDisabled(d);
|
||||
});
|
||||
|
||||
selModel.on('selectionchange', function(self) {
|
||||
if(self.getCount() > 0) {
|
||||
delButton.enable();
|
||||
|
@ -119,12 +143,7 @@ tvheadend.tableEditor = function(title, dtable, cm, rec, plugins, store,
|
|||
iconCls:'add',
|
||||
text: 'Add entry',
|
||||
handler: addRecord
|
||||
}, '-', delButton, '-', {
|
||||
tooltip: 'Save any changes made (Changed cells have red borders).',
|
||||
iconCls:'save',
|
||||
text: "Save changes",
|
||||
handler: saveChanges
|
||||
}, '->', {
|
||||
}, '-', delButton, '-', saveBtn, rejectBtn, '->', {
|
||||
text: 'Help',
|
||||
handler: function() {
|
||||
new tvheadend.help(title, helpContent);
|
||||
|
|
|
@ -36,7 +36,6 @@ tvheadend.help = function(title, pagename) {
|
|||
*/
|
||||
function accessUpdate(o) {
|
||||
|
||||
|
||||
if(o.dvr == true && tvheadend.dvrpanel == null) {
|
||||
tvheadend.dvrpanel = new tvheadend.dvr;
|
||||
tvheadend.rootTabPanel.add(tvheadend.dvrpanel);
|
||||
|
@ -71,103 +70,23 @@ function accessUpdate(o) {
|
|||
tvheadend.rootTabPanel.doLayout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Comet interfaces
|
||||
*/
|
||||
tvheadend.comet_poller = function() {
|
||||
|
||||
function parse_comet_response(responsetxt) {
|
||||
|
||||
var response = Ext.util.JSON.decode(responsetxt);
|
||||
|
||||
for (var x = 0; x < response.messages.length; x++) {
|
||||
var m = response.messages[x];
|
||||
|
||||
switch(m.notificationClass) {
|
||||
*
|
||||
*/
|
||||
tvheadend.log = function(msg, style) {
|
||||
s = style ? '<div style="' + style + '">' : '<div>'
|
||||
|
||||
case 'accessUpdate':
|
||||
accessUpdate(m);
|
||||
break;
|
||||
|
||||
case 'channeltags':
|
||||
if(m.reload != null)
|
||||
tvheadend.channelTags.reload();
|
||||
break;
|
||||
|
||||
case 'autorec':
|
||||
if(m.asyncreload != null)
|
||||
tvheadend.autorecStore.reload();
|
||||
break;
|
||||
|
||||
case 'dvrdb':
|
||||
if(m.reload != null)
|
||||
tvheadend.dvrStore.reload();
|
||||
break;
|
||||
|
||||
case 'channels':
|
||||
if(m.reload != null)
|
||||
tvheadend.channels.reload();
|
||||
break;
|
||||
|
||||
case 'logmessage':
|
||||
|
||||
var sl = Ext.get('systemlog');
|
||||
var e = Ext.DomHelper.append(sl,
|
||||
'<div>' + m.logtxt + '</div>');
|
||||
e.scrollIntoView(sl);
|
||||
break;
|
||||
|
||||
case 'dvbadapter':
|
||||
case 'dvbmux':
|
||||
case 'dvbtransport':
|
||||
var n = tvheadend.dvbtree.getNodeById(m.id);
|
||||
if(n != null) {
|
||||
|
||||
if(m.reload != null && n.isLoaded()) {
|
||||
n.reload();
|
||||
}
|
||||
|
||||
if(m.name != null) {
|
||||
n.setText(m.name);
|
||||
n.attributes.name = m.name;
|
||||
}
|
||||
|
||||
if(m.quality != null) {
|
||||
n.getUI().setColText(3, m.quality);
|
||||
n.attributes.quality = m.quality;
|
||||
}
|
||||
|
||||
if(m.status != null) {
|
||||
n.getUI().setColText(2, m.status);
|
||||
n.attributes.status = m.status;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '/comet',
|
||||
params : { boxid: response.boxid },
|
||||
success: function(result, request) {
|
||||
parse_comet_response(result.responseText);
|
||||
}});
|
||||
|
||||
};
|
||||
|
||||
Ext.Ajax.request({
|
||||
url: '/comet',
|
||||
success: function(result, request) {
|
||||
parse_comet_response(result.responseText);
|
||||
}});
|
||||
sl = Ext.get('systemlog');
|
||||
e = Ext.DomHelper.append(sl, s + '<pre>' + msg + '</pre></div>');
|
||||
e.scrollIntoView('systemlog');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
// create application
|
||||
tvheadend.app = function() {
|
||||
|
||||
|
@ -176,7 +95,6 @@ tvheadend.app = function() {
|
|||
|
||||
// public methods
|
||||
init: function() {
|
||||
|
||||
|
||||
tvheadend.rootTabPanel = new Ext.TabPanel({
|
||||
region:'center',
|
||||
|
@ -202,8 +120,14 @@ tvheadend.app = function() {
|
|||
]
|
||||
});
|
||||
|
||||
tvheadend.comet.on('accessUpdate', accessUpdate);
|
||||
|
||||
tvheadend.comet.on('logmessage', function(m) {
|
||||
tvheadend.log(m.logtxt);
|
||||
});
|
||||
|
||||
new tvheadend.cometPoller;
|
||||
|
||||
new tvheadend.comet_poller;
|
||||
Ext.QuickTips.init();
|
||||
}
|
||||
|
||||
|
|
BIN
src/webui/static/icons/information.png
Normal file
After Width: | Height: | Size: 778 B |
BIN
src/webui/static/icons/progress-bg-green.gif
Normal file
After Width: | Height: | Size: 120 B |
BIN
src/webui/static/icons/progress-bg-orange.gif
Normal file
After Width: | Height: | Size: 120 B |
BIN
src/webui/static/icons/progress-bg-red.gif
Normal file
After Width: | Height: | Size: 120 B |
Before Width: | Height: | Size: 828 B After Width: | Height: | Size: 883 B |
BIN
src/webui/static/icons/undo.png
Normal file
After Width: | Height: | Size: 631 B |