Rename transport -> service

This commit is contained in:
Andreas Öman 2010-11-29 20:06:52 +00:00
parent 76c3336e4e
commit 85132732b6
51 changed files with 2051 additions and 2619 deletions

View file

@ -48,7 +48,7 @@ SRCS = src/main.c \
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 \

View file

@ -41,10 +41,9 @@
#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:
@ -73,7 +72,7 @@
*
*/
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;
@ -121,14 +120,14 @@ typedef struct capmt_caid_ecm {
/**
*
*/
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;
@ -155,7 +154,7 @@ typedef struct capmt_transport {
/* sending requests will be based on this caid */
int ct_caid_last;
} capmt_transport_t;
} capmt_service_t;
/**
@ -166,7 +165,7 @@ typedef struct capmt {
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;
@ -199,7 +198,7 @@ capmt_send_msg(capmt_t *capmt, const uint8_t *buf, size_t len)
}
static void
capmt_send_stop(capmt_transport_t *t)
capmt_send_stop(capmt_service_t *t)
{
/* buffer for capmt */
int pos = 0;
@ -208,7 +207,7 @@ capmt_send_stop(capmt_transport_t *t)
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,
@ -223,8 +222,8 @@ capmt_send_stop(capmt_transport_t *t)
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);
@ -234,14 +233,14 @@ capmt_send_stop(capmt_transport_t *t)
/**
* 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);
@ -255,7 +254,7 @@ capmt_transport_destroy(th_descrambler_t *td)
free(cce);
}
LIST_REMOVE(td, td_transport_link);
LIST_REMOVE(td, td_service_link);
LIST_REMOVE(ct, ct_link);
@ -266,8 +265,8 @@ capmt_transport_destroy(th_descrambler_t *td)
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;
@ -293,12 +292,12 @@ handle_ca0(capmt_t* capmt) {
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;
}
@ -315,7 +314,7 @@ handle_ca0(capmt_t* capmt) {
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;
}
@ -404,12 +403,12 @@ capmt_thread(void *aux)
*
*/
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;
@ -438,7 +437,7 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
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));
@ -456,7 +455,7 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *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;
@ -537,7 +536,7 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
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;
@ -556,10 +555,10 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t,
*
*/
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;
@ -601,10 +600,10 @@ capmt_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st,
* 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;
@ -613,24 +612,24 @@ capmt_transport_start(th_transport_t *t)
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));
@ -644,15 +643,15 @@ capmt_transport_start(th_transport_t *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);
}
}

View file

@ -21,6 +21,6 @@
void capmt_init(void);
void capmt_transport_start(th_transport_t *t);
void capmt_service_start(struct service *t);
#endif /* CAPMT_H_ */

View file

@ -33,7 +33,6 @@
#include "tvheadend.h"
#include "psi.h"
#include "channels.h"
#include "transports.h"
#include "epg.h"
#include "xmltv.h"
#include "dtable.h"
@ -344,12 +343,12 @@ channel_save(channel_t *ch)
}
/**
* 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);
@ -362,8 +361,8 @@ channel_rename(channel_t *ch, const char *newname)
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);
@ -376,7 +375,7 @@ channel_rename(channel_t *ch, const char *newname)
void
channel_delete(channel_t *ch)
{
th_transport_t *t;
service_t *t;
th_subscription_t *s;
channel_tag_mapping_t *ctm;
@ -392,8 +391,8 @@ channel_delete(channel_t *ch)
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);
@ -423,22 +422,22 @@ channel_delete(channel_t *ch)
/**
* 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);
}

View file

@ -40,7 +40,7 @@ typedef struct channel {
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;

224
src/cwc.c
View file

@ -34,11 +34,11 @@
#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"
/**
*
@ -87,7 +87,7 @@ typedef enum {
*
*/
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;
@ -126,42 +126,42 @@ typedef struct ecm_pid {
/**
*
*/
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;
/**
@ -200,7 +200,7 @@ typedef struct cwc {
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;
@ -248,9 +248,9 @@ typedef struct cwc {
*
*/
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);
@ -548,7 +548,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, 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;
@ -614,7 +614,7 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
* 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;
@ -663,10 +663,10 @@ cwc_send_login(cwc_t *cwc)
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;
@ -684,18 +684,18 @@ handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
/* 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 ||
@ -705,13 +705,13 @@ handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
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",
@ -720,22 +720,22 @@ handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
" 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);
}
}
@ -747,7 +747,7 @@ handle_ecm_reply(cwc_transport_t *ct, ecm_section_t *es, uint8_t *msg,
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];
@ -759,8 +759,8 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
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) {
@ -982,11 +982,11 @@ cwc_session(cwc_t *cwc)
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;
@ -1058,11 +1058,11 @@ cwc_thread(void *aux)
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);
@ -1209,12 +1209,12 @@ cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len)
*
*/
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;
@ -1228,7 +1228,7 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
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;
}
@ -1236,7 +1236,7 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
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);
}
@ -1278,7 +1278,7 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
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;
}
@ -1289,8 +1289,8 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
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;
}
@ -1299,7 +1299,7 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
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;
@ -1317,19 +1317,19 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t,
*
*/
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;
}
}
@ -1339,59 +1339,59 @@ update_keys(cwc_transport_t *ct)
*
*/
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;
@ -1399,28 +1399,28 @@ cwc_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st,
/**
* 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);
}
@ -1428,12 +1428,12 @@ cwc_transport_destroy(th_descrambler_t *td)
*
*/
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;
@ -1449,10 +1449,10 @@ cwc_find_stream_by_caid(th_transport_t *t, int caid)
* 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);
@ -1463,25 +1463,25 @@ cwc_transport_start(th_transport_t *t)
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);
}
}

