Rename transport -> service
This commit is contained in:
parent
76c3336e4e
commit
85132732b6
51 changed files with 2051 additions and 2619 deletions
2
Makefile
2
Makefile
|
@ -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 \
|
||||
|
|
83
src/capmt.c
83
src/capmt.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
224
src/cwc.c
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "dvb_support.h"
|
||||
#include "diseqc.h"
|
||||
#include "notify.h"
|
||||
#include "transports.h"
|
||||
#include "dvr/dvr.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
23
src/htsp.c
23
src/htsp.c
|
@ -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:
|
||||
|
|
237
src/iptv_input.c
237
src/iptv_input.c
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "parsers.h"
|
||||
#include "parser_h264.h"
|
||||
#include "bitstream.h"
|
||||
#include "service.h"
|
||||
|
||||
/**
|
||||
* H.264 parser, nal escaper
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
93
src/psi.c
93
src/psi.c
|
@ -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);
|
||||
|
|
11
src/psi.h
11
src/psi.h
|
@ -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_ */
|
||||
|
|
|
@ -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
1069
src/service.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
1069
src/transports.c
1069
src/transports.c
File diff suppressed because it is too large
Load diff
105
src/transports.h
105
src/transports.h
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
26
src/tsmux.c
26
src/tsmux.c
|
@ -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 */
|
||||
|
||||
|
|
469
src/tvheadend.h
469
src/tvheadend.h
|
@ -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
118
src/v4l.c
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue