src/teletext.c \
src/channels.c \
src/subscriptions.c \
- src/transports.c \
+ src/service.c \
src/psi.c \
src/parsers.c \
src/parser_h264.c \
#include "psi.h"
#include "tsdemux.h"
#include "ffdecsa/FFdecsa.h"
-#include "transports.h"
#include "capmt.h"
#include "notify.h"
-
+#include "subscriptions.h"
#include "dtable.h"
// ca_pmt_list_management values:
*
*/
TAILQ_HEAD(capmt_queue, capmt);
-LIST_HEAD(capmt_transport_list, capmt_transport);
+LIST_HEAD(capmt_service_list, capmt_service);
LIST_HEAD(capmt_caid_ecm_list, capmt_caid_ecm);
static struct capmt_queue capmts;
static pthread_cond_t capmt_config_changed;
/**
*
*/
-typedef struct capmt_transport {
+typedef struct capmt_service {
th_descrambler_t ct_head;
- th_transport_t *ct_transport;
+ service_t *ct_service;
struct capmt *ct_capmt;
- LIST_ENTRY(capmt_transport) ct_link;
+ LIST_ENTRY(capmt_service) ct_link;
/* list of used ca-systems with ids and last ecm */
struct capmt_caid_ecm_list ct_caid_ecm;
/* sending requests will be based on this caid */
int ct_caid_last;
-} capmt_transport_t;
+} capmt_service_t;
/**
TAILQ_ENTRY(capmt) capmt_link; /* Linkage protected via global_lock */
- struct capmt_transport_list capmt_transports;
+ struct capmt_service_list capmt_services;
/* from capmt configuration */
char *capmt_sockfile;
}
static void
-capmt_send_stop(capmt_transport_t *t)
+capmt_send_stop(capmt_service_t *t)
{
/* buffer for capmt */
int pos = 0;
capmt_header_t head = {
.capmt_indicator = { 0x9F, 0x80, 0x32, 0x82, 0x00, 0x00 },
.capmt_list_management = CAPMT_LIST_ONLY,
- .program_number = t->ct_transport->tht_dvb_service_id,
+ .program_number = t->ct_service->s_dvb_service_id,
.version_number = 0,
.current_next_indicator = 0,
.program_info_length = 0,
pos += sizeof(end);
buf[4] = ((pos - 6) >> 8);
buf[5] = ((pos - 6) & 0xFF);
- buf[7] = t->ct_transport->tht_dvb_service_id >> 8;
- buf[8] = t->ct_transport->tht_dvb_service_id & 0xFF;
+ buf[7] = t->ct_service->s_dvb_service_id >> 8;
+ buf[8] = t->ct_service->s_dvb_service_id & 0xFF;
buf[9] = 1;
buf[10] = ((pos - 5 - 12) & 0xF00) >> 8;
buf[11] = ((pos - 5 - 12) & 0xFF);
/**
* global_lock is held
- * tht_stream_mutex is held
+ * s_stream_mutex is held
*/
static void
-capmt_transport_destroy(th_descrambler_t *td)
+capmt_service_destroy(th_descrambler_t *td)
{
tvhlog(LOG_INFO, "capmt", "Removing CAPMT Server from service");
- capmt_transport_t *ct = (capmt_transport_t *)td;
+ capmt_service_t *ct = (capmt_service_t *)td;
/* send stop to client */
capmt_send_stop(ct);
free(cce);
}
- LIST_REMOVE(td, td_transport_link);
+ LIST_REMOVE(td, td_service_link);
LIST_REMOVE(ct, ct_link);
static void
handle_ca0(capmt_t* capmt) {
- capmt_transport_t *ct;
- th_transport_t *t;
+ capmt_service_t *ct;
+ service_t *t;
int ret;
uint8_t invalid[8], buffer[20], *even, *odd;
even = &buffer[2];
odd = &buffer[10];
- LIST_FOREACH(ct, &capmt->capmt_transports, ct_link) {
- t = ct->ct_transport;
+ LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
+ t = ct->ct_service;
if(ret < 18) {
if(ct->ct_keystate != CT_FORBIDDEN) {
- tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->tht_svcname);
+ tvhlog(LOG_ERR, "capmt", "Can not descramble service \"%s\", access denied", t->s_svcname);
ct->ct_keystate = CT_FORBIDDEN;
}
set_odd_control_word(ct->ct_keys, odd);
if(ct->ct_keystate != CT_RESOLVED)
- tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->tht_svcname);
+ tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
ct->ct_keystate = CT_RESOLVED;
}
*
*/
static void
-capmt_table_input(struct th_descrambler *td, struct th_transport *t,
+capmt_table_input(struct th_descrambler *td, struct service *t,
struct th_stream *st, const uint8_t *data, int len)
{
- capmt_transport_t *ct = (capmt_transport_t *)td;
+ capmt_service_t *ct = (capmt_service_t *)td;
capmt_t *capmt = ct->ct_capmt;
- int adapter_num = t->tht_dvb_mux_instance->tdmi_adapter->tda_adapter_num;
+ int adapter_num = t->s_dvb_mux_instance->tdmi_adapter->tda_adapter_num;
caid_t *c;
if (!cce)
{
tvhlog(LOG_DEBUG, "capmt",
- "New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname);
+ "New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
/* ecmpid not already seen, add it to list */
cce = calloc(1, sizeof(capmt_caid_ecm_t));
break;
}
- uint16_t sid = t->tht_dvb_service_id;
+ uint16_t sid = t->s_dvb_service_id;
uint16_t ecmpid = st->st_pid;
uint16_t transponder = 0;
if(ct->ct_keystate != CT_RESOLVED)
tvhlog(LOG_INFO, "capmt",
- "Trying to obtain key for service \"%s\"",t->tht_svcname);
+ "Trying to obtain key for service \"%s\"",t->s_svcname);
buf[9] = pmtversion;
pmtversion = (pmtversion + 1) & 0x1F;
*
*/
static int
-capmt_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st,
+capmt_descramble(th_descrambler_t *td, service_t *t, struct th_stream *st,
const uint8_t *tsb)
{
- capmt_transport_t *ct = (capmt_transport_t *)td;
+ capmt_service_t *ct = (capmt_service_t *)td;
int r, i;
unsigned char *vec[3];
uint8_t *t0;
* global_lock is held
*/
void
-capmt_transport_start(th_transport_t *t)
+capmt_service_start(service_t *t)
{
capmt_t *capmt;
- capmt_transport_t *ct;
+ capmt_service_t *ct;
capmt_caid_ecm_t *cce;
th_descrambler_t *td;
TAILQ_FOREACH(capmt, &capmts, capmt_link) {
tvhlog(LOG_INFO, "capmt",
"Starting capmt server for service \"%s\" on tuner %d",
- t->tht_svcname,
- t->tht_dvb_mux_instance->tdmi_adapter->tda_adapter_num);
+ t->s_svcname,
+ t->s_dvb_mux_instance->tdmi_adapter->tda_adapter_num);
th_stream_t *st;
- /* create new capmt transport */
- ct = calloc(1, sizeof(capmt_transport_t));
+ /* create new capmt service */
+ ct = calloc(1, sizeof(capmt_service_t));
ct->ct_cluster_size = get_suggested_cluster_size();
ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
ct->ct_seq = capmt->capmt_seq++;
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
caid_t *c = LIST_FIRST(&st->st_caids);
if(c == NULL)
continue;
tvhlog(LOG_DEBUG, "capmt",
- "New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname);
+ "New caid 0x%04X for service \"%s\"", c->caid, t->s_svcname);
/* add it to list */
cce = calloc(1, sizeof(capmt_caid_ecm_t));
ct->ct_keys = get_key_struct();
ct->ct_capmt = capmt;
- ct->ct_transport = t;
+ ct->ct_service = t;
td = &ct->ct_head;
- td->td_stop = capmt_transport_destroy;
+ td->td_stop = capmt_service_destroy;
td->td_table = capmt_table_input;
td->td_descramble = capmt_descramble;
- LIST_INSERT_HEAD(&t->tht_descramblers, td, td_transport_link);
+ LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
- LIST_INSERT_HEAD(&capmt->capmt_transports, ct, ct_link);
+ LIST_INSERT_HEAD(&capmt->capmt_services, ct, ct_link);
}
}
void capmt_init(void);
-void capmt_transport_start(th_transport_t *t);
+void capmt_service_start(struct service *t);
#endif /* CAPMT_H_ */
#include "tvheadend.h"
#include "psi.h"
#include "channels.h"
-#include "transports.h"
#include "epg.h"
#include "xmltv.h"
#include "dtable.h"
}
/**
- * Rename a channel and all tied transports
+ * Rename a channel and all tied services
*/
int
channel_rename(channel_t *ch, const char *newname)
{
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
RB_REMOVE(&channel_name_tree, ch, ch_name_link);
channel_set_name(ch, newname);
- LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
- t->tht_config_save(t);
+ LIST_FOREACH(t, &ch->ch_services, s_ch_link)
+ t->s_config_save(t);
channel_save(ch);
htsp_channel_update(ch);
void
channel_delete(channel_t *ch)
{
- th_transport_t *t;
+ service_t *t;
th_subscription_t *s;
channel_tag_mapping_t *ctm;
dvr_destroy_by_channel(ch);
- while((t = LIST_FIRST(&ch->ch_transports)) != NULL)
- transport_map_channel(t, NULL, 1);
+ while((t = LIST_FIRST(&ch->ch_services)) != NULL)
+ service_map_channel(t, NULL, 1);
while((s = LIST_FIRST(&ch->ch_subscriptions)) != NULL) {
LIST_REMOVE(s, ths_channel_link);
/**
- * Merge transports from channel 'src' to channel 'dst'
+ * Merge services from channel 'src' to channel 'dst'
*
* Then, destroy the 'src' channel
*/
void
channel_merge(channel_t *dst, channel_t *src)
{
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" merged into \"%s\"",
src->ch_name, dst->ch_name);
- while((t = LIST_FIRST(&src->ch_transports)) != NULL)
- transport_map_channel(t, dst, 1);
+ while((t = LIST_FIRST(&src->ch_services)) != NULL)
+ service_map_channel(t, dst, 1);
channel_delete(src);
}
RB_ENTRY(channel) ch_identifier_link;
int ch_id;
- LIST_HEAD(, th_transport) ch_transports;
+ LIST_HEAD(, service) ch_services;
LIST_HEAD(, th_subscription) ch_subscriptions;
struct event_tree ch_epg_events;
#include "psi.h"
#include "tsdemux.h"
#include "ffdecsa/FFdecsa.h"
-#include "transports.h"
#include "cwc.h"
#include "notify.h"
#include "atomic.h"
#include "dtable.h"
+#include "subscriptions.h"
/**
*
*
*/
TAILQ_HEAD(cwc_queue, cwc);
-LIST_HEAD(cwc_transport_list, cwc_transport);
+LIST_HEAD(cwc_service_list, cwc_service);
TAILQ_HEAD(cwc_message_queue, cwc_message);
LIST_HEAD(ecm_section_list, ecm_section);
static struct cwc_queue cwcs;
/**
*
*/
-typedef struct cwc_transport {
- th_descrambler_t ct_head;
+typedef struct cwc_service {
+ th_descrambler_t cs_head;
- th_transport_t *ct_transport;
+ service_t *cs_service;
- struct cwc *ct_cwc;
+ struct cwc *cs_cwc;
- LIST_ENTRY(cwc_transport) ct_link;
+ LIST_ENTRY(cwc_service) cs_link;
- int ct_okchannel;
+ int cs_okchannel;
/**
- * Status of the key(s) in ct_keys
+ * Status of the key(s) in cs_keys
*/
enum {
- CT_UNKNOWN,
- CT_RESOLVED,
- CT_FORBIDDEN
- } ct_keystate;
+ CS_UNKNOWN,
+ CS_RESOLVED,
+ CS_FORBIDDEN
+ } cs_keystate;
- void *ct_keys;
+ void *cs_keys;
- uint8_t ct_cw[16];
- int ct_pending_cw_update;
+ uint8_t cs_cw[16];
+ int cs_pending_cw_update;
/**
* CSA
*/
- int ct_cluster_size;
- uint8_t *ct_tsbcluster;
- int ct_fill;
+ int cs_cluster_size;
+ uint8_t *cs_tsbcluster;
+ int cs_fill;
- LIST_HEAD(, ecm_pid) ct_pids;
+ LIST_HEAD(, ecm_pid) cs_pids;
-} cwc_transport_t;
+} cwc_service_t;
/**
TAILQ_ENTRY(cwc) cwc_link; /* Linkage protected via global_lock */
- struct cwc_transport_list cwc_transports;
+ struct cwc_service_list cwc_services;
uint16_t cwc_caid;
*
*/
-static void cwc_transport_destroy(th_descrambler_t *td);
+static void cwc_service_destroy(th_descrambler_t *td);
extern char *cwc_krypt(const char *key, const char *salt);
-static void cwc_detect_card_type(cwc_t *cwc);
+static void cwc_detecs_card_type(cwc_t *cwc);
void cwc_emm_conax(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_irdeto(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len);
cwc->cwc_ua[0], cwc->cwc_ua[1], cwc->cwc_ua[2], cwc->cwc_ua[3], cwc->cwc_ua[4], cwc->cwc_ua[5], cwc->cwc_ua[6], cwc->cwc_ua[7],
nprov);
- cwc_detect_card_type(cwc);
+ cwc_detecs_card_type(cwc);
msg += 15;
plen -= 12;
* based on the equivalent in sasc-ng
*/
static void
-cwc_detect_card_type(cwc_t *cwc)
+cwc_detecs_card_type(cwc_t *cwc)
{
uint8_t c_sys = cwc->cwc_caid >> 8;
static void
-handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
+handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
int len, int seq)
{
- th_transport_t *t = ct->ct_transport;
+ service_t *t = ct->cs_service;
ecm_pid_t *ep;
char chaninfo[32];
int i;
/* ERROR */
- if(ct->ct_okchannel == es->es_channel)
- ct->ct_okchannel = -1;
+ if(ct->cs_okchannel == es->es_channel)
+ ct->cs_okchannel = -1;
- if(ct->ct_keystate == CT_FORBIDDEN)
+ if(ct->cs_keystate == CS_FORBIDDEN)
return; // We already know it's bad
es->es_nok = 1;
tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d "
- "Req delay: %lld ms)", t->tht_svcname, chaninfo, seq, delay);
+ "Req delay: %lld ms)", t->s_svcname, chaninfo, seq, delay);
- LIST_FOREACH(ep, &ct->ct_pids, ep_link) {
+ LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
for(i = 0; i <= ep->ep_last_section; i++)
if(ep->ep_sections[i] == NULL ||
ep->ep_sections[i]->es_pending ||
tvhlog(LOG_ERR, "cwc",
"Can not descramble service \"%s\", access denied (seqno: %d "
"Req delay: %lld ms)",
- t->tht_svcname, seq, delay);
- ct->ct_keystate = CT_FORBIDDEN;
+ t->s_svcname, seq, delay);
+ ct->cs_keystate = CS_FORBIDDEN;
return;
} else {
- ct->ct_okchannel = es->es_channel;
+ ct->cs_okchannel = es->es_channel;
es->es_nok = 0;
tvhlog(LOG_DEBUG, "cwc",
" odd: %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (seqno: %d "
"Req delay: %lld ms)",
chaninfo,
- t->tht_svcname,
+ t->s_svcname,
msg[3 + 0], msg[3 + 1], msg[3 + 2], msg[3 + 3], msg[3 + 4],
msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9],
msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
msg[3 + 15], seq, delay);
- if(ct->ct_keystate != CT_RESOLVED)
+ if(ct->cs_keystate != CS_RESOLVED)
tvhlog(LOG_INFO, "cwc",
"Obtained key for for service \"%s\" in %lld ms, from %s",
- t->tht_svcname, delay, ct->ct_cwc->cwc_hostname);
+ t->s_svcname, delay, ct->cs_cwc->cwc_hostname);
- pthread_mutex_lock(&t->tht_stream_mutex);
- ct->ct_keystate = CT_RESOLVED;
- memcpy(ct->ct_cw, msg + 3, 16);
- ct->ct_pending_cw_update = 1;
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ ct->cs_keystate = CS_RESOLVED;
+ memcpy(ct->cs_cw, msg + 3, 16);
+ ct->cs_pending_cw_update = 1;
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
}
static int
cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
{
- cwc_transport_t *ct;
+ cwc_service_t *ct;
ecm_pid_t *ep;
ecm_section_t *es;
uint16_t seq = (msg[2] << 8) | msg[3];
switch(msgtype) {
case 0x80:
case 0x81:
- LIST_FOREACH(ct, &cwc->cwc_transports, ct_link) {
- LIST_FOREACH(ep, &ct->ct_pids, ep_link) {
+ LIST_FOREACH(ct, &cwc->cwc_services, cs_link) {
+ LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
for(i = 0; i <= ep->ep_last_section; i++) {
es = ep->ep_sections[i];
if(es != NULL) {
static void *
cwc_thread(void *aux)
{
- cwc_transport_t *ct;
+ cwc_service_t *ct;
cwc_t *cwc = aux;
int fd, d;
char errbuf[100];
- th_transport_t *t;
+ service_t *t;
char hostname[256];
int port;
struct timespec ts;
tvhlog(LOG_INFO, "cwc", "%s destroyed", cwc->cwc_hostname);
- while((ct = LIST_FIRST(&cwc->cwc_transports)) != NULL) {
- t = ct->ct_transport;
- pthread_mutex_lock(&t->tht_stream_mutex);
- cwc_transport_destroy(&ct->ct_head);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ while((ct = LIST_FIRST(&cwc->cwc_services)) != NULL) {
+ t = ct->cs_service;
+ pthread_mutex_lock(&t->s_stream_mutex);
+ cwc_service_destroy(&ct->cs_head);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
free((void *)cwc->cwc_password);
*
*/
static void
-cwc_table_input(struct th_descrambler *td, struct th_transport *t,
+cwc_table_input(struct th_descrambler *td, struct service *t,
struct th_stream *st, const uint8_t *data, int len)
{
- cwc_transport_t *ct = (cwc_transport_t *)td;
- uint16_t sid = t->tht_dvb_service_id;
- cwc_t *cwc = ct->ct_cwc;
+ cwc_service_t *ct = (cwc_service_t *)td;
+ uint16_t sid = t->s_dvb_service_id;
+ cwc_t *cwc = ct->cs_cwc;
int channel;
int section;
ecm_pid_t *ep;
if((data[0] & 0xf0) != 0x80)
return;
- LIST_FOREACH(ep, &ct->ct_pids, ep_link) {
+ LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
if(ep->ep_pid == st->st_pid)
break;
}
if(ep == NULL) {
ep = calloc(1, sizeof(ecm_pid_t));
ep->ep_pid = st->st_pid;
- LIST_INSERT_HEAD(&ct->ct_pids, ep, ep_link);
+ LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
}
if(cwc->cwc_fd == -1) {
// New key, but we are not connected (anymore), can not descramble
- ct->ct_keystate = CT_UNKNOWN;
+ ct->cs_keystate = CS_UNKNOWN;
break;
}
memcpy(es->es_ecm, data, len);
es->es_ecmsize = len;
- if(ct->ct_okchannel != -1 && channel != -1 &&
- ct->ct_okchannel != channel) {
+ if(ct->cs_okchannel != -1 && channel != -1 &&
+ ct->cs_okchannel != channel) {
tvhlog(LOG_DEBUG, "cwc", "Filtering ECM channel %d", channel);
return;
}
tvhlog(LOG_DEBUG, "cwc",
"Sending ECM%s section=%d/%d, for service %s (seqno: %d) PID %d",
- chaninfo, section, ep->ep_last_section, t->tht_svcname, es->es_seq,
+ chaninfo, section, ep->ep_last_section, t->s_svcname, es->es_seq,
st->st_pid);
es->es_time = getmonoclock();
break;
*
*/
static void
-update_keys(cwc_transport_t *ct)
+update_keys(cwc_service_t *ct)
{
int i;
- ct->ct_pending_cw_update = 0;
+ ct->cs_pending_cw_update = 0;
for(i = 0; i < 8; i++)
- if(ct->ct_cw[i]) {
- set_even_control_word(ct->ct_keys, ct->ct_cw);
+ if(ct->cs_cw[i]) {
+ set_even_control_word(ct->cs_keys, ct->cs_cw);
break;
}
for(i = 0; i < 8; i++)
- if(ct->ct_cw[8 + i]) {
- set_odd_control_word(ct->ct_keys, ct->ct_cw + 8);
+ if(ct->cs_cw[8 + i]) {
+ set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
break;
}
}
*
*/
static int
-cwc_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st,
+cwc_descramble(th_descrambler_t *td, service_t *t, struct th_stream *st,
const uint8_t *tsb)
{
- cwc_transport_t *ct = (cwc_transport_t *)td;
+ cwc_service_t *ct = (cwc_service_t *)td;
int r;
unsigned char *vec[3];
- if(ct->ct_keystate == CT_FORBIDDEN)
+ if(ct->cs_keystate == CS_FORBIDDEN)
return 1;
- if(ct->ct_keystate != CT_RESOLVED)
+ if(ct->cs_keystate != CS_RESOLVED)
return -1;
- if(ct->ct_fill == 0 && ct->ct_pending_cw_update)
+ if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
update_keys(ct);
- memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
- ct->ct_fill++;
+ memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
+ ct->cs_fill++;
- if(ct->ct_fill != ct->ct_cluster_size)
+ if(ct->cs_fill != ct->cs_cluster_size)
return 0;
while(1) {
- vec[0] = ct->ct_tsbcluster;
- vec[1] = ct->ct_tsbcluster + ct->ct_fill * 188;
+ vec[0] = ct->cs_tsbcluster;
+ vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
vec[2] = NULL;
- r = decrypt_packets(ct->ct_keys, vec);
+ r = decrypt_packets(ct->cs_keys, vec);
if(r > 0) {
int i;
- const uint8_t *t0 = ct->ct_tsbcluster;
+ const uint8_t *t0 = ct->cs_tsbcluster;
for(i = 0; i < r; i++) {
ts_recv_packet2(t, t0);
t0 += 188;
}
- r = ct->ct_fill - r;
+ r = ct->cs_fill - r;
assert(r >= 0);
if(r > 0)
- memmove(ct->ct_tsbcluster, t0, r * 188);
- ct->ct_fill = r;
+ memmove(ct->cs_tsbcluster, t0, r * 188);
+ ct->cs_fill = r;
- if(ct->ct_pending_cw_update && r > 0)
+ if(ct->cs_pending_cw_update && r > 0)
continue;
} else {
- ct->ct_fill = 0;
+ ct->cs_fill = 0;
}
break;
}
- if(ct->ct_pending_cw_update)
+ if(ct->cs_pending_cw_update)
update_keys(ct);
return 0;
/**
* global_lock is held
- * tht_stream_mutex is held
+ * s_stream_mutex is held
*/
static void
-cwc_transport_destroy(th_descrambler_t *td)
+cwc_service_destroy(th_descrambler_t *td)
{
- cwc_transport_t *ct = (cwc_transport_t *)td;
+ cwc_service_t *ct = (cwc_service_t *)td;
ecm_pid_t *ep;
int i;
- while((ep = LIST_FIRST(&ct->ct_pids)) != NULL) {
+ while((ep = LIST_FIRST(&ct->cs_pids)) != NULL) {
for(i = 0; i < 256; i++)
free(ep->ep_sections[i]);
LIST_REMOVE(ep, ep_link);
free(ep);
}
- LIST_REMOVE(td, td_transport_link);
+ LIST_REMOVE(td, td_service_link);
- LIST_REMOVE(ct, ct_link);
+ LIST_REMOVE(ct, cs_link);
- free_key_struct(ct->ct_keys);
- free(ct->ct_tsbcluster);
+ free_key_struct(ct->cs_keys);
+ free(ct->cs_tsbcluster);
free(ct);
}
*
*/
static inline th_stream_t *
-cwc_find_stream_by_caid(th_transport_t *t, int caid)
+cwc_find_stream_by_caid(service_t *t, int caid)
{
th_stream_t *st;
caid_t *c;
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
LIST_FOREACH(c, &st->st_caids, link) {
if(c->caid == caid)
return st;
* global_lock is held
*/
void
-cwc_transport_start(th_transport_t *t)
+cwc_service_start(service_t *t)
{
cwc_t *cwc;
- cwc_transport_t *ct;
+ cwc_service_t *ct;
th_descrambler_t *td;
lock_assert(&global_lock);
if(cwc_find_stream_by_caid(t, cwc->cwc_caid) == NULL)
continue;
- ct = calloc(1, sizeof(cwc_transport_t));
- ct->ct_cluster_size = get_suggested_cluster_size();
- ct->ct_tsbcluster = malloc(ct->ct_cluster_size * 188);
+ ct = calloc(1, sizeof(cwc_service_t));
+ ct->cs_cluster_size = get_suggested_cluster_size();
+ ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
- ct->ct_keys = get_key_struct();
- ct->ct_cwc = cwc;
- ct->ct_transport = t;
- ct->ct_okchannel = -1;
+ ct->cs_keys = get_key_struct();
+ ct->cs_cwc = cwc;
+ ct->cs_service = t;
+ ct->cs_okchannel = -1;
- td = &ct->ct_head;
- td->td_stop = cwc_transport_destroy;
+ td = &ct->cs_head;
+ td->td_stop = cwc_service_destroy;
td->td_table = cwc_table_input;
td->td_descramble = cwc_descramble;
- LIST_INSERT_HEAD(&t->tht_descramblers, td, td_transport_link);
+ LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
- LIST_INSERT_HEAD(&cwc->cwc_transports, ct, ct_link);
+ LIST_INSERT_HEAD(&cwc->cwc_services, ct, cs_link);
tvhlog(LOG_DEBUG, "cwc", "%s using CWC %s:%d",
- transport_nicename(t), cwc->cwc_hostname, cwc->cwc_port);
+ service_nicename(t), cwc->cwc_hostname, cwc->cwc_port);
}
}
void cwc_init(void);
-void cwc_transport_start(th_transport_t *t);
+void cwc_service_start(struct service *t);
void cwc_emm(uint8_t *data, int len);
char *tdmi_identifier;
char *tdmi_network; /* Name of network, from NIT table */
- struct th_transport_list tdmi_transports; /* via tht_mux_link */
+ struct service_list tdmi_transports; /* via s_mux_link */
TAILQ_ENTRY(th_dvb_mux_instance) tdmi_scan_link;
gtimer_t tda_mux_scanner_timer;
pthread_mutex_t tda_delivery_mutex;
- struct th_transport_list tda_transports; /* Currently bound transports */
+ struct service_list tda_transports; /* Currently bound transports */
gtimer_t tda_fe_monitor_timer;
int tda_fe_monitor_hold;
*/
void dvb_transport_load(th_dvb_mux_instance_t *tdmi);
-th_transport_t *dvb_transport_find(th_dvb_mux_instance_t *tdmi,
+struct service *dvb_transport_find(th_dvb_mux_instance_t *tdmi,
uint16_t sid, int pmt_pid,
const char *identifier);
-void dvb_transport_notify(th_transport_t *t);
+void dvb_transport_notify(struct service *t);
void dvb_transport_notify_by_adapter(th_dvb_adapter_t *tda);
-htsmsg_t *dvb_transport_build_msg(th_transport_t *t);
+htsmsg_t *dvb_transport_build_msg(struct service *t);
-int dvb_transport_get_signal_status(th_transport_t *t,
+int dvb_transport_get_signal_status(struct service *t,
signal_status_t *status);
/**
#include "settings.h"
#include "tvheadend.h"
-#include "transports.h"
#include "dvb.h"
#include "dvb_support.h"
#include "tsdemux.h"
#include "notify.h"
+#include "service.h"
struct th_dvb_adapter_queue dvb_adapters;
struct th_dvb_mux_instance_tree dvb_muxes;
if(LIST_FIRST(&tda->tda_muxes) == NULL)
return; // No muxes configured
- if(transport_compute_weight(&tda->tda_transports) > 0)
+ if(service_compute_weight(&tda->tda_transports) > 0)
return; /* someone is here */
/* Check if we have muxes pending for quickscan, if so, choose them */
void
dvb_adapter_clean(th_dvb_adapter_t *tda)
{
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
while((t = LIST_FIRST(&tda->tda_transports)) != NULL)
/* Flush all subscribers */
- transport_remove_subscriber(t, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN);
+ service_remove_subscriber(t, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN);
}
th_dvb_adapter_t *tda = aux;
int fd, i, r;
uint8_t tsb[188 * 10];
- th_transport_t *t;
+ service_t *t;
fd = tvh_open(tda->tda_dvr_path, O_RDONLY, 0);
if(fd == -1) {
pthread_mutex_lock(&tda->tda_delivery_mutex);
for(i = 0; i < r; i += 188) {
- LIST_FOREACH(t, &tda->tda_transports, tht_active_link)
- if(t->tht_dvb_mux_instance == tda->tda_mux_current)
+ LIST_FOREACH(t, &tda->tda_transports, s_active_link)
+ if(t->s_dvb_mux_instance == tda->tda_mux_current)
ts_recv_packet1(t, tsb + i, NULL);
}
char buf[100];
htsmsg_t *m = htsmsg_create_map();
th_dvb_mux_instance_t *tdmi;
- th_transport_t *t;
+ service_t *t;
int nummux = 0;
int numsvc = 0;
int fdiv;
// XXX: bad bad bad slow slow slow
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
nummux++;
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
numsvc++;
}
}
#include "dvb_support.h"
#include "diseqc.h"
#include "notify.h"
-#include "transports.h"
#include "dvr/dvr.h"
/**
#include "tvheadend.h"
#include "dvb.h"
#include "channels.h"
-#include "transports.h"
#include "teletext.h"
#include "psi.h"
#include "dvb_support.h"
#include "notify.h"
+#include "subscriptions.h"
struct th_dvb_mux_instance_tree dvb_muxes;
dvb_mux_destroy(th_dvb_mux_instance_t *tdmi)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
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);
+ t->s_dvb_mux_instance->tdmi_identifier,
+ t->s_identifier);
+ service_destroy(t);
}
dvb_transport_notify_by_adapter(tda);
dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
{
th_dvb_mux_instance_t *tdmi_dst;
- th_transport_t *t_src, *t_dst;
+ service_t *t_src, *t_dst;
th_stream_t *st_src, *st_dst;
caid_t *caid_src, *caid_dst;
if(tdmi_dst == NULL)
return -1; // Already exist
- LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, tht_group_link) {
+ LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, s_group_link) {
t_dst = dvb_transport_find(tdmi_dst,
- t_src->tht_dvb_service_id,
- t_src->tht_pmt_pid, NULL);
+ t_src->s_dvb_service_id,
+ t_src->s_pmt_pid, NULL);
- t_dst->tht_pcr_pid = t_src->tht_pcr_pid;
- t_dst->tht_enabled = t_src->tht_enabled;
- t_dst->tht_servicetype = t_src->tht_servicetype;
- t_dst->tht_scrambled = t_src->tht_scrambled;
+ t_dst->s_pcr_pid = t_src->s_pcr_pid;
+ t_dst->s_enabled = t_src->s_enabled;
+ t_dst->s_servicetype = t_src->s_servicetype;
+ t_dst->s_scrambled = t_src->s_scrambled;
- if(t_src->tht_provider != NULL)
- t_dst->tht_provider = strdup(t_src->tht_provider);
+ if(t_src->s_provider != NULL)
+ t_dst->s_provider = strdup(t_src->s_provider);
- if(t_src->tht_svcname != NULL)
- t_dst->tht_svcname = strdup(t_src->tht_svcname);
+ if(t_src->s_svcname != NULL)
+ t_dst->s_svcname = strdup(t_src->s_svcname);
- if(t_src->tht_ch != NULL)
- transport_map_channel(t_dst, t_src->tht_ch, 0);
+ if(t_src->s_ch != NULL)
+ service_map_channel(t_dst, t_src->s_ch, 0);
- pthread_mutex_lock(&t_src->tht_stream_mutex);
- pthread_mutex_lock(&t_dst->tht_stream_mutex);
+ pthread_mutex_lock(&t_src->s_stream_mutex);
+ pthread_mutex_lock(&t_dst->s_stream_mutex);
- TAILQ_FOREACH(st_src, &t_src->tht_components, st_link) {
+ TAILQ_FOREACH(st_src, &t_src->s_components, st_link) {
- st_dst = transport_stream_create(t_dst,
- st_src->st_pid,
- st_src->st_type);
+ st_dst = service_stream_create(t_dst,
+ st_src->st_pid,
+ st_src->st_type);
memcpy(st_dst->st_lang, st_src->st_lang, 4);
st_dst->st_frame_duration = st_src->st_frame_duration;
}
}
- pthread_mutex_unlock(&t_dst->tht_stream_mutex);
- pthread_mutex_unlock(&t_src->tht_stream_mutex);
+ pthread_mutex_unlock(&t_dst->s_stream_mutex);
+ pthread_mutex_unlock(&t_src->s_stream_mutex);
- t_dst->tht_config_save(t_dst); // Save config
+ t_dst->s_config_save(t_dst); // Save config
}
dvb_mux_save(tdmi_dst);
#include "dvb.h"
#include "dvb_support.h"
#include "epg.h"
-#include "transports.h"
#include "channels.h"
#include "psi.h"
#include "notify.h"
dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque)
{
- th_transport_t *t;
+ service_t *t;
channel_t *ch;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
return -1;
t = dvb_transport_find(tdmi, serviceid, 0, NULL);
- if(t == NULL || !t->tht_enabled || (ch = t->tht_ch) == NULL)
+ if(t == NULL || !t->s_enabled || (ch = t->s_ch) == NULL)
return 0;
while(len >= 12) {
dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque)
{
- th_transport_t *t;
+ service_t *t;
int version;
uint8_t section_number;
uint8_t last_section_number;
if(t == NULL)
break;
- if(t->tht_servicetype != stype ||
- t->tht_scrambled != free_ca_mode ||
- strcmp(t->tht_provider ?: "", provider) ||
- strcmp(t->tht_svcname ?: "", chname)) {
+ if(t->s_servicetype != stype ||
+ t->s_scrambled != free_ca_mode ||
+ strcmp(t->s_provider ?: "", provider) ||
+ strcmp(t->s_svcname ?: "", chname)) {
- t->tht_servicetype = stype;
- t->tht_scrambled = free_ca_mode;
+ t->s_servicetype = stype;
+ t->s_scrambled = free_ca_mode;
- free(t->tht_provider);
- t->tht_provider = strdup(provider);
+ free(t->s_provider);
+ t->s_provider = strdup(provider);
- free(t->tht_svcname);
- t->tht_svcname = strdup(chname);
+ free(t->s_svcname);
+ t->s_svcname = strdup(chname);
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
- t->tht_config_save(t);
- transport_refresh_channel(t);
+ t->s_config_save(t);
+ service_refresh_channel(t);
}
}
break;
{
uint16_t sid, chan;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
- th_transport_t *t;
+ service_t *t;
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
if(tdmi->tdmi_transport_stream_id == tsid)
t = dvb_transport_find(tdmi, sid, 0, NULL);
if(t != NULL) {
- if(t->tht_channel_number != chan) {
- t->tht_channel_number = chan;
- t->tht_config_save(t);
- transport_refresh_channel(t);
+ if(t->s_channel_number != chan) {
+ t->s_channel_number = chan;
+ t->s_config_save(t);
+ service_refresh_channel(t);
}
}
}
uint8_t tableid, void *opaque)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
- th_transport_t *t;
+ service_t *t;
int numch;
char chname[256];
uint8_t atsc_stype;
dptr += dptr[1] + 2;
}
- if(t->tht_servicetype != stype ||
- strcmp(t->tht_svcname ?: "", chname)) {
+ if(t->s_servicetype != stype ||
+ strcmp(t->s_svcname ?: "", chname)) {
- t->tht_servicetype = stype;
- tvh_str_set(&t->tht_svcname, chname);
+ t->s_servicetype = stype;
+ tvh_str_set(&t->s_svcname, chname);
- t->tht_config_save(t);
+ t->s_config_save(t);
}
}
return 0;
dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque)
{
- th_transport_t *t;
+ service_t *t;
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
- pthread_mutex_lock(&t->tht_stream_mutex);
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
+ pthread_mutex_lock(&t->s_stream_mutex);
psi_parse_pmt(t, ptr, len, 1, 1);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
return 0;
}
#include "tvheadend.h"
#include "dvb.h"
#include "channels.h"
-#include "transports.h"
#include "subscriptions.h"
#include "psi.h"
#include "dvb_support.h"
*
*/
static void
-dvb_transport_open_demuxers(th_dvb_adapter_t *tda, th_transport_t *t)
+dvb_transport_open_demuxers(th_dvb_adapter_t *tda, service_t *t)
{
struct dmx_pes_filter_params dmx_param;
int fd;
th_stream_t *st;
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
if(st->st_pid >= 0x2000)
continue;
st->st_demuxer_fd = -1;
tvhlog(LOG_ERR, "dvb",
"\"%s\" unable to open demuxer \"%s\" for pid %d -- %s",
- t->tht_identifier, tda->tda_demux_path,
+ t->s_identifier, tda->tda_demux_path,
st->st_pid, strerror(errno));
continue;
}
if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) {
tvhlog(LOG_ERR, "dvb",
"\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s",
- t->tht_identifier, tda->tda_demux_path,
+ t->s_identifier, tda->tda_demux_path,
st->st_pid, strerror(errno));
close(fd);
fd = -1;
* transports that is subscribing to the adapter
*/
static int
-dvb_transport_start(th_transport_t *t, unsigned int weight, int force_start)
+dvb_transport_start(service_t *t, unsigned int weight, int force_start)
{
int w, r;
- th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter;
+ th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
th_dvb_mux_instance_t *tdmi = tda->tda_mux_current;
lock_assert(&global_lock);
if(tda->tda_rootpath == NULL)
return SM_CODE_NO_HW_ATTACHED;
- if(t->tht_dvb_mux_instance && !t->tht_dvb_mux_instance->tdmi_enabled)
+ if(t->s_dvb_mux_instance && !t->s_dvb_mux_instance->tdmi_enabled)
return SM_CODE_MUX_NOT_ENABLED; /* Mux is disabled */
/* Check if adapter is idle, or already tuned */
if(tdmi != NULL &&
- (tdmi != t->tht_dvb_mux_instance ||
+ (tdmi != t->s_dvb_mux_instance ||
tda->tda_hostconnection == HOSTCONNECTION_USB12)) {
- w = transport_compute_weight(&tda->tda_transports);
+ w = service_compute_weight(&tda->tda_transports);
if(w && w >= weight && !force_start)
/* We are outranked by weight, cant use it */
return SM_CODE_NOT_FREE;
pthread_mutex_lock(&tda->tda_delivery_mutex);
- r = dvb_fe_tune(t->tht_dvb_mux_instance, "Transport start");
+ r = dvb_fe_tune(t->s_dvb_mux_instance, "Transport start");
if(!r)
- LIST_INSERT_HEAD(&tda->tda_transports, t, tht_active_link);
+ LIST_INSERT_HEAD(&tda->tda_transports, t, s_active_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
*
*/
static void
-dvb_transport_stop(th_transport_t *t)
+dvb_transport_stop(service_t *t)
{
- th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter;
+ th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
th_stream_t *st;
lock_assert(&global_lock);
pthread_mutex_lock(&tda->tda_delivery_mutex);
- LIST_REMOVE(t, tht_active_link);
+ LIST_REMOVE(t, s_active_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
if(st->st_demuxer_fd != -1) {
close(st->st_demuxer_fd);
st->st_demuxer_fd = -1;
}
}
- t->tht_status = TRANSPORT_IDLE;
+ t->s_status = SERVICE_IDLE;
}
*
*/
static void
-dvb_transport_refresh(th_transport_t *t)
+dvb_transport_refresh(service_t *t)
{
- th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter;
+ th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
lock_assert(&global_lock);
dvb_transport_open_demuxers(tda, t);
uint32_t sid, pmt;
const char *s;
unsigned int u32;
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
t = dvb_transport_find(tdmi, sid, pmt, f->hmf_name);
- htsmsg_get_u32(c, "stype", &t->tht_servicetype);
+ htsmsg_get_u32(c, "stype", &t->s_servicetype);
if(htsmsg_get_u32(c, "scrambled", &u32))
u32 = 0;
- t->tht_scrambled = u32;
+ t->s_scrambled = u32;
if(htsmsg_get_u32(c, "channel", &u32))
u32 = 0;
- t->tht_channel_number = u32;
+ t->s_channel_number = u32;
s = htsmsg_get_str(c, "provider");
- t->tht_provider = s ? strdup(s) : NULL;
+ t->s_provider = s ? strdup(s) : NULL;
s = htsmsg_get_str(c, "servicename");
- t->tht_svcname = s ? strdup(s) : NULL;
+ t->s_svcname = s ? strdup(s) : NULL;
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- psi_load_transport_settings(c, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ psi_load_service_settings(c, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
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), 0);
+ service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
}
htsmsg_destroy(l);
}
*
*/
static void
-dvb_transport_save(th_transport_t *t)
+dvb_transport_save(service_t *t)
{
htsmsg_t *m = htsmsg_create_map();
lock_assert(&global_lock);
- htsmsg_add_u32(m, "service_id", t->tht_dvb_service_id);
- htsmsg_add_u32(m, "pmt", t->tht_pmt_pid);
- htsmsg_add_u32(m, "stype", t->tht_servicetype);
- htsmsg_add_u32(m, "scrambled", t->tht_scrambled);
- htsmsg_add_u32(m, "channel", t->tht_channel_number);
+ htsmsg_add_u32(m, "service_id", t->s_dvb_service_id);
+ htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
+ htsmsg_add_u32(m, "stype", t->s_servicetype);
+ htsmsg_add_u32(m, "scrambled", t->s_scrambled);
+ htsmsg_add_u32(m, "channel", t->s_channel_number);
- if(t->tht_provider != NULL)
- htsmsg_add_str(m, "provider", t->tht_provider);
+ if(t->s_provider != NULL)
+ htsmsg_add_str(m, "provider", t->s_provider);
- if(t->tht_svcname != NULL)
- htsmsg_add_str(m, "servicename", t->tht_svcname);
+ if(t->s_svcname != NULL)
+ htsmsg_add_str(m, "servicename", t->s_svcname);
- if(t->tht_ch != NULL) {
- htsmsg_add_str(m, "channelname", t->tht_ch->ch_name);
+ if(t->s_ch != NULL) {
+ htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
htsmsg_add_u32(m, "mapped", 1);
}
- pthread_mutex_lock(&t->tht_stream_mutex);
- psi_save_transport_settings(m, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ psi_save_service_settings(m, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
hts_settings_save(m, "dvbtransports/%s/%s",
- t->tht_dvb_mux_instance->tdmi_identifier,
- t->tht_identifier);
+ t->s_dvb_mux_instance->tdmi_identifier,
+ t->s_identifier);
htsmsg_destroy(m);
dvb_transport_notify(t);
* return that value
*/
static int
-dvb_transport_quality(th_transport_t *t)
+dvb_transport_quality(service_t *t)
{
- th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
+ th_dvb_mux_instance_t *tdmi = t->s_dvb_mux_instance;
lock_assert(&global_lock);
* Generate a descriptive name for the source
*/
static void
-dvb_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
+dvb_transport_setsourceinfo(service_t *t, struct source_info *si)
{
- th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
+ th_dvb_mux_instance_t *tdmi = t->s_dvb_mux_instance;
char buf[100];
memset(si, 0, sizeof(struct source_info));
dvb_mux_nicename(buf, sizeof(buf), tdmi);
si->si_mux = strdup(buf);
- if(t->tht_provider != NULL)
- si->si_provider = strdup(t->tht_provider);
+ if(t->s_provider != NULL)
+ si->si_provider = strdup(t->s_provider);
- if(t->tht_svcname != NULL)
- si->si_service = strdup(t->tht_svcname);
+ if(t->s_svcname != NULL)
+ si->si_service = strdup(t->s_svcname);
}
*
*/
static int
-dvb_grace_period(th_transport_t *t)
+dvb_grace_period(service_t *t)
{
return 10;
}
*
* If it cannot be found we create it if 'pmt_pid' is also set
*/
-th_transport_t *
+service_t *
dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid,
const char *identifier)
{
- th_transport_t *t;
+ service_t *t;
char tmp[200];
char buf[200];
lock_assert(&global_lock);
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
- if(t->tht_dvb_service_id == sid)
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
+ if(t->s_dvb_service_id == sid)
return t;
}
dvb_mux_nicename(buf, sizeof(buf), tdmi);
tvhlog(LOG_DEBUG, "dvb", "Add service \"%s\" on \"%s\"", identifier, buf);
- t = transport_create(identifier, TRANSPORT_DVB, THT_MPEG_TS);
+ t = service_create(identifier, SERVICE_TYPE_DVB, S_MPEG_TS);
- t->tht_dvb_service_id = sid;
- t->tht_pmt_pid = pmt_pid;
+ t->s_dvb_service_id = sid;
+ t->s_pmt_pid = pmt_pid;
- t->tht_start_feed = dvb_transport_start;
- t->tht_refresh_feed = dvb_transport_refresh;
- t->tht_stop_feed = dvb_transport_stop;
- t->tht_config_save = dvb_transport_save;
- t->tht_setsourceinfo = dvb_transport_setsourceinfo;
- t->tht_quality_index = dvb_transport_quality;
- t->tht_grace_period = dvb_grace_period;
+ t->s_start_feed = dvb_transport_start;
+ t->s_refresh_feed = dvb_transport_refresh;
+ t->s_stop_feed = dvb_transport_stop;
+ t->s_config_save = dvb_transport_save;
+ t->s_setsourceinfo = dvb_transport_setsourceinfo;
+ t->s_quality_index = dvb_transport_quality;
+ t->s_grace_period = dvb_grace_period;
- t->tht_dvb_mux_instance = tdmi;
- LIST_INSERT_HEAD(&tdmi->tdmi_transports, t, tht_group_link);
+ t->s_dvb_mux_instance = tdmi;
+ LIST_INSERT_HEAD(&tdmi->tdmi_transports, t, s_group_link);
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
dvb_adapter_notify(tdmi->tdmi_adapter);
return t;
*
*/
htsmsg_t *
-dvb_transport_build_msg(th_transport_t *t)
+dvb_transport_build_msg(service_t *t)
{
- th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
+ th_dvb_mux_instance_t *tdmi = t->s_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, "channel", t->tht_channel_number);
+ htsmsg_add_str(m, "id", t->s_identifier);
+ htsmsg_add_u32(m, "enabled", t->s_enabled);
+ htsmsg_add_u32(m, "channel", t->s_channel_number);
- 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_u32(m, "sid", t->s_dvb_service_id);
+ htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
+ htsmsg_add_u32(m, "pcr", t->s_pcr_pid);
- htsmsg_add_str(m, "type", transport_servicetype_txt(t));
+ htsmsg_add_str(m, "type", service_servicetype_txt(t));
- htsmsg_add_str(m, "svcname", t->tht_svcname ?: "");
- htsmsg_add_str(m, "provider", t->tht_provider ?: "");
+ htsmsg_add_str(m, "svcname", t->s_svcname ?: "");
+ htsmsg_add_str(m, "provider", t->s_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);
+ if(t->s_ch != NULL)
+ htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
return m;
}
*
*/
void
-dvb_transport_notify(th_transport_t *t)
+dvb_transport_notify(service_t *t)
{
- th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
+ th_dvb_mux_instance_t *tdmi = t->s_dvb_mux_instance;
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "adapterId", tdmi->tdmi_adapter->tda_identifier);
* Get the signal status from a DVB transport
*/
int
-dvb_transport_get_signal_status(th_transport_t *t, signal_status_t *status)
+dvb_transport_get_signal_status(service_t *t, signal_status_t *status)
{
- th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance;
+ th_dvb_mux_instance_t *tdmi = t->s_dvb_mux_instance;
status->status_text = dvb_mux_status(tdmi);
status->snr = tdmi->tdmi_snr;
#include "streaming.h"
#include "dvr.h"
#include "spawn.h"
-#include "transports.h"
-
+#include "service.h"
#include "plumbing/tsfix.h"
#include "plumbing/globalheaders.h"
dvr_thread_epilog(de);
break;
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
if(sm->sm_code & TSS_PACKETS) {
} else if(sm->sm_code & (TSS_GRACEPERIOD | TSS_ERRORS)) {
#include "access.h"
#include "htsp.h"
#include "streaming.h"
-#include "transports.h"
#include "psi.h"
#include "htsmsg_binary.h"
{
channel_tag_mapping_t *ctm;
channel_tag_t *ct;
- th_transport_t *t;
+ service_t *t;
htsmsg_t *out = htsmsg_create_map();
htsmsg_t *tags = htsmsg_create_list();
htsmsg_add_u32(tags, NULL, ct->ct_identifier);
}
- LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) {
+ LIST_FOREACH(t, &ch->ch_services, s_ch_link) {
htsmsg_t *svcmsg = htsmsg_create_map();
uint16_t caid;
- htsmsg_add_str(svcmsg, "name", transport_nicename(t));
- htsmsg_add_str(svcmsg, "type", transport_servicetype_txt(t));
- if((caid = transport_get_encryption(t)) != 0) {
+ htsmsg_add_str(svcmsg, "name", service_nicename(t));
+ htsmsg_add_str(svcmsg, "type", service_servicetype_txt(t));
+ if((caid = service_get_encryption(t)) != 0) {
htsmsg_add_u32(svcmsg, "caid", caid);
htsmsg_add_str(svcmsg, "caname", psi_caid2name(caid));
}
};
/**
- * Build a htsmsg from a th_pkt and enqueue it on our HTSP transport
+ * Build a htsmsg from a th_pkt and enqueue it on our HTSP service
*/
static void
htsp_stream_deliver(htsp_subscription_t *hs, th_pkt_t *pkt)
htsp_send_message(hs->hs_htsp, m, &hs->hs_htsp->htsp_hmq_qstatus);
- if(!transport_get_signal_status(hs->hs_s->ths_transport, &status)) {
+ if(!service_get_signal_status(hs->hs_s->ths_service, &status)) {
m = htsmsg_create_map();
htsmsg_add_str(m, "method", "signalStatus");
*
*/
static void
-htsp_subscription_transport_status(htsp_subscription_t *hs, int status)
+htsp_subscription_service_status(htsp_subscription_t *hs, int status)
{
if(status & TSS_PACKETS) {
htsp_subscription_status(hs, NULL);
} else if(status & (TSS_GRACEPERIOD | TSS_ERRORS)) {
- htsp_subscription_status(hs, transport_tss2text(status));
+ htsp_subscription_status(hs, service_tss2text(status));
}
}
htsp_subscription_stop(hs, streaming_code2txt(sm->sm_code));
break;
- case SMT_TRANSPORT_STATUS:
- htsp_subscription_transport_status(hs, sm->sm_code);
+ case SMT_SERVICE_STATUS:
+ htsp_subscription_service_status(hs, sm->sm_code);
break;
case SMT_NOSTART:
#include "tvheadend.h"
#include "htsmsg.h"
#include "channels.h"
-#include "transports.h"
#include "iptv_input.h"
#include "tsdemux.h"
#include "psi.h"
static int iptv_epollfd;
static pthread_mutex_t iptv_recvmutex;
-struct th_transport_list iptv_all_transports; /* All IPTV transports */
-static struct th_transport_list iptv_active_transports; /* Currently enabled */
+struct service_list iptv_all_services; /* All IPTV services */
+static struct service_list iptv_active_services; /* Currently enabled */
/**
* PAT parser. We only parse a single program. CRC has already been verified
static void
iptv_got_pat(const uint8_t *ptr, size_t len, void *aux)
{
- th_transport_t *t = aux;
+ service_t *t = aux;
uint16_t prognum, pmt;
len -= 8;
prognum = ptr[0] << 8 | ptr[1];
pmt = (ptr[2] & 0x1f) << 8 | ptr[3];
- t->tht_pmt_pid = pmt;
+ t->s_pmt_pid = pmt;
}
static void
iptv_got_pmt(const uint8_t *ptr, size_t len, void *aux)
{
- th_transport_t *t = aux;
+ service_t *t = aux;
if(len < 3 || ptr[0] != 2)
return;
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
psi_parse_pmt(t, ptr + 3, len - 3, 0, 1);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
/**
- * Handle a single TS packet for the given IPTV transport
+ * Handle a single TS packet for the given IPTV service
*/
static void
-iptv_ts_input(th_transport_t *t, const uint8_t *tsb)
+iptv_ts_input(service_t *t, const uint8_t *tsb)
{
uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2];
if(pid == 0) {
- if(t->tht_pat_section == NULL)
- t->tht_pat_section = calloc(1, sizeof(psi_section_t));
- psi_section_reassemble(t->tht_pat_section, tsb, 1, iptv_got_pat, t);
+ if(t->s_pat_section == NULL)
+ t->s_pat_section = calloc(1, sizeof(psi_section_t));
+ psi_section_reassemble(t->s_pat_section, tsb, 1, iptv_got_pat, t);
- } else if(pid == t->tht_pmt_pid) {
+ } else if(pid == t->s_pmt_pid) {
- if(t->tht_pmt_section == NULL)
- t->tht_pmt_section = calloc(1, sizeof(psi_section_t));
- psi_section_reassemble(t->tht_pmt_section, tsb, 1, iptv_got_pmt, t);
+ if(t->s_pmt_section == NULL)
+ t->s_pmt_section = calloc(1, sizeof(psi_section_t));
+ psi_section_reassemble(t->s_pmt_section, tsb, 1, iptv_got_pmt, t);
} else {
ts_recv_packet1(t, tsb, NULL);
int nfds, fd, r, j;
uint8_t tsb[65536], *buf;
struct epoll_event ev;
- th_transport_t *t;
+ service_t *t;
while(1) {
nfds = epoll_wait(iptv_epollfd, &ev, 1, -1);
pthread_mutex_lock(&iptv_recvmutex);
- LIST_FOREACH(t, &iptv_active_transports, tht_active_link) {
- if(t->tht_iptv_fd != fd)
+ LIST_FOREACH(t, &iptv_active_services, s_active_link) {
+ if(t->s_iptv_fd != fd)
continue;
for(j = 0; j < r; j += 188)
*
*/
static int
-iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
+iptv_service_start(service_t *t, unsigned int weight, int force_start)
{
pthread_t tid;
int fd;
struct ifreq ifr;
struct epoll_event ev;
- assert(t->tht_iptv_fd == -1);
+ assert(t->s_iptv_fd == -1);
if(iptv_thread_running == 0) {
iptv_thread_running = 1;
}
/* Now, open the real socket for UDP */
- if(t->tht_iptv_group.s_addr!=0) {
+ if(t->s_iptv_group.s_addr!=0) {
fd = tvh_socket(AF_INET, SOCK_DGRAM, 0);
}
fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0);
}
if(fd == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->tht_identifier);
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_identifier);
return -1;
}
/* First, resolve interface name */
memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->tht_iptv_iface);
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
if(ioctl(fd, SIOCGIFINDEX, &ifr)) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
- t->tht_identifier, t->tht_iptv_iface);
+ t->s_identifier, t->s_iptv_iface);
close(fd);
return -1;
}
/* Bind to IPv4 multicast group */
- if(t->tht_iptv_group.s_addr!=0) {
+ if(t->s_iptv_group.s_addr!=0) {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
- sin.sin_port = htons(t->tht_iptv_port);
- sin.sin_addr.s_addr = t->tht_iptv_group.s_addr;
+ sin.sin_port = htons(t->s_iptv_port);
+ sin.sin_addr.s_addr = t->s_iptv_group.s_addr;
if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
- t->tht_identifier, inet_ntoa(sin.sin_addr), t->tht_iptv_port,
+ t->s_identifier, inet_ntoa(sin.sin_addr), t->s_iptv_port,
strerror(errno));
close(fd);
return -1;
}
/* Join IPv4 group */
memset(&m, 0, sizeof(m));
- m.imr_multiaddr.s_addr = t->tht_iptv_group.s_addr;
+ m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
m.imr_address.s_addr = 0;
m.imr_ifindex = ifr.ifr_ifindex;
if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m,
sizeof(struct ip_mreqn)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
- t->tht_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
+ t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
close(fd);
return -1;
}
/* Bind to IPv6 multicast group */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(t->tht_iptv_port);
- sin6.sin6_addr = t->tht_iptv_group6;
+ sin6.sin6_port = htons(t->s_iptv_port);
+ sin6.sin6_addr = t->s_iptv_group6;
if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1) {
inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
- t->tht_identifier, straddr, t->tht_iptv_port,
+ t->s_identifier, straddr, t->s_iptv_port,
strerror(errno));
close(fd);
return -1;
}
/* Join IPv6 group */
memset(&m6, 0, sizeof(m6));
- m6.ipv6mr_multiaddr = t->tht_iptv_group6;
+ m6.ipv6mr_multiaddr = t->s_iptv_group6;
m6.ipv6mr_interface = ifr.ifr_ifindex;
if(setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m6,
inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
- t->tht_identifier, straddr, strerror(errno));
+ t->s_identifier, straddr, strerror(errno));
close(fd);
return -1;
}
ev.data.fd = fd;
if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s",
- t->tht_identifier, strerror(errno));
+ t->s_identifier, strerror(errno));
close(fd);
return -1;
}
- t->tht_iptv_fd = fd;
+ t->s_iptv_fd = fd;
pthread_mutex_lock(&iptv_recvmutex);
- LIST_INSERT_HEAD(&iptv_active_transports, t, tht_active_link);
+ LIST_INSERT_HEAD(&iptv_active_services, t, s_active_link);
pthread_mutex_unlock(&iptv_recvmutex);
return 0;
}
*
*/
static void
-iptv_transport_refresh(th_transport_t *t)
+iptv_service_refresh(service_t *t)
{
}
*
*/
static void
-iptv_transport_stop(th_transport_t *t)
+iptv_service_stop(service_t *t)
{
struct ifreq ifr;
pthread_mutex_lock(&iptv_recvmutex);
- LIST_REMOVE(t, tht_active_link);
+ LIST_REMOVE(t, s_active_link);
pthread_mutex_unlock(&iptv_recvmutex);
- assert(t->tht_iptv_fd >= 0);
+ assert(t->s_iptv_fd >= 0);
/* First, resolve interface name */
memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->tht_iptv_iface);
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
ifr.ifr_name[IFNAMSIZ - 1] = 0;
- if(ioctl(t->tht_iptv_fd, SIOCGIFINDEX, &ifr)) {
+ if(ioctl(t->s_iptv_fd, SIOCGIFINDEX, &ifr)) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
- t->tht_identifier, t->tht_iptv_iface);
+ t->s_identifier, t->s_iptv_iface);
}
- if(t->tht_iptv_group.s_addr != 0) {
+ if(t->s_iptv_group.s_addr != 0) {
struct ip_mreqn m;
memset(&m, 0, sizeof(m));
/* Leave multicast group */
- m.imr_multiaddr.s_addr = t->tht_iptv_group.s_addr;
+ m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
m.imr_address.s_addr = 0;
m.imr_ifindex = ifr.ifr_ifindex;
- if(setsockopt(t->tht_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m,
+ if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m,
sizeof(struct ip_mreqn)) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
- t->tht_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
+ t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
}
} else {
char straddr[INET6_ADDRSTRLEN];
struct ipv6_mreq m6;
memset(&m6, 0, sizeof(m6));
- m6.ipv6mr_multiaddr = t->tht_iptv_group6;
+ m6.ipv6mr_multiaddr = t->s_iptv_group6;
m6.ipv6mr_interface = ifr.ifr_ifindex;
- if(setsockopt(t->tht_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m6,
+ if(setsockopt(t->s_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m6,
sizeof(struct ipv6_mreq)) == -1) {
inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
- t->tht_identifier, straddr, strerror(errno));
+ t->s_identifier, straddr, strerror(errno));
}
}
- close(t->tht_iptv_fd); // Automatically removes fd from epoll set
+ close(t->s_iptv_fd); // Automatically removes fd from epoll set
- t->tht_iptv_fd = -1;
+ t->s_iptv_fd = -1;
}
*
*/
static void
-iptv_transport_save(th_transport_t *t)
+iptv_service_save(service_t *t)
{
htsmsg_t *m = htsmsg_create_map();
char abuf[INET_ADDRSTRLEN];
lock_assert(&global_lock);
- htsmsg_add_u32(m, "pmt", t->tht_pmt_pid);
+ htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
- if(t->tht_iptv_port)
- htsmsg_add_u32(m, "port", t->tht_iptv_port);
+ if(t->s_iptv_port)
+ htsmsg_add_u32(m, "port", t->s_iptv_port);
- if(t->tht_iptv_iface)
- htsmsg_add_str(m, "interface", t->tht_iptv_iface);
+ if(t->s_iptv_iface)
+ htsmsg_add_str(m, "interface", t->s_iptv_iface);
- if(t->tht_iptv_group.s_addr!= 0) {
- inet_ntop(AF_INET, &t->tht_iptv_group, abuf, sizeof(abuf));
+ if(t->s_iptv_group.s_addr!= 0) {
+ inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
htsmsg_add_str(m, "group", abuf);
}
- if(IN6_IS_ADDR_MULTICAST(t->tht_iptv_group6.s6_addr) ) {
- inet_ntop(AF_INET6, &t->tht_iptv_group6, abuf6, sizeof(abuf6));
+ if(IN6_IS_ADDR_MULTICAST(t->s_iptv_group6.s6_addr) ) {
+ inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6));
htsmsg_add_str(m, "group", abuf6);
}
- if(t->tht_ch != NULL) {
- htsmsg_add_str(m, "channelname", t->tht_ch->ch_name);
+ if(t->s_ch != NULL) {
+ htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
htsmsg_add_u32(m, "mapped", 1);
}
- pthread_mutex_lock(&t->tht_stream_mutex);
- psi_save_transport_settings(m, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ psi_save_service_settings(m, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
- hts_settings_save(m, "iptvtransports/%s",
- t->tht_identifier);
+ hts_settings_save(m, "iptvservices/%s",
+ t->s_identifier);
htsmsg_destroy(m);
}
*
*/
static int
-iptv_transport_quality(th_transport_t *t)
+iptv_service_quality(service_t *t)
{
- if(t->tht_iptv_iface == NULL ||
- (t->tht_iptv_group.s_addr == 0 && t->tht_iptv_group6.s6_addr == 0) ||
- t->tht_iptv_port == 0)
+ if(t->s_iptv_iface == NULL ||
+ (t->s_iptv_group.s_addr == 0 && t->s_iptv_group6.s6_addr == 0) ||
+ t->s_iptv_port == 0)
return 0;
return 100;
* Generate a descriptive name for the source
*/
static void
-iptv_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
+iptv_service_setsourceinfo(service_t *t, struct source_info *si)
{
char straddr[INET6_ADDRSTRLEN];
memset(si, 0, sizeof(struct source_info));
- si->si_adapter = t->tht_iptv_iface ? strdup(t->tht_iptv_iface) : NULL;
- if(t->tht_iptv_group.s_addr != 0) {
- si->si_mux = strdup(inet_ntoa(t->tht_iptv_group));
+ si->si_adapter = t->s_iptv_iface ? strdup(t->s_iptv_iface) : NULL;
+ if(t->s_iptv_group.s_addr != 0) {
+ si->si_mux = strdup(inet_ntoa(t->s_iptv_group));
}
else {
- inet_ntop(AF_INET6, &t->tht_iptv_group6, straddr, sizeof(straddr));
+ inet_ntop(AF_INET6, &t->s_iptv_group6, straddr, sizeof(straddr));
si->si_mux = strdup(straddr);
}
}
*
*/
static int
-iptv_grace_period(th_transport_t *t)
+iptv_grace_period(service_t *t)
{
return 3;
}
*
*/
static void
-iptv_transport_dtor(th_transport_t *t)
+iptv_service_dtor(service_t *t)
{
- hts_settings_remove("iptvtransports/%s", t->tht_identifier);
+ hts_settings_remove("iptvservices/%s", t->s_identifier);
}
/**
*
*/
-th_transport_t *
-iptv_transport_find(const char *id, int create)
+service_t *
+iptv_service_find(const char *id, int create)
{
static int tally;
- th_transport_t *t;
+ service_t *t;
char buf[20];
if(id != NULL) {
if(strncmp(id, "iptv_", 5))
return NULL;
- LIST_FOREACH(t, &iptv_all_transports, tht_group_link)
- if(!strcmp(t->tht_identifier, id))
+ LIST_FOREACH(t, &iptv_all_services, s_group_link)
+ if(!strcmp(t->s_identifier, id))
return t;
}
tally = MAX(atoi(id + 5), tally);
}
- t = transport_create(id, TRANSPORT_IPTV, THT_MPEG_TS);
+ t = service_create(id, SERVICE_TYPE_IPTV, S_MPEG_TS);
- t->tht_start_feed = iptv_transport_start;
- t->tht_refresh_feed = iptv_transport_refresh;
- t->tht_stop_feed = iptv_transport_stop;
- t->tht_config_save = iptv_transport_save;
- t->tht_setsourceinfo = iptv_transport_setsourceinfo;
- t->tht_quality_index = iptv_transport_quality;
- t->tht_grace_period = iptv_grace_period;
- t->tht_dtor = iptv_transport_dtor;
- t->tht_iptv_fd = -1;
+ t->s_start_feed = iptv_service_start;
+ t->s_refresh_feed = iptv_service_refresh;
+ t->s_stop_feed = iptv_service_stop;
+ t->s_config_save = iptv_service_save;
+ t->s_setsourceinfo = iptv_service_setsourceinfo;
+ t->s_quality_index = iptv_service_quality;
+ t->s_grace_period = iptv_grace_period;
+ t->s_dtor = iptv_service_dtor;
+ t->s_iptv_fd = -1;
- LIST_INSERT_HEAD(&iptv_all_transports, t, tht_group_link);
+ LIST_INSERT_HEAD(&iptv_all_services, t, s_group_link);
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
return t;
}
* Load config for the given mux
*/
static void
-iptv_transport_load(void)
+iptv_service_load(void)
{
htsmsg_t *l, *c;
htsmsg_field_t *f;
uint32_t pmt;
const char *s;
unsigned int u32;
- th_transport_t *t;
+ service_t *t;
lock_assert(&global_lock);
- if((l = hts_settings_load("iptvtransports")) == NULL)
+ if((l = hts_settings_load("iptvservices")) == NULL)
return;
HTSMSG_FOREACH(f, l) {
if(htsmsg_get_u32(c, "pmt", &pmt))
continue;
- t = iptv_transport_find(f->hmf_name, 1);
- t->tht_pmt_pid = pmt;
+ t = iptv_service_find(f->hmf_name, 1);
+ t->s_pmt_pid = pmt;
- tvh_str_update(&t->tht_iptv_iface, htsmsg_get_str(c, "interface"));
+ tvh_str_update(&t->s_iptv_iface, htsmsg_get_str(c, "interface"));
if((s = htsmsg_get_str(c, "group")) != NULL){
- if (!inet_pton(AF_INET, s, &t->tht_iptv_group.s_addr)) {
- inet_pton(AF_INET6, s, &t->tht_iptv_group6.s6_addr);
+ if (!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)) {
+ inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
}
}
if(!htsmsg_get_u32(c, "port", &u32))
- t->tht_iptv_port = u32;
+ t->s_iptv_port = u32;
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- psi_load_transport_settings(c, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ psi_load_service_settings(c, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
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), 0);
+ service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
}
htsmsg_destroy(l);
}
iptv_input_init(void)
{
pthread_mutex_init(&iptv_recvmutex, NULL);
- iptv_transport_load();
+ iptv_service_load();
}
void iptv_input_init(void);
-th_transport_t *iptv_transport_find(const char *id, int create);
+struct service *iptv_service_find(const char *id, int create);
-extern struct th_transport_list iptv_all_transports;
+extern struct service_list iptv_all_services;
#endif /* IPTV_INPUT_H_ */
#include "rawtsinput.h"
#include "avahi.h"
#include "iptv_input.h"
-#include "transports.h"
+#include "service.h"
#include "v4l.h"
#include "trap.h"
#include "settings.h"
*/
xmltv_init(); /* Must be initialized before channels */
- transport_init();
+ service_init();
channels_init();
#include "parsers.h"
#include "parser_h264.h"
#include "bitstream.h"
+#include "service.h"
/**
* H.264 parser, nal escaper
void *h264_nal_deescape(bitstream_t *bs, const uint8_t *data, int size);
-int h264_decode_seq_parameter_set(th_stream_t *st, bitstream_t *bs);
+int h264_decode_seq_parameter_set(struct th_stream *st, bitstream_t *bs);
-int h264_decode_pic_parameter_set(th_stream_t *st, bitstream_t *bs);
+int h264_decode_pic_parameter_set(struct th_stream *st, bitstream_t *bs);
-int h264_decode_slice_header(th_stream_t *st, bitstream_t *bs, int *pkttype,
- int *duration, int *isfield);
+int h264_decode_slice_header(struct th_stream *st, bitstream_t *bs,
+ int *pkttype, int *duration, int *isfield);
#endif /* PARSER_H264_H_ */
#include "parsers.h"
#include "parser_latm.h"
#include "bitstream.h"
-
+#include "service.h"
typedef struct latm_private {
* Parse AAC LATM
*/
th_pkt_t *
-parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st,
+parse_latm_audio_mux_element(service_t *t, th_stream_t *st,
const uint8_t *data, int len)
{
latm_private_t *latm;
th_pkt_t *pkt = pkt_alloc(NULL, slot_len + 7, st->st_curdts, st->st_curdts);
- pkt->pkt_commercial = t->tht_tt_commercial_advice;
+ pkt->pkt_commercial = t->s_tt_commercial_advice;
pkt->pkt_duration = st->st_frame_duration;
pkt->pkt_sri = latm->sample_rate_index;
pkt->pkt_channels = latm->channel_config;
#ifndef PARSER_LATM_H_
#define PARSER_LATM_H_
-th_pkt_t *parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st,
+th_pkt_t *parse_latm_audio_mux_element(struct service *t,
+ struct th_stream *st,
const uint8_t *data, int len);
#endif /* PARSER_LATM_H_ */
#include <assert.h>
#include "tvheadend.h"
+#include "service.h"
#include "parsers.h"
#include "parser_h264.h"
#include "parser_latm.h"
#include "bitstream.h"
#include "packet.h"
-#include "transports.h"
#include "streaming.h"
#define PTS_MASK 0x1ffffffffLL
}
-static int parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
+static int parse_mpeg2video(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-static int parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
+static int parse_h264(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-typedef int (packet_parser_t)(th_transport_t *t, th_stream_t *st, size_t len,
+typedef int (packet_parser_t)(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-typedef void (aparser_t)(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
+typedef void (aparser_t)(service_t *t, th_stream_t *st, th_pkt_t *pkt);
-static void parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+static void parse_sc(service_t *t, th_stream_t *st, const uint8_t *data,
int len, packet_parser_t *vp);
-static void parse_aac(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+static void parse_aac(service_t *t, th_stream_t *st, const uint8_t *data,
int len, int start);
-static void parse_subtitles(th_transport_t *t, th_stream_t *st,
+static void parse_subtitles(service_t *t, th_stream_t *st,
const uint8_t *data, int len, int start);
-static int parse_mpa(th_transport_t *t, th_stream_t *st, size_t len,
+static int parse_mpa(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-static int parse_mpa2(th_transport_t *t, th_stream_t *st);
+static int parse_mpa2(service_t *t, th_stream_t *st);
-static int parse_ac3(th_transport_t *t, th_stream_t *st, size_t len,
+static int parse_ac3(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-static int parse_eac3(th_transport_t *t, th_stream_t *st, size_t len,
+static int parse_eac3(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset);
-static void parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
+static void parser_deliver(service_t *t, th_stream_t *st, th_pkt_t *pkt);
-static int parse_pes_header(th_transport_t *t, th_stream_t *st,
+static int parse_pes_header(service_t *t, th_stream_t *st,
const uint8_t *buf, size_t len);
/**
* Parse raw mpeg data
*/
void
-parse_mpeg_ts(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+parse_mpeg_ts(service_t *t, th_stream_t *st, const uint8_t *data,
int len, int start, int err)
{
* Note: data does not include startcode and packet length
*/
void
-parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len)
+parse_mpeg_ps(service_t *t, th_stream_t *st, uint8_t *data, int len)
{
int hlen;
* Parse AAC LATM
*/
static void
-parse_aac(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+parse_aac(service_t *t, th_stream_t *st, const uint8_t *data,
int len, int start)
{
int l, muxlen, p;
* derive further information.
*/
static void
-parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
+parse_sc(service_t *t, th_stream_t *st, const uint8_t *data, int len,
packet_parser_t *vp)
{
uint32_t sc = st->st_startcond;
*
*/
static int
-depacketize(th_transport_t *t, th_stream_t *st, size_t len,
+depacketize(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset)
{
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
*
*/
static void
-makeapkt(th_transport_t *t, th_stream_t *st, const void *buf,
+makeapkt(service_t *t, th_stream_t *st, const void *buf,
int len, int64_t dts, int duration, int channels, int sri)
{
th_pkt_t *pkt = pkt_alloc(buf, len, dts, dts);
- pkt->pkt_commercial = t->tht_tt_commercial_advice;
+ pkt->pkt_commercial = t->s_tt_commercial_advice;
pkt->pkt_duration = duration;
pkt->pkt_channels = channels;
pkt->pkt_sri = sri;
*
*/
static int
-parse_mpa2(th_transport_t *t, th_stream_t *st)
+parse_mpa2(service_t *t, th_stream_t *st)
{
int i, len;
const uint8_t *buf;
*
*/
static int
-parse_mpa(th_transport_t *t, th_stream_t *st, size_t ilen,
+parse_mpa(service_t *t, th_stream_t *st, size_t ilen,
uint32_t next_startcode, int sc_offset)
{
int r;
static int
-parse_ac3(th_transport_t *t, th_stream_t *st, size_t ilen,
+parse_ac3(service_t *t, th_stream_t *st, size_t ilen,
uint32_t next_startcode, int sc_offset)
{
int i, len;
}
static int
-parse_eac3(th_transport_t *t, th_stream_t *st, size_t ilen,
+parse_eac3(service_t *t, th_stream_t *st, size_t ilen,
uint32_t next_startcode, int sc_offset)
{
int i, len;
* Extract DTS and PTS and update current values in stream
*/
static int
-parse_pes_header(th_transport_t *t, th_stream_t *st,
+parse_pes_header(service_t *t, th_stream_t *st,
const uint8_t *buf, size_t len)
{
int64_t dts, pts, d;
err:
st->st_curdts = PTS_UNSET;
st->st_curpts = PTS_UNSET;
- limitedlog(&st->st_loglimit_pes, "TS", transport_component_nicename(st),
+ limitedlog(&st->st_loglimit_pes, "TS", service_component_nicename(st),
"Corrupted PES header");
return -1;
}
* Parse mpeg2video picture start
*/
static int
-parse_mpeg2video_pic_start(th_transport_t *t, th_stream_t *st, int *frametype,
+parse_mpeg2video_pic_start(service_t *t, th_stream_t *st, int *frametype,
bitstream_t *bs)
{
int v, pct;
if(need_save) {
st->st_width = width;
st->st_height = height;
- transport_request_save(st->st_transport, 1);
+ service_request_save(st->st_service, 1);
}
}
* Parse mpeg2video sequence start
*/
static int
-parse_mpeg2video_seq_start(th_transport_t *t, th_stream_t *st,
+parse_mpeg2video_seq_start(service_t *t, th_stream_t *st,
bitstream_t *bs)
{
int v, width, height, aspect;
*
*/
static int
-parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
+parse_mpeg2video(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset)
{
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
st->st_curpkt = pkt_alloc(NULL, 0, st->st_curpts, st->st_curdts);
st->st_curpkt->pkt_frametype = frametype;
st->st_curpkt->pkt_duration = st->st_frame_duration;
- st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
+ st->st_curpkt->pkt_commercial = t->s_tt_commercial_advice;
break;
case 0x000001b3:
* H.264 parser
*/
static int
-parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
+parse_h264(service_t *t, th_stream_t *st, size_t len,
uint32_t next_startcode, int sc_offset)
{
const uint8_t *buf = st->st_buf.sb_data + sc_offset;
st->st_curpkt->pkt_frametype = pkttype;
st->st_curpkt->pkt_field = isfield;
st->st_curpkt->pkt_duration = duration ?: st->st_frame_duration;
- st->st_curpkt->pkt_commercial = t->tht_tt_commercial_advice;
+ st->st_curpkt->pkt_commercial = t->s_tt_commercial_advice;
break;
default:
* http://broadcasting.ru/pdf-standard-specifications/subtitling/dvb-sub/en300743.v1.2.1.pdf
*/
static void
-parse_subtitles(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+parse_subtitles(service_t *t, th_stream_t *st, const uint8_t *data,
int len, int start)
{
th_pkt_t *pkt;
// end_of_PES_data_field_marker
if(buf[psize - 1] == 0xff) {
pkt = pkt_alloc(buf, psize - 1, st->st_curpts, st->st_curdts);
- pkt->pkt_commercial = t->tht_tt_commercial_advice;
+ pkt->pkt_commercial = t->s_tt_commercial_advice;
parser_deliver(t, st, pkt);
}
}
*
*/
static void
-parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
+parser_deliver(service_t *t, th_stream_t *st, th_pkt_t *pkt)
{
if(SCT_ISAUDIO(st->st_type) && pkt->pkt_pts != PTS_UNSET &&
- (t->tht_current_pts == PTS_UNSET ||
- pkt->pkt_pts > t->tht_current_pts ||
- pkt->pkt_pts < t->tht_current_pts - 180000))
- t->tht_current_pts = pkt->pkt_pts;
+ (t->s_current_pts == PTS_UNSET ||
+ pkt->pkt_pts > t->s_current_pts ||
+ pkt->pkt_pts < t->s_current_pts - 180000))
+ t->s_current_pts = pkt->pkt_pts;
#if 0
printf("PARSE: %-12s %d %10"PRId64" %10"PRId64" %10d %10d\n",
/**
* Input is ok
*/
- transport_set_streaming_status_flags(t, TSS_PACKETS);
+ service_set_streaming_status_flags(t, TSS_PACKETS);
/* Forward packet */
pkt->pkt_componentindex = st->st_index;
streaming_message_t *sm = streaming_msg_create_pkt(pkt);
- streaming_pad_deliver(&t->tht_streaming_pad, sm);
+ streaming_pad_deliver(&t->s_streaming_pad, sm);
streaming_msg_free(sm);
/* Decrease our own reference to the packet */
#include "packet.h"
-void parse_mpeg_ts(th_transport_t *t, th_stream_t *st, const uint8_t *data,
+void parse_mpeg_ts(struct service *t, struct th_stream *st,
+ const uint8_t *data,
int len, int start, int err);
-void parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len);
+void parse_mpeg_ps(struct service *t, struct th_stream *st,
+ uint8_t *data, int len);
-void parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt);
+void parser_enqueue_packet(struct service *t, struct th_stream *st,
+ th_pkt_t *pkt);
-void parser_set_stream_vsize(th_stream_t *st, int width, int height);
+void parser_set_stream_vsize(struct th_stream *st, int width, int height);
extern const unsigned int mpeg2video_framedurations[16];
break;
case SMT_EXIT:
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
case SMT_NOSTART:
case SMT_MPEGTS:
streaming_target_deliver2(gh->gh_output, sm);
gh_flush(gh);
// FALLTHRU
case SMT_EXIT:
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
case SMT_NOSTART:
case SMT_MPEGTS:
streaming_target_deliver2(gh->gh_output, sm);
break;
case SMT_EXIT:
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
case SMT_NOSTART:
case SMT_MPEGTS:
break;
#include "tvheadend.h"
#include "psi.h"
-#include "transports.h"
#include "dvb/dvb_support.h"
#include "tsdemux.h"
#include "parsers.h"
* PAT parser, from ISO 13818-1
*/
int
-psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
+psi_parse_pat(service_t *t, uint8_t *ptr, int len,
pid_section_callback_t *pmt_callback)
{
uint16_t prognum;
uint16_t pid;
th_stream_t *st;
- lock_assert(&t->tht_stream_mutex);
+ lock_assert(&t->s_stream_mutex);
if(len < 5)
return -1;
pid = (ptr[2] & 0x1f) << 8 | ptr[3];
if(prognum != 0) {
- if(transport_stream_find(t, pid) == NULL) {
- st = transport_stream_create(t, pid, SCT_PMT);
+ if(service_stream_find(t, pid) == NULL) {
+ st = service_stream_create(t, pid, SCT_PMT);
st->st_section_docrc = 1;
st->st_got_section = pmt_callback;
}
*/
int
-psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid)
+psi_build_pat(service_t *t, uint8_t *buf, int maxlen, int pmtpid)
{
if(maxlen < 12)
return -1;
* Add a CA descriptor
*/
static int
-psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid)
+psi_desc_add_ca(service_t *t, uint16_t caid, uint32_t provid, uint16_t pid)
{
th_stream_t *st;
caid_t *c;
int r = 0;
- if((st = transport_stream_find(t, pid)) == NULL) {
- st = transport_stream_create(t, pid, SCT_CA);
+ if((st = service_stream_find(t, pid)) == NULL) {
+ st = service_stream_create(t, pid, SCT_CA);
r |= PMT_UPDATE_NEW_CA_STREAM;
}
* Parser for CA descriptors
*/
static int
-psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size)
+psi_desc_ca(service_t *t, const uint8_t *buffer, int size)
{
int r = 0;
int i;
* Parser for teletext descriptor
*/
static int
-psi_desc_teletext(th_transport_t *t, const uint8_t *ptr, int size,
+psi_desc_teletext(service_t *t, const uint8_t *ptr, int size,
int parent_pid, int *position)
{
int r = 0;
// higher than normal MPEG TS (0x2000 ++)
int pid = PID_TELETEXT_BASE + page;
- if((st = transport_stream_find(t, pid)) == NULL) {
+ if((st = service_stream_find(t, pid)) == NULL) {
r |= PMT_UPDATE_NEW_STREAM;
- st = transport_stream_create(t, pid, SCT_TEXTSUB);
+ st = service_stream_create(t, pid, SCT_TEXTSUB);
}
st->st_delete_me = 0;
*
*/
static void
-sort_pids(th_transport_t *t)
+sort_pids(service_t *t)
{
th_stream_t *st, **v;
int num = 0, i = 0;
- TAILQ_FOREACH(st, &t->tht_components, st_link)
+ TAILQ_FOREACH(st, &t->s_components, st_link)
num++;
v = alloca(num * sizeof(th_stream_t *));
- TAILQ_FOREACH(st, &t->tht_components, st_link)
+ TAILQ_FOREACH(st, &t->s_components, st_link)
v[i++] = st;
qsort(v, num, sizeof(th_stream_t *), pidcmp);
- TAILQ_INIT(&t->tht_components);
+ TAILQ_INIT(&t->s_components);
for(i = 0; i < num; i++)
- TAILQ_INSERT_TAIL(&t->tht_components, v[i], st_link);
+ TAILQ_INSERT_TAIL(&t->s_components, v[i], st_link);
}
* PMT parser, from ISO 13818-1 and ETSI EN 300 468
*/
int
-psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
+psi_parse_pmt(service_t *t, const uint8_t *ptr, int len, int chksvcid,
int delete)
{
uint16_t pcr_pid, pid;
if(len < 9)
return -1;
- lock_assert(&t->tht_stream_mutex);
+ lock_assert(&t->s_stream_mutex);
- had_components = !!TAILQ_FIRST(&t->tht_components);
+ had_components = !!TAILQ_FIRST(&t->s_components);
sid = ptr[0] << 8 | ptr[1];
version = ptr[2] >> 1 & 0x1f;
pcr_pid = (ptr[5] & 0x1f) << 8 | ptr[6];
dllen = (ptr[7] & 0xf) << 8 | ptr[8];
- if(chksvcid && sid != t->tht_dvb_service_id)
+ if(chksvcid && sid != t->s_dvb_service_id)
return -1;
- if(t->tht_pcr_pid != pcr_pid) {
- t->tht_pcr_pid = pcr_pid;
+ if(t->s_pcr_pid != pcr_pid) {
+ t->s_pcr_pid = pcr_pid;
update |= PMT_UPDATE_PCR;
}
/* Mark all streams for deletion */
if(delete) {
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
st->st_delete_me = 1;
LIST_FOREACH(c, &st->st_caids, link)
if(hts_stream_type == SCT_UNKNOWN && estype == 0x06 &&
- pid == 3401 && t->tht_dvb_service_id == 10510) {
+ pid == 3401 && t->s_dvb_service_id == 10510) {
// Workaround for ITV HD
hts_stream_type = SCT_H264;
}
if(hts_stream_type != SCT_UNKNOWN) {
- if((st = transport_stream_find(t, pid)) == NULL) {
+ if((st = service_stream_find(t, pid)) == NULL) {
update |= PMT_UPDATE_NEW_STREAM;
- st = transport_stream_create(t, pid, hts_stream_type);
+ st = service_stream_create(t, pid, hts_stream_type);
}
st->st_delete_me = 0;
}
/* Scan again to see if any streams should be deleted */
- for(st = TAILQ_FIRST(&t->tht_components); st != NULL; st = next) {
+ for(st = TAILQ_FIRST(&t->s_components); st != NULL; st = next) {
next = TAILQ_NEXT(st, st_link);
for(c = LIST_FIRST(&st->st_caids); c != NULL; c = cn) {
if(st->st_delete_me) {
- transport_stream_destroy(t, st);
+ service_stream_destroy(t, st);
update |= PMT_UPDATE_STREAM_DELETED;
}
}
sort_pids(t);
if(update) {
- tvhlog(LOG_DEBUG, "PSI", "Transport \"%s\" PMT (version %d) updated"
+ tvhlog(LOG_DEBUG, "PSI", "Service \"%s\" PMT (version %d) updated"
"%s%s%s%s%s%s%s%s%s%s%s%s%s",
- transport_nicename(t), version,
+ service_nicename(t), version,
update&PMT_UPDATE_PCR ? ", PCR PID changed":"",
update&PMT_UPDATE_NEW_STREAM ? ", New elementary stream":"",
update&PMT_UPDATE_LANGUAGE ? ", Language changed":"",
update&PMT_UPDATE_CAID_DELETED ? ", CAID deleted":"",
update&PMT_REORDERED ? ", PIDs reordered":"");
- transport_request_save(t, 0);
+ service_request_save(t, 0);
// Only restart if something that our clients worry about did change
if(update & !(PMT_UPDATE_NEW_CA_STREAM |
PMT_UPDATE_NEW_CAID |
PMT_UPDATE_CA_PROVIDER_CHANGE |
PMT_UPDATE_CAID_DELETED)) {
- if(t->tht_status == TRANSPORT_RUNNING)
- transport_restart(t, had_components);
+ if(t->s_status == SERVICE_RUNNING)
+ service_restart(t, had_components);
}
}
return 0;
/**
- * Store transport settings into message
+ * Store service settings into message
*/
void
-psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
+psi_save_service_settings(htsmsg_t *m, service_t *t)
{
th_stream_t *st;
htsmsg_t *sub;
- htsmsg_add_u32(m, "pcr", t->tht_pcr_pid);
+ htsmsg_add_u32(m, "pcr", t->s_pcr_pid);
- htsmsg_add_u32(m, "disabled", !t->tht_enabled);
+ htsmsg_add_u32(m, "disabled", !t->s_enabled);
- lock_assert(&t->tht_stream_mutex);
+ lock_assert(&t->s_stream_mutex);
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
sub = htsmsg_create_map();
htsmsg_add_u32(sub, "pid", st->st_pid);
/**
- * Load transport info from htsmsg
+ * Load service info from htsmsg
*/
void
-psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
+psi_load_service_settings(htsmsg_t *m, service_t *t)
{
htsmsg_t *c;
htsmsg_field_t *f;
const char *v;
if(!htsmsg_get_u32(m, "pcr", &u32))
- t->tht_pcr_pid = u32;
+ t->s_pcr_pid = u32;
if(!htsmsg_get_u32(m, "disabled", &u32))
- t->tht_enabled = !u32;
+ t->s_enabled = !u32;
else
- t->tht_enabled = 1;
+ t->s_enabled = 1;
HTSMSG_FOREACH(f, m) {
if(strcmp(f->hmf_name, "stream"))
if(htsmsg_get_u32(c, "pid", &pid))
continue;
- st = transport_stream_create(t, pid, type);
+ st = service_stream_create(t, pid, type);
if((v = htsmsg_get_str(c, "language")) != NULL)
snprintf(st->st_lang, 4, "%s", v);
#include "htsmsg.h"
#include "streaming.h"
+#include "service.h"
#define PSI_SECTION_SIZE 5000
void psi_section_reassemble(psi_section_t *ps, const uint8_t *tsb, int crc,
section_handler_t *cb, void *opaque);
-int psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
+int psi_parse_pat(struct service *t, uint8_t *ptr, int len,
pid_section_callback_t *pmt_callback);
-int psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
+int psi_parse_pmt(struct service *t, const uint8_t *ptr, int len, int chksvcid,
int delete);
-int psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid);
+int psi_build_pat(struct service *t, uint8_t *buf, int maxlen, int pmtpid);
int psi_build_pmt(streaming_start_t *ss, uint8_t *buf, int maxlen, int pcrpid);
const char *psi_caid2name(uint16_t caid);
-void psi_load_transport_settings(htsmsg_t *m, th_transport_t *t);
-void psi_save_transport_settings(htsmsg_t *m, th_transport_t *t);
+void psi_load_service_settings(htsmsg_t *m, struct service *t);
+void psi_save_service_settings(htsmsg_t *m, struct service *t);
#endif /* PSI_H_ */
#include <errno.h>
#include "tvheadend.h"
-#include "transports.h"
#include "rawtsinput.h"
#include "psi.h"
#include "tsdemux.h"
+#include "channels.h"
typedef struct rawts {
int rt_fd;
char *rt_identifier;
psi_section_t rt_pat;
- struct th_transport_list rt_transports;
+ struct service_list rt_services;
int rt_pcr_pid;
*
*/
static int
-rawts_transport_start(th_transport_t *t, unsigned int weight, int force_start)
+rawts_service_start(service_t *t, unsigned int weight, int force_start)
{
return 0; // Always ok
}
*
*/
static void
-rawts_transport_stop(th_transport_t *t)
+rawts_service_stop(service_t *t)
{
}
*
*/
static void
-rawts_transport_save(th_transport_t *t)
+rawts_service_save(service_t *t)
{
htsmsg_t *m = htsmsg_create_map();
- printf("SAVE %s\n", transport_nicename(t));
+ printf("SAVE %s\n", service_nicename(t));
- pthread_mutex_lock(&t->tht_stream_mutex);
- psi_save_transport_settings(m, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ psi_save_service_settings(m, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
htsmsg_print(m);
htsmsg_destroy(m);
*
*/
static int
-rawts_transport_quality(th_transport_t *t)
+rawts_service_quality(service_t *t)
{
return 100;
}
* Generate a descriptive name for the source
*/
static void
-rawts_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
+rawts_service_setsourceinfo(service_t *t, struct source_info *si)
{
memset(si, 0, sizeof(struct source_info));
}
/**
*
*/
-static th_transport_t *
-rawts_transport_add(rawts_t *rt, uint16_t sid, int pmt_pid)
+static service_t *
+rawts_service_add(rawts_t *rt, uint16_t sid, int pmt_pid)
{
- th_transport_t *t;
- channel_t *ch;
+ service_t *t;
+ struct channel *ch;
char tmp[200];
- LIST_FOREACH(t, &rt->rt_transports, tht_group_link) {
- if(t->tht_dvb_service_id == sid)
+ LIST_FOREACH(t, &rt->rt_services, s_group_link) {
+ if(t->s_dvb_service_id == sid)
return t;
}
snprintf(tmp, sizeof(tmp), "%s_%04x", rt->rt_identifier, sid);
- t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS);
- t->tht_flags |= THT_DEBUG;
+ t = service_create(tmp, SERVICE_TYPE_DVB, S_MPEG_TS);
+ t->s_flags |= S_DEBUG;
- t->tht_dvb_service_id = sid;
- t->tht_pmt_pid = pmt_pid;
+ t->s_dvb_service_id = sid;
+ t->s_pmt_pid = pmt_pid;
- t->tht_start_feed = rawts_transport_start;
- t->tht_stop_feed = rawts_transport_stop;
- t->tht_config_save = rawts_transport_save;
- t->tht_setsourceinfo = rawts_transport_setsourceinfo;
- t->tht_quality_index = rawts_transport_quality;
+ t->s_start_feed = rawts_service_start;
+ t->s_stop_feed = rawts_service_stop;
+ t->s_config_save = rawts_service_save;
+ t->s_setsourceinfo = rawts_service_setsourceinfo;
+ t->s_quality_index = rawts_service_quality;
- t->tht_svcname = strdup(tmp);
+ t->s_svcname = strdup(tmp);
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
tvhlog(LOG_NOTICE, "rawts", "Added service %d (pmt: %d)", sid, pmt_pid);
- LIST_INSERT_HEAD(&rt->rt_transports, t, tht_group_link);
+ LIST_INSERT_HEAD(&rt->rt_services, t, s_group_link);
ch = channel_find_by_name(tmp, 1, 0);
- transport_map_channel(t, ch, 0);
+ service_map_channel(t, ch, 0);
return t;
}
*/
static void
-got_pmt(struct th_transport *t, th_stream_t *st,
+got_pmt(struct service *t, th_stream_t *st,
const uint8_t *table, int table_len)
{
if(table[0] != 2)
got_pat(const uint8_t *ptr, size_t len, void *opaque)
{
rawts_t *rt = opaque;
- th_transport_t *t;
+ service_t *t;
th_stream_t *st;
uint16_t prognum;
uint16_t pid;
pid = (ptr[2] & 0x1f) << 8 | ptr[3];
if(prognum != 0) {
- t = rawts_transport_add(rt, prognum, pid);
+ t = rawts_service_add(rt, prognum, pid);
if(t != NULL) {
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
- if(transport_stream_find(t, pid) == NULL) {
- st = transport_stream_create(t, pid, SCT_PMT);
+ if(service_stream_find(t, pid) == NULL) {
+ st = service_stream_create(t, pid, SCT_PMT);
st->st_section_docrc = 1;
st->st_got_section = got_pmt;
}
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
}
ptr += 4;
process_ts_packet(rawts_t *rt, uint8_t *tsb)
{
uint16_t pid;
- th_transport_t *t;
+ service_t *t;
int64_t pcr, d;
int didsleep = 0;
return;
}
- LIST_FOREACH(t, &rt->rt_transports, tht_group_link) {
+ LIST_FOREACH(t, &rt->rt_services, s_group_link) {
pcr = PTS_UNSET;
ts_recv_packet1(t, tsb, &pcr);
rt->rt_pcr_pid = pid;
if(rt->rt_pcr_pid == pid) {
- if(t->tht_pcr_last != PTS_UNSET && didsleep == 0) {
+ if(t->s_pcr_last != PTS_UNSET && didsleep == 0) {
struct timespec slp;
- int64_t delta = pcr - t->tht_pcr_last;
+ int64_t delta = pcr - t->s_pcr_last;
if(delta > 90000)
delta = 90000;
delta *= 11;
- d = delta + t->tht_pcr_last_realtime;
+ d = delta + t->s_pcr_last_realtime;
slp.tv_sec = d / 1000000;
slp.tv_nsec = (d % 1000000) * 1000;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &slp, NULL);
didsleep = 1;
}
- t->tht_pcr_last = pcr;
- t->tht_pcr_last_realtime = getmonoclock();
+ t->s_pcr_last = pcr;
+ t->s_pcr_last_realtime = getmonoclock();
}
}
}
--- /dev/null
+/*
+ * Services
+ * Copyright (C) 2010 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 <pthread.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tvheadend.h"
+#include "service.h"
+#include "subscriptions.h"
+#include "tsdemux.h"
+#include "streaming.h"
+#include "v4l.h"
+#include "psi.h"
+#include "packet.h"
+#include "channels.h"
+#include "cwc.h"
+#include "capmt.h"
+#include "notify.h"
+#include "serviceprobe.h"
+#include "atomic.h"
+#include "dvb/dvb.h"
+#include "htsp.h"
+
+#define SERVICE_HASH_WIDTH 101
+
+static struct service_list servicehash[SERVICE_HASH_WIDTH];
+
+static void service_data_timeout(void *aux);
+
+/**
+ *
+ */
+static void
+stream_init(th_stream_t *st)
+{
+ st->st_cc_valid = 0;
+
+ st->st_startcond = 0xffffffff;
+ st->st_curdts = PTS_UNSET;
+ st->st_curpts = PTS_UNSET;
+ st->st_prevdts = PTS_UNSET;
+
+ st->st_pcr_real_last = PTS_UNSET;
+ st->st_pcr_last = PTS_UNSET;
+ st->st_pcr_drift = 0;
+ st->st_pcr_recovery_fails = 0;
+
+ st->st_blank = 0;
+}
+
+
+/**
+ *
+ */
+static void
+stream_clean(th_stream_t *st)
+{
+ if(st->st_demuxer_fd != -1) {
+ // XXX: Should be in DVB-code perhaps
+ close(st->st_demuxer_fd);
+ st->st_demuxer_fd = -1;
+ }
+
+ free(st->st_priv);
+ st->st_priv = NULL;
+
+ /* Clear reassembly buffers */
+
+ st->st_startcode = 0;
+
+ sbuf_free(&st->st_buf);
+ sbuf_free(&st->st_buf_ps);
+ sbuf_free(&st->st_buf_a);
+
+ if(st->st_curpkt != NULL) {
+ pkt_ref_dec(st->st_curpkt);
+ st->st_curpkt = NULL;
+ }
+
+ free(st->st_global_data);
+ st->st_global_data = NULL;
+ st->st_global_data_len = 0;
+}
+
+
+/**
+ *
+ */
+void
+service_stream_destroy(service_t *t, th_stream_t *st)
+{
+ if(t->s_status == SERVICE_RUNNING)
+ stream_clean(st);
+ TAILQ_REMOVE(&t->s_components, st, st_link);
+ free(st->st_nicename);
+ free(st);
+}
+
+/**
+ * Service lock must be held
+ */
+static void
+service_stop(service_t *t)
+{
+ th_descrambler_t *td;
+ th_stream_t *st;
+
+ gtimer_disarm(&t->s_receive_timer);
+
+ t->s_stop_feed(t);
+
+ pthread_mutex_lock(&t->s_stream_mutex);
+
+ while((td = LIST_FIRST(&t->s_descramblers)) != NULL)
+ td->td_stop(td);
+
+ t->s_tt_commercial_advice = COMMERCIAL_UNKNOWN;
+
+ assert(LIST_FIRST(&t->s_streaming_pad.sp_targets) == NULL);
+ assert(LIST_FIRST(&t->s_subscriptions) == NULL);
+
+ /**
+ * Clean up each stream
+ */
+ TAILQ_FOREACH(st, &t->s_components, st_link)
+ stream_clean(st);
+
+ t->s_status = SERVICE_IDLE;
+
+ pthread_mutex_unlock(&t->s_stream_mutex);
+}
+
+
+/**
+ * Remove the given subscriber from the service
+ *
+ * if s == NULL all subscribers will be removed
+ *
+ * Global lock must be held
+ */
+void
+service_remove_subscriber(service_t *t, th_subscription_t *s,
+ int reason)
+{
+ lock_assert(&global_lock);
+
+ if(s == NULL) {
+ while((s = LIST_FIRST(&t->s_subscriptions)) != NULL) {
+ subscription_unlink_service(s, reason);
+ }
+ } else {
+ subscription_unlink_service(s, reason);
+ }
+
+ if(LIST_FIRST(&t->s_subscriptions) == NULL)
+ service_stop(t);
+}
+
+
+/**
+ *
+ */
+int
+service_start(service_t *t, unsigned int weight, int force_start)
+{
+ th_stream_t *st;
+ int r, timeout = 2;
+
+ lock_assert(&global_lock);
+
+ assert(t->s_status != SERVICE_RUNNING);
+ t->s_streaming_status = 0;
+ t->s_pcr_drift = 0;
+
+ if((r = t->s_start_feed(t, weight, force_start)))
+ return r;
+
+ cwc_service_start(t);
+ capmt_service_start(t);
+
+ pthread_mutex_lock(&t->s_stream_mutex);
+
+ t->s_status = SERVICE_RUNNING;
+ t->s_current_pts = PTS_UNSET;
+
+ /**
+ * Initialize stream
+ */
+ TAILQ_FOREACH(st, &t->s_components, st_link)
+ stream_init(st);
+
+ pthread_mutex_unlock(&t->s_stream_mutex);
+
+ if(t->s_grace_period != NULL)
+ timeout = t->s_grace_period(t);
+
+ gtimer_arm(&t->s_receive_timer, service_data_timeout, t, timeout);
+ return 0;
+}
+
+/**
+ *
+ */
+static int
+dvb_extra_prio(th_dvb_adapter_t *tda)
+{
+ return tda->tda_hostconnection * 10;
+}
+
+/**
+ * Return prio for the given service
+ */
+static int
+service_get_prio(service_t *t)
+{
+ switch(t->s_type) {
+ case SERVICE_TYPE_DVB:
+ return (t->s_scrambled ? 300 : 100) +
+ dvb_extra_prio(t->s_dvb_mux_instance->tdmi_adapter);
+
+ case SERVICE_TYPE_IPTV:
+ return 200;
+
+ case SERVICE_TYPE_V4L:
+ return 400;
+
+ default:
+ return 500;
+ }
+}
+
+/**
+ * Return quality index for given service
+ *
+ * We invert the result (providers say that negative numbers are worse)
+ *
+ * But for sorting, we want low numbers first
+ *
+ * Also, we bias and trim with an offset of two to avoid counting any
+ * transient errors.
+ */
+
+static int
+service_get_quality(service_t *t)
+{
+ return t->s_quality_index ? -MIN(t->s_quality_index(t) + 2, 0) : 0;
+}
+
+
+
+
+/**
+ * a - b -> lowest number first
+ */
+static int
+servicecmp(const void *A, const void *B)
+{
+ service_t *a = *(service_t **)A;
+ service_t *b = *(service_t **)B;
+
+ int q = service_get_quality(a) - service_get_quality(b);
+
+ if(q != 0)
+ return q; /* Quality precedes priority */
+
+ return service_get_prio(a) - service_get_prio(b);
+}
+
+
+/**
+ *
+ */
+service_t *
+service_find(channel_t *ch, unsigned int weight, const char *loginfo,
+ int *errorp, service_t *skip)
+{
+ service_t *t, **vec;
+ int cnt = 0, i, r, off;
+ int err = 0;
+
+ lock_assert(&global_lock);
+
+ /* First, sort all services in order */
+
+ LIST_FOREACH(t, &ch->ch_services, s_ch_link)
+ cnt++;
+
+ vec = alloca(cnt * sizeof(service_t *));
+ cnt = 0;
+ LIST_FOREACH(t, &ch->ch_services, s_ch_link) {
+
+ if(!t->s_enabled) {
+ if(loginfo != NULL) {
+ tvhlog(LOG_NOTICE, "Service", "%s: Skipping \"%s\" -- not enabled",
+ loginfo, service_nicename(t));
+ err = SM_CODE_SVC_NOT_ENABLED;
+ }
+ continue;
+ }
+
+ if(t->s_quality_index(t) < 10) {
+ if(loginfo != NULL) {
+ tvhlog(LOG_NOTICE, "Service",
+ "%s: Skipping \"%s\" -- Quality below 10%",
+ loginfo, service_nicename(t));
+ err = SM_CODE_BAD_SIGNAL;
+ }
+ continue;
+ }
+ vec[cnt++] = t;
+ }
+
+ /* Sort services, lower priority should come come earlier in the vector
+ (i.e. it will be more favoured when selecting a service */
+
+ qsort(vec, cnt, sizeof(service_t *), servicecmp);
+
+ // Skip up to the service that the caller didn't want
+ // If the sorting above is not stable that might mess up things
+ // temporary. But it should resolve itself eventually
+ if(skip != NULL) {
+ for(i = 0; i < cnt; i++) {
+ if(skip == t)
+ break;
+ }
+ off = i + 1;
+ } else {
+ off = 0;
+ }
+
+ /* First, try all services without stealing */
+ for(i = off; i < cnt; i++) {
+ t = vec[i];
+ if(t->s_status == SERVICE_RUNNING)
+ return t;
+ if((r = service_start(t, 0, 0)) == 0)
+ return t;
+ if(loginfo != NULL)
+ tvhlog(LOG_DEBUG, "Service", "%s: Unable to use \"%s\" -- %s",
+ loginfo, service_nicename(t), streaming_code2txt(r));
+ }
+
+ /* Ok, nothing, try again, but supply our weight and thus, try to steal
+ transponders */
+
+ for(i = off; i < cnt; i++) {
+ t = vec[i];
+ if((r = service_start(t, weight, 0)) == 0)
+ return t;
+ *errorp = r;
+ }
+ if(err)
+ *errorp = err;
+ else if(*errorp == 0)
+ *errorp = SM_CODE_NO_SERVICE;
+ return NULL;
+}
+
+
+/**
+ *
+ */
+unsigned int
+service_compute_weight(struct service_list *head)
+{
+ service_t *t;
+ th_subscription_t *s;
+ int w = 0;
+
+ lock_assert(&global_lock);
+
+ LIST_FOREACH(t, head, s_active_link) {
+ LIST_FOREACH(s, &t->s_subscriptions, ths_service_link) {
+ if(s->ths_weight > w)
+ w = s->ths_weight;
+ }
+ }
+ return w;
+}
+
+
+/**
+ *
+ */
+void
+service_unref(service_t *t)
+{
+ if((atomic_add(&t->s_refcount, -1)) == 1)
+ free(t);
+}
+
+
+/**
+ *
+ */
+void
+service_ref(service_t *t)
+{
+ atomic_add(&t->s_refcount, 1);
+}
+
+
+
+/**
+ * Destroy a service
+ */
+void
+service_destroy(service_t *t)
+{
+ th_stream_t *st;
+ th_subscription_t *s;
+ channel_t *ch = t->s_ch;
+
+ if(t->s_dtor != NULL)
+ t->s_dtor(t);
+
+ lock_assert(&global_lock);
+
+ serviceprobe_delete(t);
+
+ while((s = LIST_FIRST(&t->s_subscriptions)) != NULL) {
+ subscription_unlink_service(s, SM_CODE_SOURCE_DELETED);
+ }
+
+ if(t->s_ch != NULL) {
+ t->s_ch = NULL;
+ LIST_REMOVE(t, s_ch_link);
+ }
+
+ LIST_REMOVE(t, s_group_link);
+ LIST_REMOVE(t, s_hash_link);
+
+ if(t->s_status != SERVICE_IDLE)
+ service_stop(t);
+
+ t->s_status = SERVICE_ZOMBIE;
+
+ free(t->s_identifier);
+ free(t->s_svcname);
+ free(t->s_provider);
+
+ while((st = TAILQ_FIRST(&t->s_components)) != NULL) {
+ TAILQ_REMOVE(&t->s_components, st, st_link);
+ free(st->st_nicename);
+ free(st);
+ }
+
+ free(t->s_pat_section);
+ free(t->s_pmt_section);
+
+ service_unref(t);
+
+ if(ch != NULL) {
+ if(LIST_FIRST(&ch->ch_services) == NULL)
+ channel_delete(ch);
+ }
+}
+
+
+/**
+ * Create and initialize a new service struct
+ */
+service_t *
+service_create(const char *identifier, int type, int source_type)
+{
+ unsigned int hash = tvh_strhash(identifier, SERVICE_HASH_WIDTH);
+ service_t *t = calloc(1, sizeof(service_t));
+
+ lock_assert(&global_lock);
+
+ pthread_mutex_init(&t->s_stream_mutex, NULL);
+ pthread_cond_init(&t->s_tss_cond, NULL);
+ t->s_identifier = strdup(identifier);
+ t->s_type = type;
+ t->s_source_type = source_type;
+ t->s_refcount = 1;
+ t->s_enabled = 1;
+ t->s_pcr_last = PTS_UNSET;
+ TAILQ_INIT(&t->s_components);
+
+ streaming_pad_init(&t->s_streaming_pad);
+
+ LIST_INSERT_HEAD(&servicehash[hash], t, s_hash_link);
+ return t;
+}
+
+/**
+ * Find a service based on the given identifier
+ */
+service_t *
+service_find_by_identifier(const char *identifier)
+{
+ service_t *t;
+ unsigned int hash = tvh_strhash(identifier, SERVICE_HASH_WIDTH);
+
+ lock_assert(&global_lock);
+
+ LIST_FOREACH(t, &servicehash[hash], s_hash_link)
+ if(!strcmp(t->s_identifier, identifier))
+ break;
+ return t;
+}
+
+
+/**
+ *
+ */
+static void
+service_stream_make_nicename(service_t *t, th_stream_t *st)
+{
+ char buf[200];
+ if(st->st_pid != -1)
+ snprintf(buf, sizeof(buf), "%s: %s @ #%d",
+ service_nicename(t),
+ streaming_component_type2txt(st->st_type), st->st_pid);
+ else
+ snprintf(buf, sizeof(buf), "%s: %s",
+ service_nicename(t),
+ streaming_component_type2txt(st->st_type));
+
+ free(st->st_nicename);
+ st->st_nicename = strdup(buf);
+}
+
+
+/**
+ *
+ */
+void
+service_make_nicename(service_t *t)
+{
+ char buf[200];
+ source_info_t si;
+ th_stream_t *st;
+
+ lock_assert(&t->s_stream_mutex);
+
+ t->s_setsourceinfo(t, &si);
+
+ snprintf(buf, sizeof(buf),
+ "%s%s%s%s%s",
+ si.si_adapter ?: "", si.si_adapter && si.si_mux ? "/" : "",
+ si.si_mux ?: "", si.si_mux && si.si_service ? "/" : "",
+ si.si_service ?: "");
+
+ service_source_info_free(&si);
+
+ free(t->s_nicename);
+ t->s_nicename = strdup(buf);
+
+ TAILQ_FOREACH(st, &t->s_components, st_link)
+ service_stream_make_nicename(t, st);
+}
+
+
+/**
+ * Add a new stream to a service
+ */
+th_stream_t *
+service_stream_create(service_t *t, int pid,
+ streaming_component_type_t type)
+{
+ th_stream_t *st;
+ int i = 0;
+ int idx = 0;
+ lock_assert(&t->s_stream_mutex);
+
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
+ if(st->st_index > idx)
+ idx = st->st_index;
+ i++;
+ if(pid != -1 && st->st_pid == pid)
+ return st;
+ }
+
+ st = calloc(1, sizeof(th_stream_t));
+ st->st_index = idx + 1;
+ st->st_type = type;
+
+ TAILQ_INSERT_TAIL(&t->s_components, st, st_link);
+ st->st_service = t;
+
+ st->st_pid = pid;
+ st->st_demuxer_fd = -1;
+
+ avgstat_init(&st->st_rate, 10);
+ avgstat_init(&st->st_cc_errors, 10);
+
+ service_stream_make_nicename(t, st);
+
+ if(t->s_flags & S_DEBUG)
+ tvhlog(LOG_DEBUG, "service", "Add stream %s", st->st_nicename);
+
+ if(t->s_status == SERVICE_RUNNING)
+ stream_init(st);
+
+ return st;
+}
+
+
+
+/**
+ * Add a new stream to a service
+ */
+th_stream_t *
+service_stream_find(service_t *t, int pid)
+{
+ th_stream_t *st;
+
+ lock_assert(&t->s_stream_mutex);
+
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
+ if(st->st_pid == pid)
+ return st;
+ }
+ return NULL;
+}
+
+
+
+/**
+ *
+ */
+void
+service_map_channel(service_t *t, channel_t *ch, int save)
+{
+ lock_assert(&global_lock);
+
+ if(t->s_ch != NULL) {
+ LIST_REMOVE(t, s_ch_link);
+ htsp_channel_update(t->s_ch);
+ t->s_ch = NULL;
+ }
+
+
+ if(ch != NULL) {
+
+ avgstat_init(&t->s_cc_errors, 3600);
+ avgstat_init(&t->s_rate, 10);
+
+ t->s_ch = ch;
+ LIST_INSERT_HEAD(&ch->ch_services, t, s_ch_link);
+ htsp_channel_update(t->s_ch);
+ }
+
+ if(save)
+ t->s_config_save(t);
+}
+
+/**
+ *
+ */
+static void
+service_data_timeout(void *aux)
+{
+ service_t *t = aux;
+
+ pthread_mutex_lock(&t->s_stream_mutex);
+
+ if(!(t->s_streaming_status & TSS_PACKETS))
+ service_set_streaming_status_flags(t, TSS_GRACEPERIOD);
+
+ pthread_mutex_unlock(&t->s_stream_mutex);
+}
+
+/**
+ *
+ */
+static struct strtab stypetab[] = {
+ { "SDTV", ST_SDTV },
+ { "Radio", ST_RADIO },
+ { "HDTV", ST_HDTV },
+ { "SDTV-AC", ST_AC_SDTV },
+ { "HDTV-AC", ST_AC_HDTV },
+};
+
+const char *
+service_servicetype_txt(service_t *t)
+{
+ return val2str(t->s_servicetype, stypetab) ?: "Other";
+}
+
+/**
+ *
+ */
+int
+service_is_tv(service_t *t)
+{
+ return
+ t->s_servicetype == ST_SDTV ||
+ t->s_servicetype == ST_HDTV ||
+ t->s_servicetype == ST_AC_SDTV ||
+ t->s_servicetype == ST_AC_HDTV;
+}
+
+
+/**
+ *
+ */
+void
+service_set_streaming_status_flags(service_t *t, int set)
+{
+ int n;
+ streaming_message_t *sm;
+ lock_assert(&t->s_stream_mutex);
+
+ n = t->s_streaming_status;
+
+ n |= set;
+
+ if(n == t->s_streaming_status)
+ return; // Already set
+
+ t->s_streaming_status = n;
+
+ tvhlog(LOG_DEBUG, "Service", "%s: Status changed to %s%s%s%s%s%s%s",
+ service_nicename(t),
+ n & TSS_INPUT_HARDWARE ? "[Hardware input] " : "",
+ n & TSS_INPUT_SERVICE ? "[Input on service] " : "",
+ n & TSS_MUX_PACKETS ? "[Demuxed packets] " : "",
+ n & TSS_PACKETS ? "[Reassembled packets] " : "",
+ n & TSS_NO_DESCRAMBLER ? "[No available descrambler] " : "",
+ n & TSS_NO_ACCESS ? "[No access] " : "",
+ n & TSS_GRACEPERIOD ? "[Graceperiod expired] " : "");
+
+ sm = streaming_msg_create_code(SMT_SERVICE_STATUS,
+ t->s_streaming_status);
+ streaming_pad_deliver(&t->s_streaming_pad, sm);
+ streaming_msg_free(sm);
+
+ pthread_cond_broadcast(&t->s_tss_cond);
+}
+
+
+/**
+ * Restart output on a service.
+ * Happens if the stream composition changes.
+ * (i.e. an AC3 stream disappears, etc)
+ */
+void
+service_restart(service_t *t, int had_components)
+{
+ streaming_message_t *sm;
+ lock_assert(&t->s_stream_mutex);
+
+ if(had_components) {
+ sm = streaming_msg_create_code(SMT_STOP, SM_CODE_SOURCE_RECONFIGURED);
+ streaming_pad_deliver(&t->s_streaming_pad, sm);
+ streaming_msg_free(sm);
+ }
+
+ if(t->s_refresh_feed != NULL)
+ t->s_refresh_feed(t);
+
+ if(TAILQ_FIRST(&t->s_components) != NULL) {
+
+ sm = streaming_msg_create_data(SMT_START,
+ service_build_stream_start(t));
+ streaming_pad_deliver(&t->s_streaming_pad, sm);
+ streaming_msg_free(sm);
+ }
+}
+
+
+/**
+ * Generate a message containing info about all components
+ */
+streaming_start_t *
+service_build_stream_start(service_t *t)
+{
+ th_stream_t *st;
+ int n = 0;
+ streaming_start_t *ss;
+
+ lock_assert(&t->s_stream_mutex);
+
+ TAILQ_FOREACH(st, &t->s_components, st_link)
+ n++;
+
+ ss = calloc(1, sizeof(streaming_start_t) +
+ sizeof(streaming_start_component_t) * n);
+
+ ss->ss_num_components = n;
+
+ n = 0;
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
+ streaming_start_component_t *ssc = &ss->ss_components[n++];
+ ssc->ssc_index = st->st_index;
+ ssc->ssc_type = st->st_type;
+ memcpy(ssc->ssc_lang, st->st_lang, 4);
+ ssc->ssc_composition_id = st->st_composition_id;
+ ssc->ssc_ancillary_id = st->st_ancillary_id;
+ ssc->ssc_pid = st->st_pid;
+ ssc->ssc_width = st->st_width;
+ ssc->ssc_height = st->st_height;
+ }
+
+ t->s_setsourceinfo(t, &ss->ss_si);
+
+ ss->ss_refcount = 1;
+ ss->ss_pcr_pid = t->s_pcr_pid;
+ return ss;
+}
+
+
+/**
+ *
+ */
+void
+service_set_enable(service_t *t, int enabled)
+{
+ if(t->s_enabled == enabled)
+ return;
+
+ t->s_enabled = enabled;
+ t->s_config_save(t);
+ subscription_reschedule();
+}
+
+
+static pthread_mutex_t pending_save_mutex;
+static pthread_cond_t pending_save_cond;
+static struct service_queue pending_save_queue;
+
+/**
+ *
+ */
+void
+service_request_save(service_t *t, int restart)
+{
+ pthread_mutex_lock(&pending_save_mutex);
+
+ if(!t->s_ps_onqueue) {
+ t->s_ps_onqueue = 1 + !!restart;
+ TAILQ_INSERT_TAIL(&pending_save_queue, t, s_ps_link);
+ service_ref(t);
+ pthread_cond_signal(&pending_save_cond);
+ } else if(restart) {
+ t->s_ps_onqueue = 2; // upgrade to restart too
+ }
+
+ pthread_mutex_unlock(&pending_save_mutex);
+}
+
+
+/**
+ *
+ */
+static void *
+service_saver(void *aux)
+{
+ service_t *t;
+ int restart;
+ pthread_mutex_lock(&pending_save_mutex);
+
+ while(1) {
+
+ if((t = TAILQ_FIRST(&pending_save_queue)) == NULL) {
+ pthread_cond_wait(&pending_save_cond, &pending_save_mutex);
+ continue;
+ }
+ assert(t->s_ps_onqueue != 0);
+ restart = t->s_ps_onqueue == 2;
+
+ TAILQ_REMOVE(&pending_save_queue, t, s_ps_link);
+ t->s_ps_onqueue = 0;
+
+ pthread_mutex_unlock(&pending_save_mutex);
+ pthread_mutex_lock(&global_lock);
+
+ if(t->s_status != SERVICE_ZOMBIE)
+ t->s_config_save(t);
+ if(t->s_status == SERVICE_RUNNING && restart) {
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_restart(t, 1);
+ pthread_mutex_unlock(&t->s_stream_mutex);
+ }
+ service_unref(t);
+
+ pthread_mutex_unlock(&global_lock);
+ pthread_mutex_lock(&pending_save_mutex);
+ }
+ return NULL;
+}
+
+
+/**
+ *
+ */
+void
+service_init(void)
+{
+ pthread_t tid;
+ TAILQ_INIT(&pending_save_queue);
+ pthread_mutex_init(&pending_save_mutex, NULL);
+ pthread_cond_init(&pending_save_cond, NULL);
+ pthread_create(&tid, NULL, service_saver, NULL);
+}
+
+
+/**
+ *
+ */
+void
+service_source_info_free(struct source_info *si)
+{
+ free(si->si_device);
+ free(si->si_adapter);
+ free(si->si_network);
+ free(si->si_mux);
+ free(si->si_provider);
+ free(si->si_service);
+}
+
+
+void
+service_source_info_copy(source_info_t *dst, const source_info_t *src)
+{
+#define COPY(x) dst->si_##x = src->si_##x ? strdup(src->si_##x) : NULL
+ COPY(device);
+ COPY(adapter);
+ COPY(network);
+ COPY(mux);
+ COPY(provider);
+ COPY(service);
+#undef COPY
+}
+
+
+/**
+ *
+ */
+const char *
+service_nicename(service_t *t)
+{
+ return t->s_nicename;
+}
+
+const char *
+service_component_nicename(th_stream_t *st)
+{
+ return st->st_nicename;
+}
+
+const char *
+service_tss2text(int flags)
+{
+ if(flags & TSS_NO_ACCESS)
+ return "No access";
+
+ if(flags & TSS_NO_DESCRAMBLER)
+ return "No descrambler";
+
+ if(flags & TSS_PACKETS)
+ return "Got valid packets";
+
+ if(flags & TSS_MUX_PACKETS)
+ return "Got multiplexed packets but could not decode further";
+
+ if(flags & TSS_INPUT_SERVICE)
+ return "Got packets for this service but could not decode further";
+
+ if(flags & TSS_INPUT_HARDWARE)
+ return "Sensed input from hardware but nothing for the service";
+
+ if(flags & TSS_GRACEPERIOD)
+ return "No input detected";
+
+ return "No status";
+}
+
+
+/**
+ *
+ */
+int
+tss2errcode(int tss)
+{
+ if(tss & TSS_NO_ACCESS)
+ return SM_CODE_NO_ACCESS;
+
+ if(tss & TSS_NO_DESCRAMBLER)
+ return SM_CODE_NO_DESCRAMBLER;
+
+ if(tss & TSS_GRACEPERIOD)
+ return SM_CODE_NO_INPUT;
+
+ return SM_CODE_OK;
+}
+
+
+/**
+ *
+ */
+void
+service_refresh_channel(service_t *t)
+{
+ if(t->s_ch != NULL)
+ htsp_channel_update(t->s_ch);
+}
+
+
+/**
+ * Get the encryption CAID from a service
+ * only the first CA stream in a service is returned
+ */
+uint16_t
+service_get_encryption(service_t *t)
+{
+ th_stream_t *st;
+ caid_t *c;
+
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
+ switch(st->st_type) {
+ case SCT_CA:
+ LIST_FOREACH(c, &st->st_caids, link)
+ if(c->caid != 0)
+ return c->caid;
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Get the signal status from a service
+ */
+int
+service_get_signal_status(service_t *t, signal_status_t *status)
+{
+ // get signal status from the service
+ switch(t->s_type) {
+ case SERVICE_TYPE_DVB:
+ return dvb_transport_get_signal_status(t, status);
+ default:
+ return -1;
+ }
+}
+
#include "channels.h"
#include "subscriptions.h"
#include "serviceprobe.h"
-#include "transports.h"
#include "streaming.h"
-
+#include "service.h"
/* List of transports to be probed, protected with global_lock */
-static struct th_transport_queue serviceprobe_queue;
+static struct service_queue serviceprobe_queue;
static pthread_cond_t serviceprobe_cond;
/**
*
*/
void
-serviceprobe_enqueue(th_transport_t *t)
+serviceprobe_enqueue(service_t *t)
{
- if(!transport_is_tv(t))
+ if(!service_is_tv(t))
return; /* Don't even consider non-tv channels */
- if(t->tht_sp_onqueue)
+ if(t->s_sp_onqueue)
return;
- if(t->tht_ch != NULL)
+ if(t->s_ch != NULL)
return; /* Already mapped */
- t->tht_sp_onqueue = 1;
- TAILQ_INSERT_TAIL(&serviceprobe_queue, t, tht_sp_link);
+ t->s_sp_onqueue = 1;
+ TAILQ_INSERT_TAIL(&serviceprobe_queue, t, s_sp_link);
pthread_cond_signal(&serviceprobe_cond);
}
*
*/
void
-serviceprobe_delete(th_transport_t *t)
+serviceprobe_delete(service_t *t)
{
- if(!t->tht_sp_onqueue)
+ if(!t->s_sp_onqueue)
return;
- TAILQ_REMOVE(&serviceprobe_queue, t, tht_sp_link);
- t->tht_sp_onqueue = 0;
+ TAILQ_REMOVE(&serviceprobe_queue, t, s_sp_link);
+ t->s_sp_onqueue = 0;
}
static void *
serviceprobe_thread(void *aux)
{
- th_transport_t *t;
+ service_t *t;
th_subscription_t *s;
int was_doing_work = 0;
streaming_queue_t sq;
}
tvhlog(LOG_INFO, "serviceprobe", "%20s: checking...",
- t->tht_svcname);
+ t->s_svcname);
- s = subscription_create_from_transport(t, "serviceprobe", &sq.sq_st, 0);
+ s = subscription_create_from_service(t, "serviceprobe", &sq.sq_st, 0);
if(s == NULL) {
- t->tht_sp_onqueue = 0;
- TAILQ_REMOVE(&serviceprobe_queue, t, tht_sp_link);
+ t->s_sp_onqueue = 0;
+ TAILQ_REMOVE(&serviceprobe_queue, t, s_sp_link);
tvhlog(LOG_INFO, "serviceprobe", "%20s: could not subscribe",
- t->tht_svcname);
+ t->s_svcname);
continue;
}
- transport_ref(t);
+ service_ref(t);
pthread_mutex_unlock(&global_lock);
run = 1;
pthread_mutex_unlock(&sq.sq_mutex);
- if(sm->sm_type == SMT_TRANSPORT_STATUS) {
+ if(sm->sm_type == SMT_SERVICE_STATUS) {
int status = sm->sm_code;
if(status & TSS_PACKETS) {
err = NULL;
} else if(status & (TSS_GRACEPERIOD | TSS_ERRORS)) {
run = 0;
- err = transport_tss2text(status);
+ err = service_tss2text(status);
}
}
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
- if(t->tht_status != TRANSPORT_ZOMBIE) {
+ if(t->s_status != SERVICE_ZOMBIE) {
if(err != NULL) {
tvhlog(LOG_INFO, "serviceprobe", "%20s: skipped: %s",
- t->tht_svcname, err);
- } else if(t->tht_ch == NULL) {
+ t->s_svcname, err);
+ } else if(t->s_ch == NULL) {
const char *str;
- ch = channel_find_by_name(t->tht_svcname, 1, t->tht_channel_number);
- transport_map_channel(t, ch, 1);
+ ch = channel_find_by_name(t->s_svcname, 1, t->s_channel_number);
+ service_map_channel(t, ch, 1);
tvhlog(LOG_INFO, "serviceprobe", "%20s: mapped to channel \"%s\"",
- t->tht_svcname, t->tht_svcname);
+ t->s_svcname, t->s_svcname);
channel_tag_map(ch, channel_tag_find_by_name("TV channels", 1), 1);
tvhlog(LOG_INFO, "serviceprobe", "%20s: joined tag \"%s\"",
- t->tht_svcname, "TV channels");
+ t->s_svcname, "TV channels");
- switch(t->tht_servicetype) {
+ switch(t->s_servicetype) {
case ST_SDTV:
case ST_AC_SDTV:
str = "SDTV";
if(str != NULL) {
channel_tag_map(ch, channel_tag_find_by_name(str, 1), 1);
tvhlog(LOG_INFO, "serviceprobe", "%20s: joined tag \"%s\"",
- t->tht_svcname, str);
+ t->s_svcname, str);
}
- if(t->tht_provider != NULL) {
- channel_tag_map(ch, channel_tag_find_by_name(t->tht_provider, 1), 1);
+ if(t->s_provider != NULL) {
+ channel_tag_map(ch, channel_tag_find_by_name(t->s_provider, 1), 1);
tvhlog(LOG_INFO, "serviceprobe", "%20s: joined tag \"%s\"",
- t->tht_svcname, t->tht_provider);
+ t->s_svcname, t->s_provider);
}
channel_save(ch);
}
- t->tht_sp_onqueue = 0;
- TAILQ_REMOVE(&serviceprobe_queue, t, tht_sp_link);
+ t->s_sp_onqueue = 0;
+ TAILQ_REMOVE(&serviceprobe_queue, t, s_sp_link);
}
- transport_unref(t);
+ service_unref(t);
}
return NULL;
}
void serviceprobe_init(void);
-void serviceprobe_enqueue(th_transport_t *t);
+void serviceprobe_enqueue(struct service *t);
-void serviceprobe_delete(th_transport_t *t);
+void serviceprobe_delete(struct service *t);
#endif /* SERVICEPROBE_H_ */
#include "streaming.h"
#include "packet.h"
#include "atomic.h"
-#include "transports.h"
+#include "service.h"
void
streaming_pad_init(streaming_pad_t *sp)
break;
case SMT_STOP:
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
case SMT_NOSTART:
dst->sm_code = src->sm_code;
break;
if((atomic_add(&ss->ss_refcount, -1)) != 1)
return;
- transport_source_info_free(&ss->ss_si);
+ service_source_info_free(&ss->ss_si);
for(i = 0; i < ss->ss_num_components; i++)
if(ss->ss_components[i].ssc_gh)
pktbuf_ref_dec(ss->ss_components[i].ssc_gh);
case SMT_EXIT:
break;
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
break;
case SMT_NOSTART:
return "Too bad signal quality";
case SM_CODE_NO_SOURCE:
return "No source available";
- case SM_CODE_NO_TRANSPORT:
- return "No transport assigned to channel";
+ case SM_CODE_NO_SERVICE:
+ return "No service assigned to channel";
case SM_CODE_ABORTED:
return "Aborted by user";
streaming_start_t *dst = malloc(siz);
memcpy(dst, src, siz);
- transport_source_info_copy(&dst->ss_si, &src->ss_si);
+ service_source_info_copy(&dst->ss_si, &src->ss_si);
for(i = 0; i < dst->ss_num_components; i++) {
streaming_start_component_t *ssc = &dst->ss_components[i];
#include <string.h>
#include "tvheadend.h"
-#include "transports.h"
#include "subscriptions.h"
#include "streaming.h"
+#include "channels.h"
+#include "service.h"
struct th_subscription_list subscriptions;
static gtimer_t subscription_reschedule_timer;
/**
- * The transport is producing output.
+ * The service is producing output.
*/
static void
-subscription_link_transport(th_subscription_t *s, th_transport_t *t)
+subscription_link_service(th_subscription_t *s, service_t *t)
{
streaming_message_t *sm;
- s->ths_state = SUBSCRIPTION_TESTING_TRANSPORT;
+ s->ths_state = SUBSCRIPTION_TESTING_SERVICE;
- s->ths_transport = t;
- LIST_INSERT_HEAD(&t->tht_subscriptions, s, ths_transport_link);
+ s->ths_service = t;
+ LIST_INSERT_HEAD(&t->s_subscriptions, s, ths_service_link);
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
- if(TAILQ_FIRST(&t->tht_components) != NULL)
+ if(TAILQ_FIRST(&t->s_components) != NULL)
s->ths_start_message =
- streaming_msg_create_data(SMT_START, transport_build_stream_start(t));
+ streaming_msg_create_data(SMT_START, service_build_stream_start(t));
- // Link to transport output
- streaming_target_connect(&t->tht_streaming_pad, &s->ths_input);
+ // Link to service output
+ streaming_target_connect(&t->s_streaming_pad, &s->ths_input);
- if(s->ths_start_message != NULL && t->tht_streaming_status & TSS_PACKETS) {
+ if(s->ths_start_message != NULL && t->s_streaming_status & TSS_PACKETS) {
- s->ths_state = SUBSCRIPTION_GOT_TRANSPORT;
+ s->ths_state = SUBSCRIPTION_GOT_SERVICE;
// Send a START message to the subscription client
streaming_target_deliver(s->ths_output, s->ths_start_message);
s->ths_start_message = NULL;
// Send status report
- sm = streaming_msg_create_code(SMT_TRANSPORT_STATUS,
- t->tht_streaming_status);
+ sm = streaming_msg_create_code(SMT_SERVICE_STATUS,
+ t->s_streaming_status);
streaming_target_deliver(s->ths_output, sm);
}
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
/**
- * Called from transport code
+ * Called from service code
*/
void
-subscription_unlink_transport(th_subscription_t *s, int reason)
+subscription_unlink_service(th_subscription_t *s, int reason)
{
streaming_message_t *sm;
- th_transport_t *t = s->ths_transport;
+ service_t *t = s->ths_service;
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
- // Unlink from transport output
- streaming_target_disconnect(&t->tht_streaming_pad, &s->ths_input);
+ // Unlink from service output
+ streaming_target_disconnect(&t->s_streaming_pad, &s->ths_input);
- if(TAILQ_FIRST(&t->tht_components) != NULL &&
- s->ths_state == SUBSCRIPTION_GOT_TRANSPORT) {
+ if(TAILQ_FIRST(&t->s_components) != NULL &&
+ s->ths_state == SUBSCRIPTION_GOT_SERVICE) {
// Send a STOP message to the subscription client
sm = streaming_msg_create_code(SMT_STOP, reason);
streaming_target_deliver(s->ths_output, sm);
}
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
- LIST_REMOVE(s, ths_transport_link);
- s->ths_transport = NULL;
+ LIST_REMOVE(s, ths_service_link);
+ s->ths_service = NULL;
}
subscription_reschedule(void)
{
th_subscription_t *s;
- th_transport_t *t, *skip;
+ service_t *t, *skip;
streaming_message_t *sm;
char buf[128];
int error;
if(s->ths_channel == NULL)
continue; /* stale entry, channel has been destroyed */
- if(s->ths_transport != NULL) {
- /* Already got a transport */
+ if(s->ths_service != NULL) {
+ /* Already got a service */
- if(s->ths_state != SUBSCRIPTION_BAD_TRANSPORT)
+ if(s->ths_state != SUBSCRIPTION_BAD_SERVICE)
continue; /* And it seems to work ok, so we're happy */
- skip = s->ths_transport;
+ skip = s->ths_service;
error = s->ths_testing_error;
- transport_remove_subscriber(s->ths_transport, s, s->ths_testing_error);
+ service_remove_subscriber(s->ths_service, s, s->ths_testing_error);
} else {
error = 0;
skip = NULL;
}
snprintf(buf, sizeof(buf), "Subscription \"%s\"", s->ths_title);
- t = transport_find(s->ths_channel, s->ths_weight, buf, &error, skip);
+ t = service_find(s->ths_channel, s->ths_weight, buf, &error, skip);
if(t == NULL) {
- /* No transport available */
+ /* No service available */
sm = streaming_msg_create_code(SMT_NOSTART, error);
streaming_target_deliver(s->ths_output, sm);
continue;
}
- subscription_link_transport(s, t);
+ subscription_link_service(s, t);
}
}
void
subscription_unsubscribe(th_subscription_t *s)
{
- th_transport_t *t = s->ths_transport;
+ service_t *t = s->ths_service;
lock_assert(&global_lock);
}
if(t != NULL)
- transport_remove_subscriber(t, s, SM_CODE_OK);
+ service_remove_subscriber(t, s, SM_CODE_OK);
if(s->ths_start_message != NULL)
streaming_msg_free(s->ths_start_message);
/**
* This callback is invoked when we receive data and status updates from
- * the currently bound transport
+ * the currently bound service
*/
static void
subscription_input(void *opauqe, streaming_message_t *sm)
{
th_subscription_t *s = opauqe;
- if(s->ths_state == SUBSCRIPTION_TESTING_TRANSPORT) {
- // We are just testing if this transport is good
+ if(s->ths_state == SUBSCRIPTION_TESTING_SERVICE) {
+ // We are just testing if this service is good
if(sm->sm_type == SMT_START) {
if(s->ths_start_message != NULL)
return;
}
- if(sm->sm_type == SMT_TRANSPORT_STATUS &&
+ if(sm->sm_type == SMT_SERVICE_STATUS &&
sm->sm_code & (TSS_GRACEPERIOD | TSS_ERRORS)) {
- // No, mark our subscription as bad_transport
+ // No, mark our subscription as bad_service
// the scheduler will take care of things
s->ths_testing_error = tss2errcode(sm->sm_code);
- s->ths_state = SUBSCRIPTION_BAD_TRANSPORT;
+ s->ths_state = SUBSCRIPTION_BAD_SERVICE;
streaming_msg_free(sm);
return;
}
- if(sm->sm_type == SMT_TRANSPORT_STATUS &&
+ if(sm->sm_type == SMT_SERVICE_STATUS &&
sm->sm_code & TSS_PACKETS) {
if(s->ths_start_message != NULL) {
streaming_target_deliver(s->ths_output, s->ths_start_message);
s->ths_start_message = NULL;
}
- s->ths_state = SUBSCRIPTION_GOT_TRANSPORT;
+ s->ths_state = SUBSCRIPTION_GOT_SERVICE;
}
}
- if(s->ths_state != SUBSCRIPTION_GOT_TRANSPORT) {
+ if(s->ths_state != SUBSCRIPTION_GOT_SERVICE) {
streaming_msg_free(sm);
return;
}
s->ths_channel = ch;
LIST_INSERT_HEAD(&ch->ch_subscriptions, s, ths_channel_link);
- s->ths_transport = NULL;
+ s->ths_service = NULL;
subscription_reschedule();
- if(s->ths_transport == NULL) {
+ if(s->ths_service == NULL) {
tvhlog(LOG_NOTICE, "subscription",
"No transponder available for subscription \"%s\" "
"to channel \"%s\"",
} else {
source_info_t si;
- s->ths_transport->tht_setsourceinfo(s->ths_transport, &si);
+ s->ths_service->s_setsourceinfo(s->ths_service, &si);
tvhlog(LOG_INFO, "subscription",
"\"%s\" subscribing on \"%s\", weight: %d, adapter: \"%s\", "
si.si_mux ?: "<N/A>",
si.si_provider ?: "<N/A>",
si.si_service ?: "<N/A>",
- s->ths_transport->tht_quality_index(s->ths_transport));
+ s->ths_service->s_quality_index(s->ths_service));
- transport_source_info_free(&si);
+ service_source_info_free(&si);
}
return s;
}
*
*/
th_subscription_t *
-subscription_create_from_transport(th_transport_t *t, const char *name,
+subscription_create_from_service(service_t *t, const char *name,
streaming_target_t *st, int flags)
{
th_subscription_t *s = subscription_create(INT32_MAX, name, st, flags, 1);
source_info_t si;
int r;
- if(t->tht_status != TRANSPORT_RUNNING) {
- if((r = transport_start(t, INT32_MAX, 1)) != 0) {
+ if(t->s_status != SERVICE_RUNNING) {
+ if((r = service_start(t, INT32_MAX, 1)) != 0) {
subscription_unsubscribe(s);
tvhlog(LOG_INFO, "subscription",
}
}
- t->tht_setsourceinfo(t, &si);
+ t->s_setsourceinfo(t, &si);
tvhlog(LOG_INFO, "subscription",
"\"%s\" direct subscription to adapter: \"%s\", "
si.si_mux ?: "<N/A>",
si.si_provider ?: "<N/A>",
si.si_service ?: "<N/A>",
- t->tht_quality_index(t));
- transport_source_info_free(&si);
+ t->s_quality_index(t));
+ service_source_info_free(&si);
- subscription_link_transport(s, t);
+ subscription_link_service(s, t);
return s;
}
fprintf(stderr, "dummysubscription STOP\n");
break;
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
fprintf(stderr, "dummsubscription: %x\n", sm->sm_code);
break;
default:
void
subscription_dummy_join(const char *id, int first)
{
- th_transport_t *t = transport_find_by_identifier(id);
+ service_t *t = service_find_by_identifier(id);
streaming_target_t *st;
if(first) {
if(t == NULL) {
tvhlog(LOG_ERR, "subscription",
- "Unable to dummy join %s, transport not found, retrying...", id);
+ "Unable to dummy join %s, service not found, retrying...", id);
gtimer_arm(&dummy_sub_timer, dummy_retry, strdup(id), 1);
return;
st = calloc(1, sizeof(streaming_target_t));
streaming_target_init(st, dummy_callback, NULL, 0);
- subscription_create_from_transport(t, "dummy", st, 0);
+ subscription_create_from_service(t, "dummy", st, 0);
tvhlog(LOG_NOTICE, "subscription",
"Dummy join %s ok", id);
enum {
SUBSCRIPTION_IDLE,
- SUBSCRIPTION_TESTING_TRANSPORT,
- SUBSCRIPTION_GOT_TRANSPORT,
- SUBSCRIPTION_BAD_TRANSPORT,
+ SUBSCRIPTION_TESTING_SERVICE,
+ SUBSCRIPTION_GOT_SERVICE,
+ SUBSCRIPTION_BAD_SERVICE,
} ths_state;
int ths_testing_error;
destroyed during the
subscription */
- LIST_ENTRY(th_subscription) ths_transport_link;
- struct th_transport *ths_transport; /* if NULL, ths_transport_link
+ LIST_ENTRY(th_subscription) ths_service_link;
+ struct service *ths_service; /* if NULL, ths_service_link
is not linked */
char *ths_title; /* display title */
void subscription_reschedule(void);
-th_subscription_t *subscription_create_from_channel(channel_t *ch,
+th_subscription_t *subscription_create_from_channel(struct channel *ch,
unsigned int weight,
const char *name,
streaming_target_t *st,
int flags);
-th_subscription_t *subscription_create_from_transport(th_transport_t *t,
- const char *name,
- streaming_target_t *st,
- int flags);
+th_subscription_t *subscription_create_from_service(struct service *t,
+ const char *name,
+ streaming_target_t *st,
+ int flags);
void subscription_change_weight(th_subscription_t *s, int weight);
void subscription_stop(th_subscription_t *s);
-void subscription_unlink_transport(th_subscription_t *s, int reason);
+void subscription_unlink_service(th_subscription_t *s, int reason);
void subscription_dummy_join(const char *id, int first);
#include "tvheadend.h"
#include "teletext.h"
-#include "transports.h"
#include "packet.h"
#include "streaming.h"
+#include "service.h"
/**
*
static void teletext_rundown_copy(tt_private_t *ttp, tt_mag_t *ttm);
-static void teletext_rundown_scan(th_transport_t *t, tt_private_t *ttp);
+static void teletext_rundown_scan(service_t *t, tt_private_t *ttp);
#define bitreverse(b) \
(((b) * 0x0202020202ULL & 0x010884422010ULL) % 1023)
*
*/
static int
-update_tt_clock(th_transport_t *t, const uint8_t *buf)
+update_tt_clock(service_t *t, const uint8_t *buf)
{
uint8_t str[10];
int i;
return 0;
ti = tt_construct_unix_time(str);
- if(t->tht_tt_clock == ti)
+ if(t->s_tt_clock == ti)
return 0;
- t->tht_tt_clock = ti;
+ t->s_tt_clock = ti;
// printf("teletext clock is: %s", ctime(&ti));
return 1;
}
static void
-extract_subtitle(th_transport_t *t, th_stream_t *st,
+extract_subtitle(service_t *t, th_stream_t *st,
tt_mag_t *ttm, int64_t pts)
{
int i, j, off = 0;
pkt->pkt_componentindex = st->st_index;
streaming_message_t *sm = streaming_msg_create_pkt(pkt);
- streaming_pad_deliver(&t->tht_streaming_pad, sm);
+ streaming_pad_deliver(&t->s_streaming_pad, sm);
streaming_msg_free(sm);
/* Decrease our own reference to the packet */
static void
-tt_subtitle_deliver(th_transport_t *t, th_stream_t *parent, tt_mag_t *ttm)
+tt_subtitle_deliver(service_t *t, th_stream_t *parent, tt_mag_t *ttm)
{
th_stream_t *st;
if(ttm->ttm_current_pts == PTS_UNSET)
return;
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
if(parent->st_pid == st->st_parent_pid &&
ttm->ttm_curpage == st->st_pid - PID_TELETEXT_BASE) {
extract_subtitle(t, st, ttm, ttm->ttm_current_pts);
*
*/
static void
-tt_decode_line(th_transport_t *t, th_stream_t *st, uint8_t *buf)
+tt_decode_line(service_t *t, th_stream_t *st, uint8_t *buf)
{
uint8_t mpag, line, s12, s34, c;
int page, magidx, i;
if(update_tt_clock(t, buf + 34))
teletext_rundown_scan(t, ttp);
- ttm->ttm_current_pts = t->tht_current_pts;
+ ttm->ttm_current_pts = t->s_current_pts;
ttm->ttm_inactive = 0;
break;
*
*/
static void
-teletext_scan_stream(th_transport_t *t, th_stream_t *st)
+teletext_scan_stream(service_t *t, th_stream_t *st)
{
tt_private_t *ttp = st->st_priv;
tt_mag_t *ttm;
*
*/
void
-teletext_input(th_transport_t *t, th_stream_t *st, const uint8_t *tsb)
+teletext_input(service_t *t, th_stream_t *st, const uint8_t *tsb)
{
int i, j;
const uint8_t *x;
static void
-teletext_rundown_scan(th_transport_t *t, tt_private_t *ttp)
+teletext_rundown_scan(service_t *t, tt_private_t *ttp)
{
int i;
uint8_t *l;
- time_t now = t->tht_tt_clock, start, stop, last = 0;
+ time_t now = t->s_tt_clock, start, stop, last = 0;
th_commercial_advice_t ca;
if(ttp->ttp_rundown_valid == 0)
stop = start + tt_time_to_len(l + 32);
if(start <= now && stop > now)
- t->tht_tt_commercial_advice = ca;
+ t->s_tt_commercial_advice = ca;
- if(start > now && ca != t->tht_tt_commercial_advice && last == 0)
+ if(start > now && ca != t->s_tt_commercial_advice && last == 0)
last = start;
}
}
#ifndef TELETEXT_H
#define TELETEXT_H
-void teletext_input(th_transport_t *t, th_stream_t *st, const uint8_t *tsb);
+void teletext_input(struct service *t, struct th_stream *st,
+ const uint8_t *tsb);
#endif /* TELETEXT_H */
+++ /dev/null
-/*
- * tvheadend, transport and subscription functions
- * Copyright (C) 2007 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 <pthread.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tvheadend.h"
-#include "transports.h"
-#include "subscriptions.h"
-#include "tsdemux.h"
-#include "streaming.h"
-#include "v4l.h"
-#include "psi.h"
-#include "packet.h"
-#include "channels.h"
-#include "cwc.h"
-#include "capmt.h"
-#include "notify.h"
-#include "serviceprobe.h"
-#include "atomic.h"
-#include "dvb/dvb.h"
-#include "htsp.h"
-
-#define TRANSPORT_HASH_WIDTH 101
-
-static struct th_transport_list transporthash[TRANSPORT_HASH_WIDTH];
-
-static void transport_data_timeout(void *aux);
-
-/**
- *
- */
-static void
-stream_init(th_stream_t *st)
-{
- st->st_cc_valid = 0;
-
- st->st_startcond = 0xffffffff;
- st->st_curdts = PTS_UNSET;
- st->st_curpts = PTS_UNSET;
- st->st_prevdts = PTS_UNSET;
-
- st->st_pcr_real_last = PTS_UNSET;
- st->st_pcr_last = PTS_UNSET;
- st->st_pcr_drift = 0;
- st->st_pcr_recovery_fails = 0;
-
- st->st_blank = 0;
-}
-
-
-/**
- *
- */
-static void
-stream_clean(th_stream_t *st)
-{
- if(st->st_demuxer_fd != -1) {
- // XXX: Should be in DVB-code perhaps
- close(st->st_demuxer_fd);
- st->st_demuxer_fd = -1;
- }
-
- free(st->st_priv);
- st->st_priv = NULL;
-
- /* Clear reassembly buffers */
-
- st->st_startcode = 0;
-
- sbuf_free(&st->st_buf);
- sbuf_free(&st->st_buf_ps);
- sbuf_free(&st->st_buf_a);
-
- if(st->st_curpkt != NULL) {
- pkt_ref_dec(st->st_curpkt);
- st->st_curpkt = NULL;
- }
-
- free(st->st_global_data);
- st->st_global_data = NULL;
- st->st_global_data_len = 0;
-}
-
-
-/**
- *
- */
-void
-transport_stream_destroy(th_transport_t *t, th_stream_t *st)
-{
- if(t->tht_status == TRANSPORT_RUNNING)
- stream_clean(st);
- TAILQ_REMOVE(&t->tht_components, st, st_link);
- free(st->st_nicename);
- free(st);
-}
-
-/**
- * Transport lock must be held
- */
-static void
-transport_stop(th_transport_t *t)
-{
- th_descrambler_t *td;
- th_stream_t *st;
-
- gtimer_disarm(&t->tht_receive_timer);
-
- t->tht_stop_feed(t);
-
- pthread_mutex_lock(&t->tht_stream_mutex);
-
- while((td = LIST_FIRST(&t->tht_descramblers)) != NULL)
- td->td_stop(td);
-
- t->tht_tt_commercial_advice = COMMERCIAL_UNKNOWN;
-
- assert(LIST_FIRST(&t->tht_streaming_pad.sp_targets) == NULL);
- assert(LIST_FIRST(&t->tht_subscriptions) == NULL);
-
- /**
- * Clean up each stream
- */
- TAILQ_FOREACH(st, &t->tht_components, st_link)
- stream_clean(st);
-
- t->tht_status = TRANSPORT_IDLE;
-
- pthread_mutex_unlock(&t->tht_stream_mutex);
-}
-
-
-/**
- * Remove the given subscriber from the transport
- *
- * if s == NULL all subscribers will be removed
- *
- * Global lock must be held
- */
-void
-transport_remove_subscriber(th_transport_t *t, th_subscription_t *s,
- int reason)
-{
- lock_assert(&global_lock);
-
- if(s == NULL) {
- while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) {
- subscription_unlink_transport(s, reason);
- }
- } else {
- subscription_unlink_transport(s, reason);
- }
-
- if(LIST_FIRST(&t->tht_subscriptions) == NULL)
- transport_stop(t);
-}
-
-
-/**
- *
- */
-int
-transport_start(th_transport_t *t, unsigned int weight, int force_start)
-{
- th_stream_t *st;
- int r, timeout = 2;
-
- lock_assert(&global_lock);
-
- assert(t->tht_status != TRANSPORT_RUNNING);
- t->tht_streaming_status = 0;
- t->tht_pcr_drift = 0;
-
- if((r = t->tht_start_feed(t, weight, force_start)))
- return r;
-
- cwc_transport_start(t);
- capmt_transport_start(t);
-
- pthread_mutex_lock(&t->tht_stream_mutex);
-
- t->tht_status = TRANSPORT_RUNNING;
- t->tht_current_pts = PTS_UNSET;
-
- /**
- * Initialize stream
- */
- TAILQ_FOREACH(st, &t->tht_components, st_link)
- stream_init(st);
-
- pthread_mutex_unlock(&t->tht_stream_mutex);
-
- if(t->tht_grace_period != NULL)
- timeout = t->tht_grace_period(t);
-
- gtimer_arm(&t->tht_receive_timer, transport_data_timeout, t, timeout);
- return 0;
-}
-
-/**
- *
- */
-static int
-dvb_extra_prio(th_dvb_adapter_t *tda)
-{
- return tda->tda_hostconnection * 10;
-}
-
-/**
- * Return prio for the given transport
- */
-static int
-transport_get_prio(th_transport_t *t)
-{
- switch(t->tht_type) {
- case TRANSPORT_DVB:
- return (t->tht_scrambled ? 300 : 100) +
- dvb_extra_prio(t->tht_dvb_mux_instance->tdmi_adapter);
-
- case TRANSPORT_IPTV:
- return 200;
-
- case TRANSPORT_V4L:
- return 400;
-
- default:
- return 500;
- }
-}
-
-/**
- * Return quality index for given transport
- *
- * We invert the result (providers say that negative numbers are worse)
- *
- * But for sorting, we want low numbers first
- *
- * Also, we bias and trim with an offset of two to avoid counting any
- * transient errors.
- */
-
-static int
-transport_get_quality(th_transport_t *t)
-{
- return t->tht_quality_index ? -MIN(t->tht_quality_index(t) + 2, 0) : 0;
-}
-
-
-
-
-/**
- * a - b -> lowest number first
- */
-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;
-
- int q = transport_get_quality(a) - transport_get_quality(b);
-
- if(q != 0)
- return q; /* Quality precedes priority */
-
- return transport_get_prio(a) - transport_get_prio(b);
-}
-
-
-/**
- *
- */
-th_transport_t *
-transport_find(channel_t *ch, unsigned int weight, const char *loginfo,
- int *errorp, th_transport_t *skip)
-{
- th_transport_t *t, **vec;
- int cnt = 0, i, r, off;
- int err = 0;
-
- lock_assert(&global_lock);
-
- /* First, sort all transports in order */
-
- LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
- cnt++;
-
- vec = alloca(cnt * sizeof(th_transport_t *));
- cnt = 0;
- LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) {
-
- if(!t->tht_enabled) {
- if(loginfo != NULL) {
- tvhlog(LOG_NOTICE, "Transport", "%s: Skipping \"%s\" -- not enabled",
- loginfo, transport_nicename(t));
- err = SM_CODE_SVC_NOT_ENABLED;
- }
- continue;
- }
-
- if(t->tht_quality_index(t) < 10) {
- if(loginfo != NULL) {
- tvhlog(LOG_NOTICE, "Transport",
- "%s: Skipping \"%s\" -- Quality below 10%",
- loginfo, transport_nicename(t));
- err = SM_CODE_BAD_SIGNAL;
- }
- continue;
- }
- vec[cnt++] = t;
- }
-
- /* Sort transports, lower priority should come come earlier in the vector
- (i.e. it will be more favoured when selecting a transport */
-
- qsort(vec, cnt, sizeof(th_transport_t *), transportcmp);
-
- // Skip up to the transport that the caller didn't want
- // If the sorting above is not stable that might mess up things
- // temporary. But it should resolve itself eventually
- if(skip != NULL) {
- for(i = 0; i < cnt; i++) {
- if(skip == t)
- break;
- }
- off = i + 1;
- } else {
- off = 0;
- }
-
- /* First, try all transports without stealing */
- for(i = off; i < cnt; i++) {
- t = vec[i];
- if(t->tht_status == TRANSPORT_RUNNING)
- return t;
- if((r = transport_start(t, 0, 0)) == 0)
- return t;
- if(loginfo != NULL)
- tvhlog(LOG_DEBUG, "Transport", "%s: Unable to use \"%s\" -- %s",
- loginfo, transport_nicename(t), streaming_code2txt(r));
- }
-
- /* Ok, nothing, try again, but supply our weight and thus, try to steal
- transponders */
-
- for(i = off; i < cnt; i++) {
- t = vec[i];
- if((r = transport_start(t, weight, 0)) == 0)
- return t;
- *errorp = r;
- }
- if(err)
- *errorp = err;
- else if(*errorp == 0)
- *errorp = SM_CODE_NO_TRANSPORT;
- return NULL;
-}
-
-
-/**
- *
- */
-unsigned int
-transport_compute_weight(struct th_transport_list *head)
-{
- th_transport_t *t;
- th_subscription_t *s;
- int w = 0;
-
- lock_assert(&global_lock);
-
- LIST_FOREACH(t, head, tht_active_link) {
- LIST_FOREACH(s, &t->tht_subscriptions, ths_transport_link) {
- if(s->ths_weight > w)
- w = s->ths_weight;
- }
- }
- return w;
-}
-
-
-/**
- *
- */
-void
-transport_unref(th_transport_t *t)
-{
- if((atomic_add(&t->tht_refcount, -1)) == 1)
- free(t);
-}
-
-
-/**
- *
- */
-void
-transport_ref(th_transport_t *t)
-{
- atomic_add(&t->tht_refcount, 1);
-}
-
-
-
-/**
- * Destroy a transport
- */
-void
-transport_destroy(th_transport_t *t)
-{
- th_stream_t *st;
- th_subscription_t *s;
- channel_t *ch = t->tht_ch;
-
- if(t->tht_dtor != NULL)
- t->tht_dtor(t);
-
- lock_assert(&global_lock);
-
- serviceprobe_delete(t);
-
- while((s = LIST_FIRST(&t->tht_subscriptions)) != NULL) {
- subscription_unlink_transport(s, SM_CODE_SOURCE_DELETED);
- }
-
- if(t->tht_ch != NULL) {
- t->tht_ch = NULL;
- LIST_REMOVE(t, tht_ch_link);
- }
-
- LIST_REMOVE(t, tht_group_link);
- LIST_REMOVE(t, tht_hash_link);
-
- if(t->tht_status != TRANSPORT_IDLE)
- transport_stop(t);
-
- t->tht_status = TRANSPORT_ZOMBIE;
-
- free(t->tht_identifier);
- free(t->tht_svcname);
- free(t->tht_provider);
-
- while((st = TAILQ_FIRST(&t->tht_components)) != NULL) {
- TAILQ_REMOVE(&t->tht_components, st, st_link);
- free(st->st_nicename);
- free(st);
- }
-
- free(t->tht_pat_section);
- free(t->tht_pmt_section);
-
- transport_unref(t);
-
- if(ch != NULL) {
- if(LIST_FIRST(&ch->ch_transports) == NULL)
- channel_delete(ch);
- }
-}
-
-
-/**
- * Create and initialize a new transport struct
- */
-th_transport_t *
-transport_create(const char *identifier, int type, int source_type)
-{
- unsigned int hash = tvh_strhash(identifier, TRANSPORT_HASH_WIDTH);
- th_transport_t *t = calloc(1, sizeof(th_transport_t));
-
- lock_assert(&global_lock);
-
- pthread_mutex_init(&t->tht_stream_mutex, NULL);
- pthread_cond_init(&t->tht_tss_cond, NULL);
- t->tht_identifier = strdup(identifier);
- t->tht_type = type;
- t->tht_source_type = source_type;
- t->tht_refcount = 1;
- t->tht_enabled = 1;
- t->tht_pcr_last = PTS_UNSET;
- TAILQ_INIT(&t->tht_components);
-
- streaming_pad_init(&t->tht_streaming_pad);
-
- LIST_INSERT_HEAD(&transporthash[hash], t, tht_hash_link);
- return t;
-}
-
-/**
- * Find a transport based on the given identifier
- */
-th_transport_t *
-transport_find_by_identifier(const char *identifier)
-{
- th_transport_t *t;
- unsigned int hash = tvh_strhash(identifier, TRANSPORT_HASH_WIDTH);
-
- lock_assert(&global_lock);
-
- LIST_FOREACH(t, &transporthash[hash], tht_hash_link)
- if(!strcmp(t->tht_identifier, identifier))
- break;
- return t;
-}
-
-
-/**
- *
- */
-static void
-transport_stream_make_nicename(th_transport_t *t, th_stream_t *st)
-{
- char buf[200];
- if(st->st_pid != -1)
- snprintf(buf, sizeof(buf), "%s: %s @ #%d",
- transport_nicename(t),
- streaming_component_type2txt(st->st_type), st->st_pid);
- else
- snprintf(buf, sizeof(buf), "%s: %s",
- transport_nicename(t),
- streaming_component_type2txt(st->st_type));
-
- free(st->st_nicename);
- st->st_nicename = strdup(buf);
-}
-
-
-/**
- *
- */
-void
-transport_make_nicename(th_transport_t *t)
-{
- char buf[200];
- source_info_t si;
- th_stream_t *st;
-
- lock_assert(&t->tht_stream_mutex);
-
- t->tht_setsourceinfo(t, &si);
-
- snprintf(buf, sizeof(buf),
- "%s%s%s%s%s",
- si.si_adapter ?: "", si.si_adapter && si.si_mux ? "/" : "",
- si.si_mux ?: "", si.si_mux && si.si_service ? "/" : "",
- si.si_service ?: "");
-
- transport_source_info_free(&si);
-
- free(t->tht_nicename);
- t->tht_nicename = strdup(buf);
-
- TAILQ_FOREACH(st, &t->tht_components, st_link)
- transport_stream_make_nicename(t, st);
-}
-
-
-/**
- * Add a new stream to a transport
- */
-th_stream_t *
-transport_stream_create(th_transport_t *t, int pid,
- streaming_component_type_t type)
-{
- th_stream_t *st;
- int i = 0;
- int idx = 0;
- lock_assert(&t->tht_stream_mutex);
-
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
- if(st->st_index > idx)
- idx = st->st_index;
- i++;
- if(pid != -1 && st->st_pid == pid)
- return st;
- }
-
- st = calloc(1, sizeof(th_stream_t));
- st->st_index = idx + 1;
- st->st_type = type;
-
- TAILQ_INSERT_TAIL(&t->tht_components, st, st_link);
- st->st_transport = t;
-
- st->st_pid = pid;
- st->st_demuxer_fd = -1;
-
- avgstat_init(&st->st_rate, 10);
- avgstat_init(&st->st_cc_errors, 10);
-
- transport_stream_make_nicename(t, st);
-
- if(t->tht_flags & THT_DEBUG)
- tvhlog(LOG_DEBUG, "transport", "Add stream %s", st->st_nicename);
-
- if(t->tht_status == TRANSPORT_RUNNING)
- stream_init(st);
-
- return st;
-}
-
-
-
-/**
- * Add a new stream to a transport
- */
-th_stream_t *
-transport_stream_find(th_transport_t *t, int pid)
-{
- th_stream_t *st;
-
- lock_assert(&t->tht_stream_mutex);
-
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
- if(st->st_pid == pid)
- return st;
- }
- return NULL;
-}
-
-
-
-/**
- *
- */
-void
-transport_map_channel(th_transport_t *t, channel_t *ch, int save)
-{
- lock_assert(&global_lock);
-
- if(t->tht_ch != NULL) {
- LIST_REMOVE(t, tht_ch_link);
- htsp_channel_update(t->tht_ch);
- t->tht_ch = NULL;
- }
-
-
- if(ch != NULL) {
-
- avgstat_init(&t->tht_cc_errors, 3600);
- avgstat_init(&t->tht_rate, 10);
-
- t->tht_ch = ch;
- LIST_INSERT_HEAD(&ch->ch_transports, t, tht_ch_link);
- htsp_channel_update(t->tht_ch);
- }
-
- if(save)
- t->tht_config_save(t);
-}
-
-/**
- *
- */
-static void
-transport_data_timeout(void *aux)
-{
- th_transport_t *t = aux;
-
- pthread_mutex_lock(&t->tht_stream_mutex);
-
- if(!(t->tht_streaming_status & TSS_PACKETS))
- transport_set_streaming_status_flags(t, TSS_GRACEPERIOD);
-
- pthread_mutex_unlock(&t->tht_stream_mutex);
-}
-
-/**
- *
- */
-static struct strtab stypetab[] = {
- { "SDTV", ST_SDTV },
- { "Radio", ST_RADIO },
- { "HDTV", ST_HDTV },
- { "SDTV-AC", ST_AC_SDTV },
- { "HDTV-AC", ST_AC_HDTV },
-};
-
-const char *
-transport_servicetype_txt(th_transport_t *t)
-{
- return val2str(t->tht_servicetype, stypetab) ?: "Other";
-}
-
-/**
- *
- */
-int
-transport_is_tv(th_transport_t *t)
-{
- return
- t->tht_servicetype == ST_SDTV ||
- t->tht_servicetype == ST_HDTV ||
- t->tht_servicetype == ST_AC_SDTV ||
- t->tht_servicetype == ST_AC_HDTV;
-}
-
-
-/**
- *
- */
-void
-transport_set_streaming_status_flags(th_transport_t *t, int set)
-{
- int n;
- streaming_message_t *sm;
- lock_assert(&t->tht_stream_mutex);
-
- n = t->tht_streaming_status;
-
- n |= set;
-
- if(n == t->tht_streaming_status)
- return; // Already set
-
- t->tht_streaming_status = n;
-
- tvhlog(LOG_DEBUG, "Transport", "%s: Status changed to %s%s%s%s%s%s%s",
- transport_nicename(t),
- n & TSS_INPUT_HARDWARE ? "[Hardware input] " : "",
- n & TSS_INPUT_SERVICE ? "[Input on service] " : "",
- n & TSS_MUX_PACKETS ? "[Demuxed packets] " : "",
- n & TSS_PACKETS ? "[Reassembled packets] " : "",
- n & TSS_NO_DESCRAMBLER ? "[No available descrambler] " : "",
- n & TSS_NO_ACCESS ? "[No access] " : "",
- n & TSS_GRACEPERIOD ? "[Graceperiod expired] " : "");
-
- sm = streaming_msg_create_code(SMT_TRANSPORT_STATUS,
- t->tht_streaming_status);
- streaming_pad_deliver(&t->tht_streaming_pad, sm);
- streaming_msg_free(sm);
-
- pthread_cond_broadcast(&t->tht_tss_cond);
-}
-
-
-/**
- * Restart output on a transport.
- * Happens if the stream composition changes.
- * (i.e. an AC3 stream disappears, etc)
- */
-void
-transport_restart(th_transport_t *t, int had_components)
-{
- streaming_message_t *sm;
- lock_assert(&t->tht_stream_mutex);
-
- if(had_components) {
- sm = streaming_msg_create_code(SMT_STOP, SM_CODE_SOURCE_RECONFIGURED);
- streaming_pad_deliver(&t->tht_streaming_pad, sm);
- streaming_msg_free(sm);
- }
-
- if(t->tht_refresh_feed != NULL)
- t->tht_refresh_feed(t);
-
- if(TAILQ_FIRST(&t->tht_components) != NULL) {
-
- sm = streaming_msg_create_data(SMT_START,
- transport_build_stream_start(t));
- streaming_pad_deliver(&t->tht_streaming_pad, sm);
- streaming_msg_free(sm);
- }
-}
-
-
-/**
- * Generate a message containing info about all components
- */
-streaming_start_t *
-transport_build_stream_start(th_transport_t *t)
-{
- th_stream_t *st;
- int n = 0;
- streaming_start_t *ss;
-
- lock_assert(&t->tht_stream_mutex);
-
- TAILQ_FOREACH(st, &t->tht_components, st_link)
- n++;
-
- ss = calloc(1, sizeof(streaming_start_t) +
- sizeof(streaming_start_component_t) * n);
-
- ss->ss_num_components = n;
-
- n = 0;
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
- streaming_start_component_t *ssc = &ss->ss_components[n++];
- ssc->ssc_index = st->st_index;
- ssc->ssc_type = st->st_type;
- memcpy(ssc->ssc_lang, st->st_lang, 4);
- ssc->ssc_composition_id = st->st_composition_id;
- ssc->ssc_ancillary_id = st->st_ancillary_id;
- ssc->ssc_pid = st->st_pid;
- ssc->ssc_width = st->st_width;
- ssc->ssc_height = st->st_height;
- }
-
- t->tht_setsourceinfo(t, &ss->ss_si);
-
- ss->ss_refcount = 1;
- ss->ss_pcr_pid = t->tht_pcr_pid;
- return ss;
-}
-
-
-/**
- *
- */
-void
-transport_set_enable(th_transport_t *t, int enabled)
-{
- if(t->tht_enabled == enabled)
- return;
-
- t->tht_enabled = enabled;
- t->tht_config_save(t);
- subscription_reschedule();
-}
-
-
-static pthread_mutex_t pending_save_mutex;
-static pthread_cond_t pending_save_cond;
-static struct th_transport_queue pending_save_queue;
-
-/**
- *
- */
-void
-transport_request_save(th_transport_t *t, int restart)
-{
- pthread_mutex_lock(&pending_save_mutex);
-
- if(!t->tht_ps_onqueue) {
- t->tht_ps_onqueue = 1 + !!restart;
- TAILQ_INSERT_TAIL(&pending_save_queue, t, tht_ps_link);
- transport_ref(t);
- pthread_cond_signal(&pending_save_cond);
- } else if(restart) {
- t->tht_ps_onqueue = 2; // upgrade to restart too
- }
-
- pthread_mutex_unlock(&pending_save_mutex);
-}
-
-
-/**
- *
- */
-static void *
-transport_saver(void *aux)
-{
- th_transport_t *t;
- int restart;
- pthread_mutex_lock(&pending_save_mutex);
-
- while(1) {
-
- if((t = TAILQ_FIRST(&pending_save_queue)) == NULL) {
- pthread_cond_wait(&pending_save_cond, &pending_save_mutex);
- continue;
- }
- assert(t->tht_ps_onqueue != 0);
- restart = t->tht_ps_onqueue == 2;
-
- TAILQ_REMOVE(&pending_save_queue, t, tht_ps_link);
- t->tht_ps_onqueue = 0;
-
- pthread_mutex_unlock(&pending_save_mutex);
- pthread_mutex_lock(&global_lock);
-
- if(t->tht_status != TRANSPORT_ZOMBIE)
- t->tht_config_save(t);
- if(t->tht_status == TRANSPORT_RUNNING && restart) {
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_restart(t, 1);
- pthread_mutex_unlock(&t->tht_stream_mutex);
- }
- transport_unref(t);
-
- pthread_mutex_unlock(&global_lock);
- pthread_mutex_lock(&pending_save_mutex);
- }
- return NULL;
-}
-
-
-/**
- *
- */
-void
-transport_init(void)
-{
- pthread_t tid;
- TAILQ_INIT(&pending_save_queue);
- pthread_mutex_init(&pending_save_mutex, NULL);
- pthread_cond_init(&pending_save_cond, NULL);
- pthread_create(&tid, NULL, transport_saver, NULL);
-}
-
-
-/**
- *
- */
-void
-transport_source_info_free(struct source_info *si)
-{
- free(si->si_device);
- free(si->si_adapter);
- free(si->si_network);
- free(si->si_mux);
- free(si->si_provider);
- free(si->si_service);
-}
-
-
-void
-transport_source_info_copy(source_info_t *dst, const source_info_t *src)
-{
-#define COPY(x) dst->si_##x = src->si_##x ? strdup(src->si_##x) : NULL
- COPY(device);
- COPY(adapter);
- COPY(network);
- COPY(mux);
- COPY(provider);
- COPY(service);
-#undef COPY
-}
-
-
-/**
- *
- */
-const char *
-transport_nicename(th_transport_t *t)
-{
- return t->tht_nicename;
-}
-
-const char *
-transport_component_nicename(th_stream_t *st)
-{
- return st->st_nicename;
-}
-
-const char *
-transport_tss2text(int flags)
-{
- if(flags & TSS_NO_ACCESS)
- return "No access";
-
- if(flags & TSS_NO_DESCRAMBLER)
- return "No descrambler";
-
- if(flags & TSS_PACKETS)
- return "Got valid packets";
-
- if(flags & TSS_MUX_PACKETS)
- return "Got multiplexed packets but could not decode further";
-
- if(flags & TSS_INPUT_SERVICE)
- return "Got packets for this service but could not decode further";
-
- if(flags & TSS_INPUT_HARDWARE)
- return "Sensed input from hardware but nothing for the service";
-
- if(flags & TSS_GRACEPERIOD)
- return "No input detected";
-
- return "No status";
-}
-
-
-/**
- *
- */
-int
-tss2errcode(int tss)
-{
- if(tss & TSS_NO_ACCESS)
- return SM_CODE_NO_ACCESS;
-
- if(tss & TSS_NO_DESCRAMBLER)
- return SM_CODE_NO_DESCRAMBLER;
-
- if(tss & TSS_GRACEPERIOD)
- return SM_CODE_NO_INPUT;
-
- return SM_CODE_OK;
-}
-
-
-/**
- *
- */
-void
-transport_refresh_channel(th_transport_t *t)
-{
- if(t->tht_ch != NULL)
- htsp_channel_update(t->tht_ch);
-}
-
-
-/**
- * Get the encryption CAID from a transport
- * only the first CA stream in a transport is returned
- */
-uint16_t
-transport_get_encryption(th_transport_t *t)
-{
- th_stream_t *st;
- caid_t *c;
-
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
- switch(st->st_type) {
- case SCT_CA:
- LIST_FOREACH(c, &st->st_caids, link)
- if(c->caid != 0)
- return c->caid;
- break;
- default:
- break;
- }
- }
- return 0;
-}
-
-
-/**
- * Get the signal status from a transport
- */
-int
-transport_get_signal_status(th_transport_t *t, signal_status_t *status)
-{
- // get signal status from the transport
- switch(t->tht_type) {
- case TRANSPORT_DVB:
- return dvb_transport_get_signal_status(t, status);
- default:
- return -1;
- }
-}
-
+++ /dev/null
-/*
- * tvheadend, transport functions
- * Copyright (C) 2007 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/>.
- */
-
-#ifndef TRANSPORTS_H
-#define TRANSPORTS_H
-
-#define PID_TELETEXT_BASE 0x2000
-
-#include "channels.h"
-#include "htsmsg.h"
-#include "subscriptions.h"
-
-void transport_init(void);
-
-unsigned int transport_compute_weight(struct th_transport_list *head);
-
-int transport_start(th_transport_t *t, unsigned int weight, int force_start);
-
-th_transport_t *transport_create(const char *identifier, int type,
- int source_type);
-
-void transport_unref(th_transport_t *t);
-
-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, int save);
-
-th_transport_t *transport_find(channel_t *ch, unsigned int weight,
- const char *loginfo, int *errorp,
- th_transport_t *skip);
-
-th_stream_t *transport_stream_find(th_transport_t *t, int pid);
-
-th_stream_t *transport_stream_create(th_transport_t *t, int pid,
- streaming_component_type_t type);
-
-void transport_set_priority(th_transport_t *t, int prio);
-
-void transport_settings_write(th_transport_t *t);
-
-const char *transport_servicetype_txt(th_transport_t *t);
-
-int transport_is_tv(th_transport_t *t);
-
-void transport_destroy(th_transport_t *t);
-
-void transport_remove_subscriber(th_transport_t *t, th_subscription_t *s,
- int reason);
-
-void transport_set_streaming_status_flags(th_transport_t *t, int flag);
-
-struct streaming_start;
-struct streaming_start *transport_build_stream_start(th_transport_t *t);
-
-void transport_set_enable(th_transport_t *t, int enabled);
-
-void transport_restart(th_transport_t *t, int had_components);
-
-void transport_stream_destroy(th_transport_t *t, th_stream_t *st);
-
-void transport_request_save(th_transport_t *t, int restart);
-
-void transport_source_info_free(source_info_t *si);
-
-void transport_source_info_copy(source_info_t *dst, const source_info_t *src);
-
-void transport_make_nicename(th_transport_t *t);
-
-const char *transport_nicename(th_transport_t *t);
-
-const char *transport_component_nicename(th_stream_t *st);
-
-const char *transport_tss2text(int flags);
-
-static inline int transport_tss_is_error(int flags)
-{
- return flags & TSS_ERRORS ? 1 : 0;
-}
-
-void transport_refresh_channel(th_transport_t *t);
-
-int tss2errcode(int tss);
-
-uint16_t transport_get_encryption(th_transport_t *t);
-
-int transport_get_signal_status(th_transport_t *t, signal_status_t *status);
-
-#endif /* TRANSPORTS_H */
#include "tvheadend.h"
#include "teletext.h"
-#include "transports.h"
#include "subscriptions.h"
#include "psi.h"
#include "tsdemux.h"
#include "parsers.h"
#include "streaming.h"
-static void ts_remux(th_transport_t *t, const uint8_t *tsb);
+static void ts_remux(service_t *t, const uint8_t *tsb);
/**
* Code for dealing with a complete section
{
th_descrambler_t *td;
th_stream_t *st = opaque;
- th_transport_t *t = st->st_transport;
+ service_t *t = st->st_service;
if(st->st_type == SCT_CA) {
- LIST_FOREACH(td, &t->tht_descramblers, td_transport_link)
+ LIST_FOREACH(td, &t->s_descramblers, td_service_link)
td->td_table(td, t, st, data, len);
} else if(st->st_got_section != NULL) {
st->st_got_section(t, st, data, len);
* Continue processing of transport stream packets
*/
static void
-ts_recv_packet0(th_transport_t *t, th_stream_t *st, const uint8_t *tsb)
+ts_recv_packet0(service_t *t, th_stream_t *st, const uint8_t *tsb)
{
int off, pusi, cc, error;
- transport_set_streaming_status_flags(t, TSS_MUX_PACKETS);
+ service_set_streaming_status_flags(t, TSS_MUX_PACKETS);
- if(streaming_pad_probe_type(&t->tht_streaming_pad, SMT_MPEGTS))
+ if(streaming_pad_probe_type(&t->s_streaming_pad, SMT_MPEGTS))
ts_remux(t, tsb);
error = !!(tsb[1] & 0x80);
cc = tsb[3] & 0xf;
if(st->st_cc_valid && cc != st->st_cc) {
/* Incorrect CC */
- limitedlog(&st->st_loglimit_cc, "TS", transport_component_nicename(st),
+ limitedlog(&st->st_loglimit_cc, "TS", service_component_nicename(st),
"Continuity counter error");
- avgstat_add(&t->tht_cc_errors, 1, dispatch_clock);
+ avgstat_add(&t->s_cc_errors, 1, dispatch_clock);
avgstat_add(&st->st_cc_errors, 1, dispatch_clock);
// Mark as error if this is not the first packet of a payload
if(off > 188)
break;
- if(t->tht_status == TRANSPORT_RUNNING)
+ if(t->s_status == SERVICE_RUNNING)
parse_mpeg_ts(t, st, tsb + off, 188 - off, pusi, error);
break;
}
* than the stream PCR
*/
static void
-ts_extract_pcr(th_transport_t *t, th_stream_t *st, const uint8_t *tsb,
+ts_extract_pcr(service_t *t, th_stream_t *st, const uint8_t *tsb,
int64_t *pcrp)
{
int64_t real, pcr, d;
st->st_pcr_recovery_fails = 0;
st->st_pcr_drift += d;
- if(t->tht_pcr_pid == st->st_pid) {
- /* This is the registered PCR PID, adjust transport PCR drift
+ if(t->s_pcr_pid == st->st_pid) {
+ /* This is the registered PCR PID, adjust service PCR drift
via an IIR filter */
- t->tht_pcr_drift = (t->tht_pcr_drift * 255 + st->st_pcr_drift) / 256;
+ t->s_pcr_drift = (t->s_pcr_drift * 255 + st->st_pcr_drift) / 256;
}
}
st->st_pcr_last = pcr;
}
/**
- * Process transport stream packets, extract PCR and optionally descramble
+ * Process service stream packets, extract PCR and optionally descramble
*/
void
-ts_recv_packet1(th_transport_t *t, const uint8_t *tsb, int64_t *pcrp)
+ts_recv_packet1(service_t *t, const uint8_t *tsb, int64_t *pcrp)
{
th_stream_t *st;
int pid, n, m, r;
th_descrambler_t *td;
int error = 0;
- if(t->tht_status != TRANSPORT_RUNNING)
+ if(t->s_status != SERVICE_RUNNING)
return;
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
- transport_set_streaming_status_flags(t, TSS_INPUT_HARDWARE);
+ service_set_streaming_status_flags(t, TSS_INPUT_HARDWARE);
if(tsb[1] & 0x80) {
/* Transport Error Indicator */
- limitedlog(&t->tht_loglimit_tei, "TS", transport_nicename(t),
+ limitedlog(&t->s_loglimit_tei, "TS", service_nicename(t),
"Transport error indicator");
error = 1;
}
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
- st = transport_stream_find(t, pid);
+ st = service_stream_find(t, pid);
/* Extract PCR */
if(tsb[3] & 0x20 && tsb[4] > 0 && tsb[5] & 0x10 && !error)
ts_extract_pcr(t, st, tsb, pcrp);
if(st == NULL) {
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
return;
}
if(!error)
- transport_set_streaming_status_flags(t, TSS_INPUT_SERVICE);
+ service_set_streaming_status_flags(t, TSS_INPUT_SERVICE);
- avgstat_add(&t->tht_rate, 188, dispatch_clock);
+ avgstat_add(&t->s_rate, 188, dispatch_clock);
if((tsb[3] & 0xc0) ||
- (t->tht_scrambled_seen && st->st_type != SCT_CA &&
+ (t->s_scrambled_seen && st->st_type != SCT_CA &&
st->st_type != SCT_PAT && st->st_type != SCT_PMT)) {
/**
* Lock for descrambling, but only if packet was not in error
*/
if(!error)
- t->tht_scrambled_seen = t->tht_scrambled;
+ t->s_scrambled_seen = t->s_scrambled;
/* scrambled stream */
n = m = 0;
- LIST_FOREACH(td, &t->tht_descramblers, td_transport_link) {
+ LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
n++;
r = td->td_descramble(td, t, st, tsb);
if(r == 0) {
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
return;
}
if(!error) {
if(n == 0) {
- transport_set_streaming_status_flags(t, TSS_NO_DESCRAMBLER);
+ service_set_streaming_status_flags(t, TSS_NO_DESCRAMBLER);
} else if(m == n) {
- transport_set_streaming_status_flags(t, TSS_NO_ACCESS);
+ service_set_streaming_status_flags(t, TSS_NO_ACCESS);
}
}
} else {
ts_recv_packet0(t, st, tsb);
}
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
* Process transport stream packets, simple version
*/
void
-ts_recv_packet2(th_transport_t *t, const uint8_t *tsb)
+ts_recv_packet2(service_t *t, const uint8_t *tsb)
{
th_stream_t *st;
int pid = (tsb[1] & 0x1f) << 8 | tsb[2];
- if((st = transport_stream_find(t, pid)) != NULL)
+ if((st = service_stream_find(t, pid)) != NULL)
ts_recv_packet0(t, st, tsb);
}
*
*/
static void
-ts_remux(th_transport_t *t, const uint8_t *src)
+ts_remux(service_t *t, const uint8_t *src)
{
uint8_t tsb[188];
memcpy(tsb, src, 188);
streaming_message_t sm;
sm.sm_type = SMT_MPEGTS;
sm.sm_data = tsb;
- streaming_pad_deliver(&t->tht_streaming_pad, &sm);
+ streaming_pad_deliver(&t->s_streaming_pad, &sm);
}
#ifndef TSDEMUX_H
#define TSDEMUX_H
-void ts_recv_packet1(th_transport_t *t, const uint8_t *tsb, int64_t *pcrp);
+void ts_recv_packet1(struct service *t, const uint8_t *tsb, int64_t *pcrp);
-void ts_recv_packet2(th_transport_t *t, const uint8_t *tsb);
+void ts_recv_packet2(struct service *t, const uint8_t *tsb);
#endif /* TSDEMUX_H */
if(ts->ts_pcr_start == AV_NOPTS_VALUE)
return; /* dont know anything yet */
- ts->ts_pcr_ref = now - ts->ts_pcr_start + t->tht_pcr_drift;
+ ts->ts_pcr_ref = now - ts->ts_pcr_start + t->s_pcr_drift;
}
f = TAILQ_FIRST(&tmf->tmf_queue); /* next packet we are going to send */
- next = f->tm_deadline + ts->ts_pcr_ref - t->tht_pcr_drift;
+ next = f->tm_deadline + ts->ts_pcr_ref - t->s_pcr_drift;
if(next < now + 100)
next = now + 100;
int i;
int64_t t, tlow, pcr;
uint8_t *d;
- th_transport_t *tr;
+ service_t *tr;
if(ts->ts_block == 0)
return;
if((d[3] & 0xf0) == 0x30 && d[4] >= 7 && d[5] & 0x10) {
tr = ts->ts_muxer->tm_subscription->ths_transport;
- pcr = getclock_hires() - ts->ts_pcr_ref - tr->tht_pcr_drift;
+ pcr = getclock_hires() - ts->ts_pcr_ref - tr->s_pcr_drift;
t = av_rescale_q(pcr, AV_TIME_BASE_Q, mpeg_tc_27M);
tlow = t % 300LL;
t = t / 300LL;
{
ts_muxer_t *ts = aux;
th_muxer_t *tm = ts->ts_muxer;
- th_transport_t *t;
+ service_t *t;
th_muxstream_t *tms;
uint8_t table[180];
int l, pcrpid;
t = tm->tm_subscription->ths_transport;
LIST_FOREACH(tms, &tm->tm_streams, tms_muxer_link0)
- if(tms->tms_stream->st_pid == t->tht_pcr_pid)
+ if(tms->tms_stream->st_pid == t->s_pcr_pid)
break;
pcrpid = tms ? tms->tms_index : 0x1fff;
{
th_muxstream_t *tms = opaque;
th_muxer_t *tm = tms->tms_muxer;
- th_transport_t *t = tm->tm_subscription->ths_transport;
+ service_t *t = tm->tm_subscription->ths_transport;
ts_muxer_t *ts = tm->tm_opaque;
th_muxpkt_t *f;
th_muxfifo_t *tmf = &tms->tms_delivery_fifo;
- int64_t pcr = now - ts->ts_pcr_ref - t->tht_pcr_drift;
+ int64_t pcr = now - ts->ts_pcr_ref - t->s_pcr_drift;
int64_t dl, next, delta;
f = tmf_deq(tmf);
return;
}
- next = f->tm_deadline + ts->ts_pcr_ref - t->tht_pcr_drift;
+ next = f->tm_deadline + ts->ts_pcr_ref - t->s_pcr_drift;
if(next < now + 100)
next = now + 100;
int64_t now;
th_muxpkt_t *f;
th_muxfifo_t *tmf = &tms->tms_delivery_fifo;
- th_transport_t *t = ts->ts_muxer->tm_subscription->ths_transport;
+ service_t *t = ts->ts_muxer->tm_subscription->ths_transport;
int64_t next;
if(dtimer_isarmed(&tms->tms_mux_timer))
if(ts->ts_pcr_start == AV_NOPTS_VALUE)
return; /* dont know anything yet */
- ts->ts_pcr_ref = now - ts->ts_pcr_start + t->tht_pcr_drift;
+ ts->ts_pcr_ref = now - ts->ts_pcr_start + t->s_pcr_drift;
}
f = TAILQ_FIRST(&tmf->tmf_queue); /* next packet we are going to send */
- next = f->tm_deadline + ts->ts_pcr_ref - t->tht_pcr_drift;
+ next = f->tm_deadline + ts->ts_pcr_ref - t->s_pcr_drift;
if(next < now + 100)
next = now + 100;
th_subscription_t *s = ts->ts_muxer->tm_subscription;
if(!(ts->ts_flags & TS_SEEK) &&
- s->ths_transport->tht_source_type == THT_MPEG_TS) {
+ s->ths_transport->s_source_type == S_MPEG_TS) {
/* We dont need to seek and source is MPEG TS, we can use a
shortcut to avoid remuxing stream */
LIST_HEAD(dvr_config_list, dvr_config);
LIST_HEAD(dvr_entry_list, dvr_entry);
TAILQ_HEAD(ref_update_queue, ref_update);
-LIST_HEAD(th_transport_list, th_transport);
-RB_HEAD(th_transport_tree, th_transport);
-TAILQ_HEAD(th_transport_queue, th_transport);
+LIST_HEAD(service_list, service);
+RB_HEAD(service_tree, service);
+TAILQ_HEAD(service_queue, service);
LIST_HEAD(th_stream_list, th_stream);
TAILQ_HEAD(th_stream_queue, th_stream);
LIST_HEAD(th_muxer_list, th_muxer);
SMT_START,
/**
- * Transport status
+ * Service status
*
* Notification about status of source, see TSS_ flags
*/
- SMT_TRANSPORT_STATUS,
+ SMT_SERVICE_STATUS,
/**
* Streaming stop.
#define SM_CODE_SVC_NOT_ENABLED 204
#define SM_CODE_BAD_SIGNAL 205
#define SM_CODE_NO_SOURCE 206
-#define SM_CODE_NO_TRANSPORT 207
+#define SM_CODE_NO_SERVICE 207
#define SM_CODE_ABORTED 300
-/**
- * Descrambler superclass
- *
- * Created/Destroyed on per-transport basis upon transport start/stop
- */
-typedef struct th_descrambler {
- LIST_ENTRY(th_descrambler) td_transport_link;
-
- void (*td_table)(struct th_descrambler *d, struct th_transport *t,
- struct th_stream *st,
- const uint8_t *section, int section_len);
-
- int (*td_descramble)(struct th_descrambler *d, struct th_transport *t,
- struct th_stream *st, const uint8_t *tsb);
-
- void (*td_stop)(struct th_descrambler *d);
-
-} th_descrambler_t;
-
-
-
-/*
- * Section callback, called when a PSI table is fully received
- */
-typedef void (pid_section_callback_t)(struct th_transport *t,
- struct th_stream *pi,
- const uint8_t *section, int section_len);
-
-LIST_HEAD(caid_list, caid);
-/**
- *
- */
-typedef struct caid {
- LIST_ENTRY(caid) link;
-
- uint8_t delete_me;
- uint16_t caid;
- uint32_t providerid;
-
-} caid_t;
-
-/*
- * Stream, one media component for a transport.
- *
- * XXX: This should be renamed to 'elementary_stream' or something
- */
-typedef struct th_stream {
-
- TAILQ_ENTRY(th_stream) st_link;
- int st_position;
- struct th_transport *st_transport;
-
- streaming_component_type_t st_type;
- int st_index;
-
- uint16_t st_aspect_num;
- uint16_t st_aspect_den;
-
- char st_lang[4]; /* ISO 639 3-letter language code */
- uint16_t st_composition_id;
- uint16_t st_ancillary_id;
-
- int16_t st_pid;
- uint16_t st_parent_pid; /* For subtitle streams originating from
- a teletext stream. this is the pid
- of the teletext stream */
-
- uint8_t st_cc; /* Last CC */
- uint8_t st_cc_valid; /* Is CC valid at all? */
-
- avgstat_t st_cc_errors;
- avgstat_t st_rate;
-
- int st_demuxer_fd;
- int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */
-
- struct psi_section *st_section;
- int st_section_docrc; /* Set if we should verify CRC on tables */
- pid_section_callback_t *st_got_section;
- void *st_got_section_opaque;
-
- /* PCR recovery */
-
- int st_pcr_recovery_fails;
- int64_t st_pcr_real_last; /* realtime clock when we saw last PCR */
- int64_t st_pcr_last; /* PCR clock when we saw last PCR */
- int64_t st_pcr_drift;
-
- /* For transport stream packet reassembly */
-
- sbuf_t st_buf;
-
- uint32_t st_startcond;
- uint32_t st_startcode;
- uint32_t st_startcode_offset;
- int st_parser_state;
- int st_parser_ptr;
- void *st_priv; /* Parser private data */
-
- sbuf_t st_buf_ps; // program stream reassembly (analogue adapters)
- sbuf_t st_buf_a; // Audio packet reassembly
-
- uint8_t *st_global_data;
- int st_global_data_len;
- int st_incomplete;
- int st_ssc_intercept;
- int st_ssc_ptr;
- uint8_t st_ssc_buf[32];
-
- struct th_pkt *st_curpkt;
- int64_t st_curpts;
- int64_t st_curdts;
- int64_t st_prevdts;
- int64_t st_nextdts;
- int st_frame_duration;
- int st_width;
- int st_height;
-
- int st_meta_change;
-
- /* CA ID's on this stream */
- struct caid_list st_caids;
-
- int st_vbv_size; /* Video buffer size (in bytes) */
- int st_vbv_delay; /* -1 if CBR */
-
- /* */
-
- int st_delete_me; /* Temporary flag for deleting streams */
-
- /* Error log limiters */
-
- loglimiter_t st_loglimit_cc;
- loglimiter_t st_loglimit_pes;
-
- char *st_nicename;
-
- /* Teletext subtitle */
- char st_blank; // Last subtitle was blank
-
-
-} th_stream_t;
-
-
-/**
- * A Transport (or in MPEG TS terms: a 'service')
- */
-typedef struct th_transport {
-
- LIST_ENTRY(th_transport) tht_hash_link;
-
- enum {
- TRANSPORT_DVB,
- TRANSPORT_IPTV,
- TRANSPORT_V4L,
- } tht_type;
-
- enum {
- /**
- * Transport is idle.
- */
- TRANSPORT_IDLE,
-
- /**
- * Transport producing output
- */
- TRANSPORT_RUNNING,
-
- /**
- * Destroyed, but pointer is till valid.
- * This would be the case if transport_destroy() did not actually free
- * the transport because there are references held to it.
- *
- * Reference counts can be used so that code can hold a pointer to
- * a transport without having the global lock.
- *
- * Note: No fields in the transport may be accessed without the
- * global lock held. Thus, the global_lock must be reaquired and
- * then tht_status must be checked. If it is ZOMBIE the code must
- * just drop the refcount and pretend that the transport never
- * was there in the first place.
- */
- TRANSPORT_ZOMBIE,
- } tht_status;
-
- /**
- * Refcount, operated using atomic.h ops.
- */
- int tht_refcount;
-
- /**
- *
- */
- int tht_flags;
-
-#define THT_DEBUG 0x1
-
- /**
- * Source type is used to determine if an output requesting
- * MPEG-TS can shortcut all the parsing and remuxing.
- */
- enum {
- THT_MPEG_TS,
- THT_OTHER,
- } tht_source_type;
-
-
- /**
- * PID carrying the programs PCR.
- * XXX: We don't support transports that does not carry
- * the PCR in one of the content streams.
- */
- uint16_t tht_pcr_pid;
-
- /**
- * PID for the PMT of this MPEG-TS stream.
- */
- uint16_t tht_pmt_pid;
-
- /**
- * Set if transport is enabled (the default). If disabled it should
- * not be considered when chasing for available transports during
- * subscription scheduling.
- */
- int tht_enabled;
-
- /**
- * Last PCR seen, we use it for a simple clock for rawtsinput.c
- */
- int64_t tht_pcr_last;
- int64_t tht_pcr_last_realtime;
-
- LIST_ENTRY(th_transport) tht_group_link;
-
- LIST_ENTRY(th_transport) tht_active_link;
-
- LIST_HEAD(, th_subscription) tht_subscriptions;
-
- int (*tht_start_feed)(struct th_transport *t, unsigned int weight,
- int force_start);
-
- void (*tht_refresh_feed)(struct th_transport *t);
-
- void (*tht_stop_feed)(struct th_transport *t);
-
- void (*tht_config_save)(struct th_transport *t);
-
- void (*tht_setsourceinfo)(struct th_transport *t, struct source_info *si);
-
- int (*tht_quality_index)(struct th_transport *t);
-
- int (*tht_grace_period)(struct th_transport *t);
-
- void (*tht_dtor)(struct th_transport *t);
-
- /*
- * Per source type structs
- */
- struct th_dvb_mux_instance *tht_dvb_mux_instance;
-
- /**
- * Unique identifer (used for storing on disk, etc)
- */
- char *tht_identifier;
-
- /**
- * Name usable for displaying to user
- */
- char *tht_nicename;
-
- /**
- * Service ID according to EN 300 468
- */
- uint16_t tht_dvb_service_id;
-
- uint16_t tht_channel_number;
-
- /**
- * Service name (eg. DVB service name as specified by EN 300 468)
- */
- char *tht_svcname;
-
- /**
- * Provider name (eg. DVB provider name as specified by EN 300 468)
- */
- char *tht_provider;
-
- enum {
- /* Service types defined in EN 300 468 */
-
- ST_SDTV = 0x1, /* SDTV (MPEG2) */
- ST_RADIO = 0x2,
- ST_HDTV = 0x11, /* HDTV (MPEG2) */
- ST_AC_SDTV = 0x16, /* Advanced codec SDTV */
- ST_AC_HDTV = 0x19, /* Advanced codec HDTV */
- } tht_servicetype;
-
-
- /**
- * Teletext...
- */
- th_commercial_advice_t tht_tt_commercial_advice;
- int tht_tt_rundown_content_length;
- time_t tht_tt_clock; /* Network clock as determined by teletext decoder */
-
- /**
- * Channel mapping
- */
- LIST_ENTRY(th_transport) tht_ch_link;
- struct channel *tht_ch;
-
- /**
- * Service probe, see serviceprobe.c for details
- */
- int tht_sp_onqueue;
- TAILQ_ENTRY(th_transport) tht_sp_link;
-
- /**
- * Pending save.
- *
- * transport_request_save() will enqueue the transport here.
- * We need to do this if we don't hold the global lock.
- * This happens when we update PMT from within the TS stream itself.
- * Then we hold the stream mutex, and thus, can not obtain the global lock
- * as it would cause lock inversion.
- */
- int tht_ps_onqueue;
- TAILQ_ENTRY(th_transport) tht_ps_link;
-
- /**
- * Timer which is armed at transport start. Once it fires
- * it will check if any packets has been parsed. If not the status
- * will be set to TRANSPORT_STATUS_NO_INPUT
- */
- gtimer_t tht_receive_timer;
-
- /**
- * IPTV members
- */
- char *tht_iptv_iface;
- struct in_addr tht_iptv_group;
- struct in6_addr tht_iptv_group6;
- uint16_t tht_iptv_port;
- int tht_iptv_fd;
-
- /**
- * For per-transport PAT/PMT parsers, allocated on demand
- * Free'd by transport_destroy
- */
- struct psi_section *tht_pat_section;
- struct psi_section *tht_pmt_section;
-
- /**
- * V4l members
- */
-
- struct v4l_adapter *tht_v4l_adapter;
- int tht_v4l_frequency; // In Hz
-
-
- /*********************************************************
- *
- * Streaming part of transport
- *
- * All access to fields below this must be protected with
- * tht_stream_mutex held.
- *
- * Note: Code holding tht_stream_mutex should _never_
- * acquire global_lock while already holding tht_stream_mutex.
- *
- */
-
- /**
- * Mutex to be held during streaming.
- * This mutex also protects all th_stream_t instances for this
- * transport.
- */
- pthread_mutex_t tht_stream_mutex;
-
-
- /**
- * Condition variable to singal when streaming_status changes
- * interlocked with tht_stream_mutex
- */
- pthread_cond_t tht_tss_cond;
- /**
- *
- */
- int tht_streaming_status;
-
- // Progress
-#define TSS_INPUT_HARDWARE 0x1
-#define TSS_INPUT_SERVICE 0x2
-#define TSS_MUX_PACKETS 0x4
-#define TSS_PACKETS 0x8
-
-#define TSS_GRACEPERIOD 0x8000
-
- // Errors
-#define TSS_NO_DESCRAMBLER 0x10000
-#define TSS_NO_ACCESS 0x20000
-
-#define TSS_ERRORS 0xffff0000
-
-
- /**
- * For simple streaming sources (such as video4linux) keeping
- * track of the video and audio stream is convenient.
- */
- th_stream_t *tht_video;
- th_stream_t *tht_audio;
-
- /**
- * Average continuity errors
- */
- avgstat_t tht_cc_errors;
-
- /**
- * Average bitrate
- */
- avgstat_t tht_rate;
-
- /**
- * Descrambling support
- */
-
- struct th_descrambler_list tht_descramblers;
- int tht_scrambled;
- int tht_scrambled_seen;
- int tht_caid;
-
- /**
- * PCR drift compensation. This should really be per-packet.
- */
- int64_t tht_pcr_drift;
-
- /**
- * List of all components.
- */
- struct th_stream_queue tht_components;
-
-
- /**
- * Delivery pad, this is were we finally deliver all streaming output
- */
- streaming_pad_t tht_streaming_pad;
-
-
- loglimiter_t tht_loglimit_tei;
-
-
- int64_t tht_current_pts;
-
-} th_transport_t;
-
const char *streaming_component_type2txt(streaming_component_type_t s);
static inline unsigned int tvh_strhash(const char *s, unsigned int mod)
extern time_t dispatch_clock;
-extern struct th_transport_list all_transports;
+extern struct service_list all_transports;
extern struct channel_tree channel_name_tree;
extern void scopedunlock(pthread_mutex_t **mtxp);
#include "settings.h"
#include "tvheadend.h"
-#include "transports.h"
+#include "service.h"
#include "v4l.h"
#include "parsers.h"
#include "notify.h"
#include "psi.h"
-
+#include "channels.h"
struct v4l_adapter_queue v4l_adapters;
static void
v4l_input(v4l_adapter_t *va)
{
- th_transport_t *t = va->va_current_transport;
+ service_t *t = va->va_current_service;
th_stream_t *st;
uint8_t buf[4000];
uint8_t *ptr, *pkt;
ptr = buf;
- pthread_mutex_lock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
- transport_set_streaming_status_flags(t,
+ service_set_streaming_status_flags(t,
TSS_INPUT_HARDWARE | TSS_INPUT_SERVICE);
while(len > 0) {
continue;
case 0x000001e0:
- st = t->tht_video;
+ st = t->s_video;
break;
case 0x000001c0:
- st = t->tht_audio;
+ st = t->s_audio;
break;
}
st->st_buf_ps.sb_ptr += r;
if(st->st_buf_ps.sb_ptr == l) {
- transport_set_streaming_status_flags(t, TSS_MUX_PACKETS);
+ service_set_streaming_status_flags(t, TSS_MUX_PACKETS);
parse_mpeg_ps(t, st, pkt + 6, l - 6);
ptr++; len--;
}
}
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_unlock(&t->s_stream_mutex);
}
*
*/
static int
-v4l_transport_start(th_transport_t *t, unsigned int weight, int force_start)
+v4l_service_start(service_t *t, unsigned int weight, int force_start)
{
- v4l_adapter_t *va = t->tht_v4l_adapter;
- int frequency = t->tht_v4l_frequency;
+ v4l_adapter_t *va = t->s_v4l_adapter;
+ int frequency = t->s_v4l_frequency;
struct v4l2_frequency vf;
int result;
v4l2_std_id std = 0xff;
int fd;
- if(va->va_current_transport != NULL)
+ if(va->va_current_service != NULL)
return 1; // Adapter busy
fd = tvh_open(va->va_path, O_RDWR | O_NONBLOCK, 0);
va->va_fd = fd;
- va->va_current_transport = t;
+ va->va_current_service = t;
pthread_create(&va->va_thread, NULL, v4l_thread, va);
v4l_adapter_notify(va);
return 0;
*
*/
static void
-v4l_transport_refresh(th_transport_t *t)
+v4l_service_refresh(service_t *t)
{
}
*
*/
static void
-v4l_transport_stop(th_transport_t *t)
+v4l_service_stop(service_t *t)
{
char c = 'q';
- v4l_adapter_t *va = t->tht_v4l_adapter;
+ v4l_adapter_t *va = t->s_v4l_adapter;
- assert(va->va_current_transport != NULL);
+ assert(va->va_current_service != NULL);
if(write(va->va_pipe[1], &c, 1) != 1)
tvhlog(LOG_ERR, "v4l", "Unable to close video thread -- %s",
close(va->va_pipe[1]);
close(va->va_fd);
- va->va_current_transport = NULL;
+ va->va_current_service = NULL;
v4l_adapter_notify(va);
}
*
*/
static void
-v4l_transport_save(th_transport_t *t)
+v4l_service_save(service_t *t)
{
- v4l_adapter_t *va = t->tht_v4l_adapter;
+ v4l_adapter_t *va = t->s_v4l_adapter;
htsmsg_t *m = htsmsg_create_map();
- htsmsg_add_u32(m, "frequency", t->tht_v4l_frequency);
+ htsmsg_add_u32(m, "frequency", t->s_v4l_frequency);
- if(t->tht_ch != NULL) {
- htsmsg_add_str(m, "channelname", t->tht_ch->ch_name);
+ if(t->s_ch != NULL) {
+ htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
htsmsg_add_u32(m, "mapped", 1);
}
- pthread_mutex_lock(&t->tht_stream_mutex);
- psi_save_transport_settings(m, t);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ psi_save_service_settings(m, t);
+ pthread_mutex_unlock(&t->s_stream_mutex);
hts_settings_save(m, "v4lservices/%s/%s",
- va->va_identifier, t->tht_identifier);
+ va->va_identifier, t->s_identifier);
htsmsg_destroy(m);
}
*
*/
static int
-v4l_transport_quality(th_transport_t *t)
+v4l_service_quality(service_t *t)
{
return 100;
}
*
*/
static int
-v4l_grace_period(th_transport_t *t)
+v4l_grace_period(service_t *t)
{
return 2;
}
* Generate a descriptive name for the source
*/
static void
-v4l_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
+v4l_service_setsourceinfo(service_t *t, struct source_info *si)
{
char buf[64];
memset(si, 0, sizeof(struct source_info));
- si->si_adapter = strdup(t->tht_v4l_adapter->va_displayname);
+ si->si_adapter = strdup(t->s_v4l_adapter->va_displayname);
- snprintf(buf, sizeof(buf), "%d Hz", t->tht_v4l_frequency);
+ snprintf(buf, sizeof(buf), "%d Hz", t->s_v4l_frequency);
si->si_mux = strdup(buf);
}
/**
*
*/
-th_transport_t *
-v4l_transport_find(v4l_adapter_t *va, const char *id, int create)
+service_t *
+v4l_service_find(v4l_adapter_t *va, const char *id, int create)
{
- th_transport_t *t;
+ service_t *t;
char buf[200];
int vaidlen = strlen(va->va_identifier);
if(strncmp(id, va->va_identifier, vaidlen))
return NULL;
- LIST_FOREACH(t, &va->va_transports, tht_group_link)
- if(!strcmp(t->tht_identifier, id))
+ LIST_FOREACH(t, &va->va_services, s_group_link)
+ if(!strcmp(t->s_identifier, id))
return t;
}
va->va_tally = MAX(atoi(id + vaidlen + 1), va->va_tally);
}
- t = transport_create(id, TRANSPORT_V4L, 0);
+ t = service_create(id, SERVICE_TYPE_V4L, 0);
- t->tht_start_feed = v4l_transport_start;
- t->tht_refresh_feed = v4l_transport_refresh;
- t->tht_stop_feed = v4l_transport_stop;
- t->tht_config_save = v4l_transport_save;
- t->tht_setsourceinfo = v4l_transport_setsourceinfo;
- t->tht_quality_index = v4l_transport_quality;
- t->tht_grace_period = v4l_grace_period;
- t->tht_iptv_fd = -1;
- t->tht_v4l_adapter = va;
+ t->s_start_feed = v4l_service_start;
+ t->s_refresh_feed = v4l_service_refresh;
+ t->s_stop_feed = v4l_service_stop;
+ t->s_config_save = v4l_service_save;
+ t->s_setsourceinfo = v4l_service_setsourceinfo;
+ t->s_quality_index = v4l_service_quality;
+ t->s_grace_period = v4l_grace_period;
+ t->s_iptv_fd = -1;
+ t->s_v4l_adapter = va;
- pthread_mutex_lock(&t->tht_stream_mutex);
- transport_make_nicename(t);
- t->tht_video = transport_stream_create(t, -1, SCT_MPEG2VIDEO);
- t->tht_audio = transport_stream_create(t, -1, SCT_MPEG2AUDIO);
- pthread_mutex_unlock(&t->tht_stream_mutex);
+ pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
+ t->s_video = service_stream_create(t, -1, SCT_MPEG2VIDEO);
+ t->s_audio = service_stream_create(t, -1, SCT_MPEG2AUDIO);
+ pthread_mutex_unlock(&t->s_stream_mutex);
- LIST_INSERT_HEAD(&va->va_transports, t, tht_group_link);
+ LIST_INSERT_HEAD(&va->va_services, t, s_group_link);
return t;
}
if(va->va_devicename)
htsmsg_add_str(m, "devicename", va->va_devicename);
- if(va->va_current_transport != NULL) {
+ if(va->va_current_service != NULL) {
char buf[100];
snprintf(buf, sizeof(buf), "%d Hz",
- va->va_current_transport->tht_v4l_frequency);
+ va->va_current_service->s_v4l_frequency);
htsmsg_add_str(m, "currentMux", buf);
} else {
htsmsg_add_str(m, "currentMux", "- inactive -");
const char *s;
unsigned int u32;
- th_transport_t *t = v4l_transport_find(va, name, 1);
+ service_t *t = v4l_service_find(va, name, 1);
if(t == NULL)
return;
u32 = 0;
if(!htsmsg_get_u32(c, "frequency", &u32))
- t->tht_v4l_frequency = u32;
+ t->s_v4l_frequency = u32;
if(s && u32)
- transport_map_channel(t, channel_find_by_name(s, 1, 0), 0);
+ service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
}
/**
// struct v4l2_capability va_caps;
- struct th_transport *va_current_transport;
+ struct service *va_current_service;
- struct th_transport_list va_transports;
+ struct service_list va_services;
int va_tally;
/** Receiver thread stuff */
htsmsg_t *v4l_adapter_build_msg(v4l_adapter_t *va);
-th_transport_t *v4l_transport_find(v4l_adapter_t *va, const char *id,
- int create);
+service_t *v4l_service_find(v4l_adapter_t *va, const char *id,
+ int create);
void v4l_init(void);
#include "psi.h"
#include "dvr/dvr.h"
-#include "transports.h"
#include "serviceprobe.h"
#include "xmltv.h"
#include "epg.h"
*
*/
void
-extjs_transport_delete(htsmsg_t *in)
+extjs_service_delete(htsmsg_t *in)
{
htsmsg_field_t *f;
- th_transport_t *t;
+ service_t *t;
const char *id;
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
if((id = htsmsg_field_get_string(f)) != NULL &&
- (t = transport_find_by_identifier(id)) != NULL)
- transport_destroy(t);
+ (t = service_find_by_identifier(id)) != NULL)
+ service_destroy(t);
}
}
*
*/
static void
-transport_update(htsmsg_t *in)
+service_update(htsmsg_t *in)
{
htsmsg_field_t *f;
htsmsg_t *c;
- th_transport_t *t;
+ service_t *t;
uint32_t u32;
const char *id;
const char *chname;
(id = htsmsg_get_str(c, "id")) == NULL)
continue;
- if((t = transport_find_by_identifier(id)) == NULL)
+ if((t = service_find_by_identifier(id)) == NULL)
continue;
if(!htsmsg_get_u32(c, "enabled", &u32))
- transport_set_enable(t, u32);
+ service_set_enable(t, u32);
if((chname = htsmsg_get_str(c, "channelname")) != NULL)
- transport_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
+ service_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
}
}
{
htsbuf_queue_t *hq = &hc->hc_reply;
htsmsg_t *out, *streams, *c;
- th_transport_t *t;
+ service_t *t;
th_stream_t *st;
caid_t *ca;
char buf[128];
pthread_mutex_lock(&global_lock);
- if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) {
+ if(remain == NULL || (t = service_find_by_identifier(remain)) == NULL) {
pthread_mutex_unlock(&global_lock);
return 404;
}
streams = htsmsg_create_list();
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
c = htsmsg_create_map();
htsmsg_add_u32(c, "pid", st->st_pid);
}
out = htsmsg_create_map();
- htsmsg_add_str(out, "title", t->tht_svcname ?: "unnamed transport");
+ htsmsg_add_str(out, "title", t->s_svcname ?: "unnamed service");
htsmsg_add_msg(out, "streams", streams);
*
*/
static void
-transport_update_iptv(htsmsg_t *in)
+service_update_iptv(htsmsg_t *in)
{
htsmsg_field_t *f;
htsmsg_t *c;
- th_transport_t *t;
+ service_t *t;
uint32_t u32;
const char *id, *s;
int save;
(id = htsmsg_get_str(c, "id")) == NULL)
continue;
- if((t = transport_find_by_identifier(id)) == NULL)
+ if((t = service_find_by_identifier(id)) == NULL)
continue;
save = 0;
if(!htsmsg_get_u32(c, "port", &u32)) {
- t->tht_iptv_port = u32;
+ t->s_iptv_port = u32;
save = 1;
}
if((s = htsmsg_get_str(c, "group")) != NULL) {
- if(!inet_pton(AF_INET, s, &t->tht_iptv_group.s_addr)){
- inet_pton(AF_INET6, s, &t->tht_iptv_group6.s6_addr);
+ if(!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)){
+ inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
}
save = 1;
}
- save |= tvh_str_update(&t->tht_iptv_iface, htsmsg_get_str(c, "interface"));
+ save |= tvh_str_update(&t->s_iptv_iface, htsmsg_get_str(c, "interface"));
if(save)
- t->tht_config_save(t); // Save config
+ t->s_config_save(t); // Save config
}
}
*
*/
static htsmsg_t *
-build_record_iptv(th_transport_t *t)
+build_record_iptv(service_t *t)
{
htsmsg_t *r = htsmsg_create_map();
char abuf[INET_ADDRSTRLEN];
char abuf6[INET6_ADDRSTRLEN];
- htsmsg_add_str(r, "id", t->tht_identifier);
+ htsmsg_add_str(r, "id", t->s_identifier);
- htsmsg_add_str(r, "channelname", t->tht_ch ? t->tht_ch->ch_name : "");
- htsmsg_add_str(r, "interface", t->tht_iptv_iface ?: "");
+ htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : "");
+ htsmsg_add_str(r, "interface", t->s_iptv_iface ?: "");
- if(t->tht_iptv_group.s_addr != 0){
- inet_ntop(AF_INET, &t->tht_iptv_group, abuf, sizeof(abuf));
- htsmsg_add_str(r, "group", t->tht_iptv_group.s_addr ? abuf : "");
+ if(t->s_iptv_group.s_addr != 0){
+ inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
+ htsmsg_add_str(r, "group", t->s_iptv_group.s_addr ? abuf : "");
}
else {
- inet_ntop(AF_INET6, &t->tht_iptv_group6, abuf6, sizeof(abuf6));
- htsmsg_add_str(r, "group", t->tht_iptv_group6.s6_addr ? abuf6 : "");
+ inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6));
+ htsmsg_add_str(r, "group", t->s_iptv_group6.s6_addr ? abuf6 : "");
}
- htsmsg_add_u32(r, "port", t->tht_iptv_port);
- htsmsg_add_u32(r, "enabled", t->tht_enabled);
+ htsmsg_add_u32(r, "port", t->s_iptv_port);
+ htsmsg_add_u32(r, "enabled", t->s_enabled);
return r;
}
*
*/
static int
-iptv_transportcmp(const void *A, const void *B)
+iptv_servicecmp(const void *A, const void *B)
{
- th_transport_t *a = *(th_transport_t **)A;
- th_transport_t *b = *(th_transport_t **)B;
+ service_t *a = *(service_t **)A;
+ service_t *b = *(service_t **)B;
- return memcmp(&a->tht_iptv_group, &b->tht_iptv_group, 4);
+ return memcmp(&a->s_iptv_group, &b->s_iptv_group, 4);
}
/**
htsmsg_t *out, *in, *array;
const char *op = http_arg_get(&hc->hc_req_args, "op");
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
- th_transport_t *t, **tvec;
+ service_t *t, **tvec;
int count = 0, i = 0;
pthread_mutex_lock(&global_lock);
in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
if(!strcmp(op, "get")) {
- LIST_FOREACH(t, &iptv_all_transports, tht_group_link)
+ LIST_FOREACH(t, &iptv_all_services, s_group_link)
count++;
- tvec = alloca(sizeof(th_transport_t *) * count);
- LIST_FOREACH(t, &iptv_all_transports, tht_group_link)
+ tvec = alloca(sizeof(service_t *) * count);
+ LIST_FOREACH(t, &iptv_all_services, s_group_link)
tvec[i++] = t;
out = htsmsg_create_map();
array = htsmsg_create_list();
- qsort(tvec, count, sizeof(th_transport_t *), iptv_transportcmp);
+ qsort(tvec, count, sizeof(service_t *), iptv_servicecmp);
for(i = 0; i < count; i++)
htsmsg_add_msg(array, NULL, build_record_iptv(tvec[i]));
} else if(!strcmp(op, "update")) {
if(in != NULL) {
- transport_update(in); // Generic transport parameters
- transport_update_iptv(in); // IPTV speicifc
+ service_update(in); // Generic service parameters
+ service_update_iptv(in); // IPTV speicifc
}
out = htsmsg_create_map();
} else if(!strcmp(op, "create")) {
- out = build_record_iptv(iptv_transport_find(NULL, 1));
+ out = build_record_iptv(iptv_service_find(NULL, 1));
} else if(!strcmp(op, "delete")) {
if(in != NULL)
- extjs_transport_delete(in);
+ extjs_service_delete(in);
out = htsmsg_create_map();
*
*/
void
-extjs_transport_update(htsmsg_t *in)
+extjs_service_update(htsmsg_t *in)
{
htsmsg_field_t *f;
htsmsg_t *c;
- th_transport_t *t;
+ service_t *t;
uint32_t u32;
const char *id;
const char *chname;
(id = htsmsg_get_str(c, "id")) == NULL)
continue;
- if((t = transport_find_by_identifier(id)) == NULL)
+ if((t = service_find_by_identifier(id)) == NULL)
continue;
if(!htsmsg_get_u32(c, "enabled", &u32))
- transport_set_enable(t, u32);
+ service_set_enable(t, u32);
if((chname = htsmsg_get_str(c, "channelname")) != NULL)
- transport_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
+ service_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
}
}
#include "dtable.h"
#include "channels.h"
#include "psi.h"
-#include "transports.h"
#include "serviceprobe.h"
#include "dvb/dvb.h"
const char *sibling = http_arg_get(&hc->hc_req_args, "sibling");
const char *s, *sc;
th_dvb_mux_instance_t *tdmi;
- th_transport_t *t;
+ service_t *t;
pthread_mutex_lock(&global_lock);
"Service probe started on \"%s\"", tda->tda_displayname);
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
- if(t->tht_enabled)
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
+ if(t->s_enabled)
serviceprobe_enqueue(t);
}
}
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;
+ service_t *a = *(service_t **)A;
+ service_t *b = *(service_t **)B;
- return strcasecmp(a->tht_svcname ?: "\0377", b->tht_svcname ?: "\0377");
+ return strcasecmp(a->s_svcname ?: "\0377", b->s_svcname ?: "\0377");
}
/**
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;
+ service_t *t, **tvec;
int count = 0, i = 0;
pthread_mutex_lock(&global_lock);
array = htsmsg_create_list();
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
count++;
}
}
- tvec = alloca(sizeof(th_transport_t *) * count);
+ tvec = alloca(sizeof(service_t *) * count);
LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
- LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+ LIST_FOREACH(t, &tdmi->tdmi_transports, s_group_link) {
tvec[i++] = t;
}
}
- qsort(tvec, count, sizeof(th_transport_t *), transportcmp);
+ qsort(tvec, count, sizeof(service_t *), transportcmp);
for(i = 0; i < count; i++)
htsmsg_add_msg(array, NULL, dvb_transport_build_msg(tvec[i]));
} else if(!strcmp(op, "update")) {
if(in != NULL)
- extjs_transport_update(in);
+ extjs_service_update(in);
out = htsmsg_create_map();
#include "psi.h"
#include "v4l.h"
-#include "transports.h"
#include "serviceprobe.h"
*
*/
static void
-transport_update_v4l(htsmsg_t *in)
+service_update_v4l(htsmsg_t *in)
{
htsmsg_field_t *f;
htsmsg_t *c;
- th_transport_t *t;
+ service_t *t;
uint32_t u32;
const char *id;
int save;
(id = htsmsg_get_str(c, "id")) == NULL)
continue;
- if((t = transport_find_by_identifier(id)) == NULL)
+ if((t = service_find_by_identifier(id)) == NULL)
continue;
save = 0;
if(!htsmsg_get_u32(c, "frequency", &u32)) {
- t->tht_v4l_frequency = u32;
+ t->s_v4l_frequency = u32;
save = 1;
}
if(save)
- t->tht_config_save(t); // Save config
+ t->s_config_save(t); // Save config
}
}
*
*/
static htsmsg_t *
-build_record_v4l(th_transport_t *t)
+build_record_v4l(service_t *t)
{
htsmsg_t *r = htsmsg_create_map();
- htsmsg_add_str(r, "id", t->tht_identifier);
+ htsmsg_add_str(r, "id", t->s_identifier);
- htsmsg_add_str(r, "channelname", t->tht_ch ? t->tht_ch->ch_name : "");
- htsmsg_add_u32(r, "frequency", t->tht_v4l_frequency);
- htsmsg_add_u32(r, "enabled", t->tht_enabled);
+ htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : "");
+ htsmsg_add_u32(r, "frequency", t->s_v4l_frequency);
+ htsmsg_add_u32(r, "enabled", t->s_enabled);
return r;
}
*
*/
static int
-v4l_transportcmp(const void *A, const void *B)
+v4l_servicecmp(const void *A, const void *B)
{
- th_transport_t *a = *(th_transport_t **)A;
- th_transport_t *b = *(th_transport_t **)B;
+ service_t *a = *(service_t **)A;
+ service_t *b = *(service_t **)B;
- return (int)a->tht_v4l_frequency - (int)b->tht_v4l_frequency;
+ return (int)a->s_v4l_frequency - (int)b->s_v4l_frequency;
}
/**
htsmsg_t *out, *in, *array;
const char *op = http_arg_get(&hc->hc_req_args, "op");
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
- th_transport_t *t, **tvec;
+ service_t *t, **tvec;
int count = 0, i = 0;
pthread_mutex_lock(&global_lock);
if(!strcmp(op, "get")) {
- LIST_FOREACH(t, &va->va_transports, tht_group_link)
+ LIST_FOREACH(t, &va->va_services, s_group_link)
count++;
- tvec = alloca(sizeof(th_transport_t *) * count);
- LIST_FOREACH(t, &va->va_transports, tht_group_link)
+ tvec = alloca(sizeof(service_t *) * count);
+ LIST_FOREACH(t, &va->va_services, s_group_link)
tvec[i++] = t;
out = htsmsg_create_map();
array = htsmsg_create_list();
- qsort(tvec, count, sizeof(th_transport_t *), v4l_transportcmp);
+ qsort(tvec, count, sizeof(service_t *), v4l_servicecmp);
for(i = 0; i < count; i++)
htsmsg_add_msg(array, NULL, build_record_v4l(tvec[i]));
} else if(!strcmp(op, "update")) {
if(in != NULL) {
- extjs_transport_update(in); // Generic transport parameters
- transport_update_v4l(in); // V4L speicifc
+ extjs_service_update(in); // Generic service parameters
+ service_update_v4l(in); // V4L speicifc
}
out = htsmsg_create_map();
} else if(!strcmp(op, "create")) {
- out = build_record_v4l(v4l_transport_find(va, NULL, 1));
+ out = build_record_v4l(v4l_service_find(va, NULL, 1));
} else if(!strcmp(op, "delete")) {
if(in != NULL)
- extjs_transport_delete(in);
+ extjs_service_delete(in);
out = htsmsg_create_map();
#include "dvb/dvb_support.h"
#endif
-#include "transports.h"
-
extern char tvh_binshasum[20];
extern char *htsversion_full;
#if ENABLE_LINUXDVB
static void
-dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent)
+dumptransports(htsbuf_queue_t *hq, struct service_list *l, int indent)
{
- th_transport_t *t;
+ service_t *t;
th_stream_t *st;
outputtitle(hq, indent, "Transports (or services)");
- LIST_FOREACH(t, l, tht_group_link) {
+ LIST_FOREACH(t, l, s_group_link) {
htsbuf_qprintf(hq, "%*.s%s (%s)\n", indent + 2, "",
- transport_nicename(t), t->tht_identifier);
+ service_nicename(t), t->s_identifier);
htsbuf_qprintf(hq, "%*.s%-16s %-5s %-5s %-5s %-5s %-10s\n", indent + 4, "",
htsbuf_qprintf(hq, "%*.s-------------------------------------------\n",
indent + 4, "");
- TAILQ_FOREACH(st, &t->tht_components, st_link) {
+ TAILQ_FOREACH(st, &t->s_components, st_link) {
caid_t *caid;
htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s\n", indent + 4, "",
streaming_component_type2txt(st->st_type),
run = 0;
break;
- case SMT_TRANSPORT_STATUS:
+ case SMT_SERVICE_STATUS:
//printf("SMT_TRANSPORT_STATUS\n");
break;
void extjs_start_v4l(void);
#endif
-void extjs_transport_update(htsmsg_t *in);
+void extjs_service_update(htsmsg_t *in);
-void extjs_transport_delete(htsmsg_t *in);
+void extjs_service_delete(htsmsg_t *in);
/**