View file

@ -21,7 +21,7 @@
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);

View file

@ -128,7 +128,7 @@ typedef struct th_dvb_mux_instance {
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;
@ -183,7 +183,7 @@ typedef struct th_dvb_adapter {
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;
@ -297,17 +297,17 @@ int dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src);
*/
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);
/**

View file

@ -36,11 +36,11 @@
#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;
@ -411,7 +411,7 @@ dvb_adapter_mux_scanner(void *aux)
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 */
@ -499,13 +499,13 @@ dvb_adapter_destroy(th_dvb_adapter_t *tda)
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);
}
@ -520,7 +520,7 @@ dvb_adapter_input_dvr(void *aux)
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) {
@ -535,8 +535,8 @@ dvb_adapter_input_dvr(void *aux)
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);
}
@ -565,7 +565,7 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda)
char buf[100];
htsmsg_t *m = htsmsg_create_map();
th_dvb_mux_instance_t *tdmi;
th_transport_t *t;
service_t *t;
int nummux = 0;
int numsvc = 0;
int fdiv;
@ -576,7 +576,7 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda)
// 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++;
}
}

View file

@ -38,7 +38,6 @@
#include "dvb_support.h"
#include "diseqc.h"
#include "notify.h"
#include "transports.h"
#include "dvr/dvr.h"
/**

View file

@ -39,11 +39,11 @@
#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;
@ -294,7 +294,7 @@ void
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);
@ -303,9 +303,9 @@ dvb_mux_destroy(th_dvb_mux_instance_t *tdmi)
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);
@ -1074,7 +1074,7 @@ int
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;
@ -1088,34 +1088,34 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
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;
@ -1130,10 +1130,10 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
}
}
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);

View file

@ -37,7 +37,6 @@
#include "dvb.h"
#include "dvb_support.h"
#include "epg.h"
#include "transports.h"
#include "channels.h"
#include "psi.h"
#include "notify.h"
@ -478,7 +477,7 @@ static int
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;
@ -539,7 +538,7 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
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) {
@ -640,7 +639,7 @@ static int
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;
@ -733,26 +732,26 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
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;
@ -1045,7 +1044,7 @@ dvb_table_local_channel(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
{
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)
@ -1062,10 +1061,10 @@ dvb_table_local_channel(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
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);
}
}
}
@ -1190,7 +1189,7 @@ atsc_vct_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
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;
@ -1250,13 +1249,13 @@ atsc_vct_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
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;
@ -1272,12 +1271,12 @@ static int
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;
}

View file

@ -39,7 +39,6 @@
#include "tvheadend.h"
#include "dvb.h"
#include "channels.h"
#include "transports.h"
#include "subscriptions.h"
#include "psi.h"
#include "dvb_support.h"
@ -49,13 +48,13 @@
*
*/
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;
@ -69,7 +68,7 @@ dvb_transport_open_demuxers(th_dvb_adapter_t *tda, th_transport_t *t)
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;
}
@ -84,7 +83,7 @@ dvb_transport_open_demuxers(th_dvb_adapter_t *tda, th_transport_t *t)
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;
@ -104,10 +103,10 @@ dvb_transport_open_demuxers(th_dvb_adapter_t *tda, th_transport_t *t)
* 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);
@ -115,16 +114,16 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int force_start)
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;
@ -134,9 +133,9 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int force_start)
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);
@ -151,24 +150,24 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int force_start)
*
*/
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;
}
@ -176,9 +175,9 @@ dvb_transport_stop(th_transport_t *t)
*
*/
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);
@ -197,7 +196,7 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
uint32_t sid, pmt;
const char *s;
unsigned int u32;
th_transport_t *t;
service_t *t;
lock_assert(&global_lock);
@ -216,32 +215,32 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
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);
}
@ -250,36 +249,36 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
*
*/
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);
@ -293,9 +292,9 @@ dvb_transport_save(th_transport_t *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);
@ -307,9 +306,9 @@ dvb_transport_quality(th_transport_t *t)
* 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));
@ -327,11 +326,11 @@ dvb_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
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);
}
@ -339,7 +338,7 @@ dvb_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
*
*/
static int
dvb_grace_period(th_transport_t *t)
dvb_grace_period(service_t *t)
{
return 10;
}
@ -350,18 +349,18 @@ dvb_grace_period(th_transport_t *t)
*
* 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;
}
@ -376,25 +375,25 @@ dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid,
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;
@ -405,32 +404,32 @@ dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid,
*
*/
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;
}
@ -452,9 +451,9 @@ dvb_transport_notify_by_adapter(th_dvb_adapter_t *tda)
*
*/
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);
@ -466,9 +465,9 @@ dvb_transport_notify(th_transport_t *t)
* 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;

View file

@ -29,8 +29,7 @@
#include "streaming.h"
#include "dvr.h"
#include "spawn.h"
#include "transports.h"
#include "service.h"
#include "plumbing/tsfix.h"
#include "plumbing/globalheaders.h"
@ -445,7 +444,7 @@ dvr_thread(void *aux)
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)) {

View file

@ -37,7 +37,6 @@
#include "access.h"
#include "htsp.h"
#include "streaming.h"
#include "transports.h"
#include "psi.h"
#include "htsmsg_binary.h"
@ -295,7 +294,7 @@ htsp_build_channel(channel_t *ch, const char *method)
{
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();
@ -317,12 +316,12 @@ htsp_build_channel(channel_t *ch, const char *method)
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));
}
@ -1380,7 +1379,7 @@ const static char frametypearray[PKT_NTYPES] = {
};
/**
* 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)
@ -1470,7 +1469,7 @@ 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");
@ -1585,12 +1584,12 @@ htsp_subscription_status(htsp_subscription_t *hs, const char *err)
*
*/
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));
}
}
@ -1616,8 +1615,8 @@ htsp_streaming_input(void *opaque, streaming_message_t *sm)
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:

View file

@ -36,7 +36,6 @@
#include "tvheadend.h"
#include "htsmsg.h"
#include "channels.h"
#include "transports.h"
#include "iptv_input.h"
#include "tsdemux.h"
#include "psi.h"
@ -46,8 +45,8 @@ static int iptv_thread_running;
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
@ -55,7 +54,7 @@ static struct th_transport_list iptv_active_transports; /* Currently enabled */
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;
@ -67,7 +66,7 @@ iptv_got_pat(const uint8_t *ptr, size_t len, void *aux)
prognum = ptr[0] << 8 | ptr[1];
pmt = (ptr[2] & 0x1f) << 8 | ptr[3];
t->tht_pmt_pid = pmt;
t->s_pmt_pid = pmt;
}
@ -77,36 +76,36 @@ iptv_got_pat(const uint8_t *ptr, size_t len, void *aux)
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);
@ -123,7 +122,7 @@ iptv_thread(void *aux)
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);
@ -165,8 +164,8 @@ iptv_thread(void *aux)
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)
@ -182,7 +181,7 @@ iptv_thread(void *aux)
*
*/
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;
@ -194,7 +193,7 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
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;
@ -203,7 +202,7 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
}
/* 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);
}
@ -211,44 +210,44 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0);
}
if(fd == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->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;
}
@ -256,19 +255,19 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
/* 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,
@ -276,7 +275,7 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
straddr, sizeof(straddr));
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
t->tht_identifier, straddr, strerror(errno));
t->s_identifier, straddr, strerror(errno));
close(fd);
return -1;
}
@ -294,15 +293,15 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
ev.data.fd = fd;
if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s",
t->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;
}
@ -312,7 +311,7 @@ iptv_transport_start(th_transport_t *t, unsigned int weight, int force_start)
*
*/
static void
iptv_transport_refresh(th_transport_t *t)
iptv_service_refresh(service_t *t)
{
}
@ -322,38 +321,38 @@ iptv_transport_refresh(th_transport_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];
@ -361,24 +360,24 @@ iptv_transport_stop(th_transport_t *t)
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;
}
@ -386,7 +385,7 @@ iptv_transport_stop(th_transport_t *t)
*
*/
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];
@ -394,33 +393,33 @@ iptv_transport_save(th_transport_t *t)
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);
}
@ -430,11 +429,11 @@ iptv_transport_save(th_transport_t *t)
*
*/
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;
@ -445,17 +444,17 @@ iptv_transport_quality(th_transport_t *t)
* 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);
}
}
@ -465,7 +464,7 @@ iptv_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
*
*/
static int
iptv_grace_period(th_transport_t *t)
iptv_grace_period(service_t *t)
{
return 3;
}
@ -475,20 +474,20 @@ iptv_grace_period(th_transport_t *t)
*
*/
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) {
@ -496,8 +495,8 @@ iptv_transport_find(const char *id, int create)
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;
}
@ -512,23 +511,23 @@ iptv_transport_find(const char *id, int create)
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;
}
@ -538,18 +537,18 @@ iptv_transport_find(const char *id, int create)
* 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) {
@ -559,31 +558,31 @@ iptv_transport_load(void)
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);
}
@ -596,5 +595,5 @@ void
iptv_input_init(void)
{
pthread_mutex_init(&iptv_recvmutex, NULL);
iptv_transport_load();
iptv_service_load();
}

View file

@ -21,8 +21,8 @@
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_ */

View file

@ -53,7 +53,7 @@
#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"
@ -364,7 +364,7 @@ main(int argc, char **argv)
*/
xmltv_init(); /* Must be initialized before channels */
transport_init();
service_init();
channels_init();

View file

@ -32,6 +32,7 @@
#include "parsers.h"
#include "parser_h264.h"
#include "bitstream.h"
#include "service.h"
/**
* H.264 parser, nal escaper

View file

@ -23,11 +23,11 @@
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_ */

View file

@ -34,7 +34,7 @@
#include "parsers.h"
#include "parser_latm.h"
#include "bitstream.h"
#include "service.h"
typedef struct latm_private {
@ -159,7 +159,7 @@ read_stream_mux_config(th_stream_t *st, latm_private_t *latm, bitstream_t *bs)
* 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;
@ -196,7 +196,7 @@ parse_latm_audio_mux_element(th_transport_t *t, th_stream_t *st,
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;

View file

@ -19,7 +19,8 @@
#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_ */

View file

@ -26,12 +26,12 @@
#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
@ -81,48 +81,48 @@ getpts(const uint8_t *p)
}
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)
{
@ -170,7 +170,7 @@ parse_mpeg_ts(th_transport_t *t, th_stream_t *st, const uint8_t *data,
* 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;
@ -206,7 +206,7 @@ parse_mpeg_ps(th_transport_t *t, th_stream_t *st, uint8_t *data, int len)
* 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;
@ -273,7 +273,7 @@ parse_aac(th_transport_t *t, th_stream_t *st, const uint8_t *data,
* 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;
@ -373,7 +373,7 @@ parse_sc(th_transport_t *t, th_stream_t *st, const uint8_t *data, int len,
*
*/
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;
@ -413,13 +413,13 @@ depacketize(th_transport_t *t, th_stream_t *st, size_t len,
*
*/
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;
@ -453,7 +453,7 @@ mpa_valid_frame(const uint8_t *buf)
*
*/
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;
@ -495,7 +495,7 @@ parse_mpa2(th_transport_t *t, th_stream_t *st)
*
*/
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;
@ -567,7 +567,7 @@ static const char acmodtab[8] = {2,1,2,3,3,4,4,5};
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;
@ -646,7 +646,7 @@ eac3_valid_frame(const uint8_t *buf)
}
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;
@ -709,7 +709,7 @@ parse_eac3(th_transport_t *t, th_stream_t *st, size_t ilen,
* 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;
@ -754,7 +754,7 @@ parse_pes_header(th_transport_t *t, th_stream_t *st,
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;
}
@ -780,7 +780,7 @@ const unsigned int mpeg2video_framedurations[16] = {
* 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;
@ -829,7 +829,7 @@ parser_set_stream_vsize(th_stream_t *st, int width, int height)
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);
}
}
@ -858,7 +858,7 @@ static const uint8_t mpeg2_aspect[16][2]={
* 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;
@ -926,7 +926,7 @@ parser_global_data_move(th_stream_t *st, const uint8_t *data, size_t len)
*
*/
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;
@ -961,7 +961,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
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:
@ -1054,7 +1054,7 @@ parse_mpeg2video(th_transport_t *t, th_stream_t *st, size_t len,
* 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;
@ -1130,7 +1130,7 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
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:
@ -1172,7 +1172,7 @@ parse_h264(th_transport_t *t, th_stream_t *st, size_t len,
* 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;
@ -1226,7 +1226,7 @@ parse_subtitles(th_transport_t *t, th_stream_t *st, const uint8_t *data,
// 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);
}
}
@ -1237,13 +1237,13 @@ parse_subtitles(th_transport_t *t, th_stream_t *st, const uint8_t *data,
*
*/
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",
@ -1263,14 +1263,14 @@ parser_deliver(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
/**
* 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 */

View file

@ -21,14 +21,17 @@
#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];

View file

@ -242,7 +242,7 @@ gh_hold(globalheaders_t *gh, streaming_message_t *sm)
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);
@ -269,7 +269,7 @@ gh_pass(globalheaders_t *gh, streaming_message_t *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);

View file

@ -362,7 +362,7 @@ tsfix_input(void *opaque, streaming_message_t *sm)
break;
case SMT_EXIT:
case SMT_TRANSPORT_STATUS:
case SMT_SERVICE_STATUS:
case SMT_NOSTART:
case SMT_MPEGTS:
break;

View file

@ -24,7 +24,6 @@
#include "tvheadend.h"
#include "psi.h"
#include "transports.h"
#include "dvb/dvb_support.h"
#include "tsdemux.h"
#include "parsers.h"
@ -114,14 +113,14 @@ psi_section_reassemble(psi_section_t *ps, const uint8_t *tsb, int crc,
* 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;
@ -135,8 +134,8 @@ psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
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;
}
@ -178,7 +177,7 @@ psi_append_crc32(uint8_t *buf, int offset, int maxlen)
*/
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;
@ -225,14 +224,14 @@ psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid)
* 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;
}
@ -267,7 +266,7 @@ psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid)
* 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;
@ -321,7 +320,7 @@ psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size)
* 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;
@ -338,9 +337,9 @@ psi_desc_teletext(th_transport_t *t, const uint8_t *ptr, int size,
// 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;
@ -384,23 +383,23 @@ pidcmp(const void *A, const void *B)
*
*/
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);
}
@ -408,7 +407,7 @@ sort_pids(th_transport_t *t)
* 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;
@ -432,9 +431,9 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
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;
@ -447,11 +446,11 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
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;
}
@ -460,7 +459,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
/* 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)
@ -593,16 +592,16 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
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;
@ -631,7 +630,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
}
/* 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) {
@ -645,7 +644,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
if(st->st_delete_me) {
transport_stream_destroy(t, st);
service_stream_destroy(t, st);
update |= PMT_UPDATE_STREAM_DELETED;
}
}
@ -654,9 +653,9 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
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":"",
@ -671,15 +670,15 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid,
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;
@ -865,21 +864,21 @@ streaming_component_type2txt(streaming_component_type_t s)
/**
* 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);
@ -995,10 +994,10 @@ load_caid(htsmsg_t *m, th_stream_t *st)
/**
* 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;
@ -1008,12 +1007,12 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
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"))
@ -1032,7 +1031,7 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
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);

View file

@ -21,6 +21,7 @@
#include "htsmsg.h"
#include "streaming.h"
#include "service.h"
#define PSI_SECTION_SIZE 5000
@ -36,19 +37,19 @@ typedef struct psi_section {
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_ */

View file

@ -29,10 +29,10 @@
#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;
@ -40,7 +40,7 @@ typedef struct rawts {
char *rt_identifier;
psi_section_t rt_pat;
struct th_transport_list rt_transports;
struct service_list rt_services;
int rt_pcr_pid;
@ -51,7 +51,7 @@ typedef struct rawts {
*
*/
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
}
@ -60,7 +60,7 @@ rawts_transport_start(th_transport_t *t, unsigned int weight, int force_start)
*
*/
static void
rawts_transport_stop(th_transport_t *t)
rawts_service_stop(service_t *t)
{
}
@ -68,14 +68,14 @@ rawts_transport_stop(th_transport_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);
@ -87,7 +87,7 @@ rawts_transport_save(th_transport_t *t)
*
*/
static int
rawts_transport_quality(th_transport_t *t)
rawts_service_quality(service_t *t)
{
return 100;
}
@ -97,7 +97,7 @@ rawts_transport_quality(th_transport_t *t)
* 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));
}
@ -107,46 +107,46 @@ rawts_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
/**
*
*/
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;
}
@ -156,7 +156,7 @@ rawts_transport_add(rawts_t *rt, uint16_t sid, int pmt_pid)
*/
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)
@ -176,7 +176,7 @@ static void
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;
@ -195,17 +195,17 @@ got_pat(const uint8_t *ptr, size_t len, void *opaque)
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;
@ -231,7 +231,7 @@ static void
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;
@ -242,7 +242,7 @@ process_ts_packet(rawts_t *rt, uint8_t *tsb)
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);
@ -253,24 +253,24 @@ process_ts_packet(rawts_t *rt, uint8_t *tsb)
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();
}
}
}

1069
src/service.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -31,31 +31,30 @@
#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);
}
@ -64,12 +63,12 @@ serviceprobe_enqueue(th_transport_t *t)
*
*/
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;
}
@ -79,7 +78,7 @@ serviceprobe_delete(th_transport_t *t)
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;
@ -110,18 +109,18 @@ serviceprobe_thread(void *aux)
}
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;
@ -135,7 +134,7 @@ serviceprobe_thread(void *aux)
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) {
@ -143,7 +142,7 @@ serviceprobe_thread(void *aux)
err = NULL;
} else if(status & (TSS_GRACEPERIOD | TSS_ERRORS)) {
run = 0;
err = transport_tss2text(status);
err = service_tss2text(status);
}
}
@ -157,25 +156,25 @@ serviceprobe_thread(void *aux)
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";
@ -191,21 +190,21 @@ serviceprobe_thread(void *aux)
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;
}

View file

@ -21,8 +21,8 @@
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_ */

View file

@ -22,7 +22,7 @@
#include "streaming.h"
#include "packet.h"
#include "atomic.h"
#include "transports.h"
#include "service.h"
void
streaming_pad_init(streaming_pad_t *sp)
@ -183,7 +183,7 @@ streaming_msg_clone(streaming_message_t *src)
break;
case SMT_STOP:
case SMT_TRANSPORT_STATUS:
case SMT_SERVICE_STATUS:
case SMT_NOSTART:
dst->sm_code = src->sm_code;
break;
@ -214,7 +214,7 @@ streaming_start_unref(streaming_start_t *ss)
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);
@ -244,7 +244,7 @@ streaming_msg_free(streaming_message_t *sm)
case SMT_EXIT:
break;
case SMT_TRANSPORT_STATUS:
case SMT_SERVICE_STATUS:
break;
case SMT_NOSTART:
@ -355,8 +355,8 @@ streaming_code2txt(int code)
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";
@ -388,7 +388,7 @@ streaming_start_copy(const streaming_start_t *src)
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];

View file

@ -32,9 +32,10 @@
#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;
@ -61,70 +62,70 @@ subscription_sort(th_subscription_t *a, th_subscription_t *b)
/**
* 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;
}
@ -141,7 +142,7 @@ void
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;
@ -155,31 +156,31 @@ subscription_reschedule(void)
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);
}
}
@ -189,7 +190,7 @@ subscription_reschedule(void)
void
subscription_unsubscribe(th_subscription_t *s)
{
th_transport_t *t = s->ths_transport;
service_t *t = s->ths_service;
lock_assert(&global_lock);
@ -205,7 +206,7 @@ subscription_unsubscribe(th_subscription_t *s)
}
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);
@ -219,15 +220,15 @@ subscription_unsubscribe(th_subscription_t *s)
/**
* 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)
@ -236,27 +237,27 @@ subscription_input(void *opauqe, streaming_message_t *sm)
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;
}
@ -320,11 +321,11 @@ subscription_create_from_channel(channel_t *ch, unsigned int weight,
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\"",
@ -332,7 +333,7 @@ subscription_create_from_channel(channel_t *ch, unsigned int weight,
} 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\", "
@ -344,9 +345,9 @@ subscription_create_from_channel(channel_t *ch, unsigned int weight,
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;
}
@ -356,15 +357,15 @@ subscription_create_from_channel(channel_t *ch, unsigned int weight,
*
*/
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",
@ -374,7 +375,7 @@ subscription_create_from_transport(th_transport_t *t, const char *name,
}
}
t->tht_setsourceinfo(t, &si);
t->s_setsourceinfo(t, &si);
tvhlog(LOG_INFO, "subscription",
"\"%s\" direct subscription to adapter: \"%s\", "
@ -386,10 +387,10 @@ subscription_create_from_transport(th_transport_t *t, const char *name,
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;
}
@ -426,7 +427,7 @@ dummy_callback(void *opauqe, streaming_message_t *sm)
fprintf(stderr, "dummysubscription STOP\n");
break;
case SMT_TRANSPORT_STATUS:
case SMT_SERVICE_STATUS:
fprintf(stderr, "dummsubscription: %x\n", sm->sm_code);
break;
default:
@ -454,7 +455,7 @@ dummy_retry(void *opaque)
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) {
@ -464,7 +465,7 @@ subscription_dummy_join(const char *id, int 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;
@ -472,7 +473,7 @@ subscription_dummy_join(const char *id, int first)
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);

View file

@ -27,9 +27,9 @@ typedef struct th_subscription {
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;
@ -39,8 +39,8 @@ typedef struct th_subscription {
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 */
@ -67,23 +67,23 @@ void subscription_set_weight(th_subscription_t *s, unsigned int weight);
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);

View file

@ -31,9 +31,9 @@
#include "tvheadend.h"
#include "teletext.h"
#include "transports.h"
#include "packet.h"
#include "streaming.h"
#include "service.h"
/**
*
@ -61,7 +61,7 @@ typedef struct tt_private {
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)
@ -236,7 +236,7 @@ is_tt_clock(const uint8_t *str)
*
*/
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;
@ -250,17 +250,17 @@ update_tt_clock(th_transport_t *t, const uint8_t *buf)
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;
@ -315,7 +315,7 @@ extract_subtitle(th_transport_t *t, th_stream_t *st,
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 */
@ -354,14 +354,14 @@ dump_page(tt_mag_t *ttm)
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);
@ -373,7 +373,7 @@ tt_subtitle_deliver(th_transport_t *t, th_stream_t *parent, tt_mag_t *ttm)
*
*/
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;
@ -429,7 +429,7 @@ tt_decode_line(th_transport_t *t, th_stream_t *st, uint8_t *buf)
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;
@ -453,7 +453,7 @@ tt_decode_line(th_transport_t *t, th_stream_t *st, uint8_t *buf)
*
*/
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;
@ -475,7 +475,7 @@ teletext_scan_stream(th_transport_t *t, th_stream_t *st)
*
*/
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;
@ -562,11 +562,11 @@ teletext_rundown_copy(tt_private_t *ttp, tt_mag_t *ttm)
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)
@ -586,9 +586,9 @@ teletext_rundown_scan(th_transport_t *t, tt_private_t *ttp)
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;
}
}

View file

@ -19,6 +19,7 @@
#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 */

File diff suppressed because it is too large Load diff

View file

@ -1,105 +0,0 @@
/*
* 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 */

View file

@ -34,14 +34,13 @@
#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
@ -51,10 +50,10 @@ got_section(const uint8_t *data, size_t len, void *opaque)
{
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);
@ -66,13 +65,13 @@ got_section(const uint8_t *data, size_t len, void *opaque)
* 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);
@ -84,9 +83,9 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, const uint8_t *tsb)
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
@ -119,7 +118,7 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, const uint8_t *tsb)
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;
}
@ -132,7 +131,7 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, const uint8_t *tsb)
* 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;
@ -167,11 +166,11 @@ ts_extract_pcr(th_transport_t *t, th_stream_t *st, const uint8_t *tsb,
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;
@ -179,67 +178,67 @@ ts_extract_pcr(th_transport_t *t, th_stream_t *st, const uint8_t *tsb,
}
/**
* 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;
}
@ -249,16 +248,16 @@ ts_recv_packet1(th_transport_t *t, const uint8_t *tsb, int64_t *pcrp)
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);
}
@ -266,12 +265,12 @@ ts_recv_packet1(th_transport_t *t, const uint8_t *tsb, int64_t *pcrp)
* 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);
}
@ -280,7 +279,7 @@ ts_recv_packet2(th_transport_t *t, const uint8_t *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);
@ -288,5 +287,5 @@ ts_remux(th_transport_t *t, const uint8_t *src)
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);
}

View file

@ -19,8 +19,8 @@
#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 */

View file

@ -193,11 +193,11 @@ ts_check_deliver(tsmuxer_t *tsm, tsmuxer_es_t *te)
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;
@ -691,7 +691,7 @@ ts_muxer_send_packet(ts_muxer_t *ts)
int i;
int64_t t, tlow, pcr;
uint8_t *d;
th_transport_t *tr;
service_t *tr;
if(ts->ts_block == 0)
return;
@ -706,7 +706,7 @@ ts_muxer_send_packet(ts_muxer_t *ts)
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;
@ -802,7 +802,7 @@ ts_muxer_generate_tables(void *aux, int64_t now)
{
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;
@ -824,7 +824,7 @@ ts_muxer_generate_tables(void *aux, int64_t now)
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;
@ -905,11 +905,11 @@ ts_deliver(void *opaque, int64_t now)
{
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);
@ -928,7 +928,7 @@ ts_deliver(void *opaque, int64_t now)
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;
@ -949,7 +949,7 @@ ts_check_deliver(ts_muxer_t *ts, th_muxstream_t *tms)
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))
@ -964,11 +964,11 @@ ts_check_deliver(ts_muxer_t *ts, th_muxstream_t *tms)
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;
@ -1367,7 +1367,7 @@ ts_muxer_play(ts_muxer_t *ts, int64_t toffset)
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 */

View file

@ -107,9 +107,9 @@ RB_HEAD(event_tree, event);
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);
@ -222,11 +222,11 @@ typedef enum {
SMT_START,
/**
* Transport status
* Service status
*
* Notification about status of source, see TSS_ flags
*/
SMT_TRANSPORT_STATUS,
SMT_SERVICE_STATUS,
/**
* Streaming stop.
@ -275,7 +275,7 @@ typedef enum {
#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
@ -339,461 +339,6 @@ typedef struct sbuf {
/**
* 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)
@ -846,7 +391,7 @@ int rate_to_sri(int rate);
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);

118
src/v4l.c
View file

@ -34,12 +34,12 @@
#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;
@ -52,7 +52,7 @@ static void v4l_adapter_notify(v4l_adapter_t *va);
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;
@ -64,9 +64,9 @@ v4l_input(v4l_adapter_t *va)
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) {
@ -79,10 +79,10 @@ v4l_input(v4l_adapter_t *va)
continue;
case 0x000001e0:
st = t->tht_video;
st = t->s_video;
break;
case 0x000001c0:
st = t->tht_audio;
st = t->s_audio;
break;
}
@ -101,7 +101,7 @@ v4l_input(v4l_adapter_t *va)
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);
@ -121,7 +121,7 @@ v4l_input(v4l_adapter_t *va)
ptr++; len--;
}
}
pthread_mutex_unlock(&t->tht_stream_mutex);
pthread_mutex_unlock(&t->s_stream_mutex);
}
@ -170,16 +170,16 @@ v4l_thread(void *aux)
*
*/
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);
@ -225,7 +225,7 @@ v4l_transport_start(th_transport_t *t, unsigned int weight, int force_start)
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;
@ -236,7 +236,7 @@ v4l_transport_start(th_transport_t *t, unsigned int weight, int force_start)
*
*/
static void
v4l_transport_refresh(th_transport_t *t)
v4l_service_refresh(service_t *t)
{
}
@ -246,12 +246,12 @@ v4l_transport_refresh(th_transport_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",
@ -262,7 +262,7 @@ v4l_transport_stop(th_transport_t *t)
close(va->va_pipe[1]);
close(va->va_fd);
va->va_current_transport = NULL;
va->va_current_service = NULL;
v4l_adapter_notify(va);
}
@ -271,25 +271,25 @@ v4l_transport_stop(th_transport_t *t)
*
*/
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);
}
@ -299,7 +299,7 @@ v4l_transport_save(th_transport_t *t)
*
*/
static int
v4l_transport_quality(th_transport_t *t)
v4l_service_quality(service_t *t)
{
return 100;
}
@ -309,7 +309,7 @@ v4l_transport_quality(th_transport_t *t)
*
*/
static int
v4l_grace_period(th_transport_t *t)
v4l_grace_period(service_t *t)
{
return 2;
}
@ -319,14 +319,14 @@ v4l_grace_period(th_transport_t *t)
* 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);
}
@ -334,10 +334,10 @@ v4l_transport_setsourceinfo(th_transport_t *t, struct source_info *si)
/**
*
*/
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);
@ -347,8 +347,8 @@ v4l_transport_find(v4l_adapter_t *va, const char *id, int create)
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;
}
@ -363,25 +363,25 @@ v4l_transport_find(v4l_adapter_t *va, const char *id, int create)
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;
}
@ -614,10 +614,10 @@ v4l_adapter_build_msg(v4l_adapter_t *va)
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 -");
@ -702,7 +702,7 @@ v4l_service_create_by_msg(v4l_adapter_t *va, htsmsg_t *c, const char *name)
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;
@ -712,10 +712,10 @@ v4l_service_create_by_msg(v4l_adapter_t *va, htsmsg_t *c, const char *name)
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);
}
/**

View file

@ -46,9 +46,9 @@ typedef struct v4l_adapter {
// 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 */
@ -74,8 +74,8 @@ void v4l_adapter_set_logging(v4l_adapter_t *va, int on);
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);

View file

@ -38,7 +38,6 @@
#include "psi.h"
#include "dvr/dvr.h"
#include "transports.h"
#include "serviceprobe.h"
#include "xmltv.h"
#include "epg.h"
@ -1069,16 +1068,16 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
*
*/
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);
}
}
@ -1087,11 +1086,11 @@ extjs_transport_delete(htsmsg_t *in)
*
*/
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;
@ -1101,14 +1100,14 @@ transport_update(htsmsg_t *in)
(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);
}
}
@ -1122,21 +1121,21 @@ extjs_servicedetails(http_connection_t *hc,
{
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);
@ -1186,7 +1185,7 @@ extjs_servicedetails(http_connection_t *hc,
}
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);
@ -1249,11 +1248,11 @@ extjs_mergechannel(http_connection_t *hc, const char *remain, void *opaque)
*
*/
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;
@ -1263,27 +1262,27 @@ transport_update_iptv(htsmsg_t *in)
(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
}
}
@ -1293,27 +1292,27 @@ transport_update_iptv(htsmsg_t *in)
*
*/
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;
}
@ -1321,12 +1320,12 @@ build_record_iptv(th_transport_t *t)
*
*/
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);
}
/**
@ -1339,7 +1338,7 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
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);
@ -1347,16 +1346,16 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
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]));
@ -1365,19 +1364,19 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
} 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();
@ -1403,11 +1402,11 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
*
*/
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;
@ -1417,14 +1416,14 @@ extjs_transport_update(htsmsg_t *in)
(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);
}
}

View file

@ -36,7 +36,6 @@
#include "dtable.h"
#include "channels.h"
#include "psi.h"
#include "transports.h"
#include "serviceprobe.h"
#include "dvb/dvb.h"
@ -113,7 +112,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
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);
@ -204,8 +203,8 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
"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);
}
}
@ -345,10 +344,10 @@ extjs_dvbmuxes(http_connection_t *hc, const char *remain, void *opaque)
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");
}
/**
@ -363,7 +362,7 @@ extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
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);
@ -382,20 +381,20 @@ extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
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]));
@ -404,7 +403,7 @@ extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
} else if(!strcmp(op, "update")) {
if(in != NULL)
extjs_transport_update(in);
extjs_service_update(in);
out = htsmsg_create_map();

View file

@ -37,7 +37,6 @@
#include "psi.h"
#include "v4l.h"
#include "transports.h"
#include "serviceprobe.h"
@ -133,11 +132,11 @@ extjs_v4ladapter(http_connection_t *hc, const char *remain, void *opaque)
*
*/
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;
@ -147,17 +146,17 @@ transport_update_v4l(htsmsg_t *in)
(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
}
}
@ -167,15 +166,15 @@ transport_update_v4l(htsmsg_t *in)
*
*/
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;
}
@ -183,12 +182,12 @@ build_record_v4l(th_transport_t *t)
*
*/
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;
}
/**
@ -202,7 +201,7 @@ extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
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);
@ -216,16 +215,16 @@ extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
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]));
@ -234,19 +233,19 @@ extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
} 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();

View file

@ -36,8 +36,6 @@
#include "dvb/dvb_support.h"
#endif
#include "transports.h"
extern char tvh_binshasum[20];
extern char *htsversion_full;
@ -83,16 +81,16 @@ dumpchannels(htsbuf_queue_t *hq)
#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, "",
@ -106,7 +104,7 @@ dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent)
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),

View file

@ -237,7 +237,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq)
run = 0;
break;
case SMT_TRANSPORT_STATUS:
case SMT_SERVICE_STATUS:
//printf("SMT_TRANSPORT_STATUS\n");
break;

View file

@ -37,9 +37,9 @@ void extjs_list_v4l_adapters(htsmsg_t *array);
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);
/**