linxudvb: remove deprecated code
Some bits are still incomplete, but I can refer to copies from now on.
This commit is contained in:
parent
9c40f25c6f
commit
e4a510deb6
17 changed files with 0 additions and 6584 deletions
|
@ -1,122 +0,0 @@
|
|||
#include <time.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "diseqc.h"
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static inline void
|
||||
msleep(uint32_t msec)
|
||||
{
|
||||
struct timespec req = { msec / 1000, 1000000 * (msec % 1000) };
|
||||
|
||||
while (nanosleep(&req, &req))
|
||||
;
|
||||
}
|
||||
|
||||
int
|
||||
diseqc_send_msg(int fe_fd, __u8 framing_byte, __u8 address, __u8 cmd,
|
||||
__u8 data_1, __u8 data_2, __u8 data_3, __u8 msg_len)
|
||||
{
|
||||
int err;
|
||||
struct dvb_diseqc_master_cmd message;
|
||||
|
||||
tvhtrace("diseqc", "sending %X %X %X %X %X %X",
|
||||
framing_byte, address, cmd, data_1, data_2, data_3);
|
||||
|
||||
message.msg[0] = framing_byte;
|
||||
message.msg[1] = address;
|
||||
message.msg[2] = cmd;
|
||||
message.msg[3] = data_1;
|
||||
message.msg[4] = data_2;
|
||||
message.msg[5] = data_3;
|
||||
message.msg_len = msg_len;
|
||||
if ((err = ioctl(fe_fd, FE_DISEQC_SEND_MASTER_CMD, &message))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error sending diseqc command");
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
diseqc_setup(int fe_fd, int lnb_num, int voltage, int band,
|
||||
uint32_t version, uint32_t repeats)
|
||||
{
|
||||
int i = (lnb_num % 4) * 4 + voltage * 2 + (band ? 1 : 0);
|
||||
int j = lnb_num / 4;
|
||||
int k, err;
|
||||
|
||||
tvhtrace("diseqc",
|
||||
"fe_fd=%i, lnb_num=%i, voltage=%i, band=%i, version=%i, repeats=%i",
|
||||
fe_fd, lnb_num, voltage, band, version, repeats);
|
||||
|
||||
/* verify lnb number and diseqc data */
|
||||
if(lnb_num < 0 || lnb_num >=64 || i < 0 || i >= 16 || j < 0 || j >= 16)
|
||||
return -1;
|
||||
|
||||
/* turn off continuous tone */
|
||||
tvhtrace("diseqc", "disabling continuous tone");
|
||||
if ((err = ioctl(fe_fd, FE_SET_TONE, SEC_TONE_OFF))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error trying to turn off continuous tone");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* set lnb voltage */
|
||||
tvhtrace("diseqc", "setting lnb voltage to %iV", (i/2) % 2 ? 18 : 13);
|
||||
if ((err = ioctl(fe_fd, FE_SET_VOLTAGE, (i/2) % 2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error setting lnb voltage");
|
||||
return err;
|
||||
}
|
||||
msleep(15);
|
||||
|
||||
if (repeats == 0) { /* uncommited msg, wait 15ms, commited msg */
|
||||
if ((err = diseqc_send_msg(fe_fd, 0xE0, 0x10, 0x39, 0xF0 | j, 0, 0, 4)))
|
||||
return err;
|
||||
msleep(15);
|
||||
if ((err = diseqc_send_msg(fe_fd, 0xE0, 0x10, 0x38, 0xF0 | i, 0, 0, 4)))
|
||||
return err;
|
||||
} else { /* commited msg, 25ms, uncommited msg, 25ms, commited msg, etc */
|
||||
if ((err = diseqc_send_msg(fe_fd, 0xE0, 0x10, 0x38, 0xF0 | i, 0, 0, 4)))
|
||||
return err;
|
||||
for (k = 0; k < repeats; k++) {
|
||||
msleep(25);
|
||||
if ((err = diseqc_send_msg(fe_fd, 0xE0, 0x10, 0x39, 0xF0 | j, 0, 0, 4)))
|
||||
return err;
|
||||
msleep(25);
|
||||
if ((err = diseqc_send_msg(fe_fd, 0xE1, 0x10, 0x38, 0xF0 | i, 0, 0, 4)))
|
||||
return err;
|
||||
}
|
||||
}
|
||||
msleep(15);
|
||||
|
||||
/* set toneburst */
|
||||
tvhtrace("diseqc", (i/4) % 2 ? "sending mini diseqc B" : "sending mini diseqc A");
|
||||
if ((err = ioctl(fe_fd, FE_DISEQC_SEND_BURST, (i/4) % 2 ? SEC_MINI_B : SEC_MINI_A))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error sending mini diseqc command");
|
||||
return err;
|
||||
}
|
||||
msleep(15);
|
||||
|
||||
/* set continuous tone */
|
||||
tvhtrace("diseqc", i % 2 ? "enabling continous tone" : "disabling continuous tone");
|
||||
if ((err = ioctl(fe_fd, FE_SET_TONE, i % 2 ? SEC_TONE_ON : SEC_TONE_OFF))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error setting continuous tone");
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
diseqc_voltage_off(int fe_fd)
|
||||
{
|
||||
int err;
|
||||
|
||||
tvhtrace("diseqc", "sending diseqc voltage off command");
|
||||
if ((err = ioctl(fe_fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF))) {
|
||||
tvhlog(LOG_ERR, "diseqc", "error sending diseqc voltage off command");
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#ifndef __DISEQC_H__
|
||||
#define __DISEQC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
/**
|
||||
* set up the switch to position/voltage/tone
|
||||
*/
|
||||
int diseqc_send_msg(int fe_fd, __u8 framing_byte, __u8 address, __u8 cmd,
|
||||
__u8 data_1, __u8 data_2, __u8 data_3, __u8 msg_len);
|
||||
int diseqc_setup(int fe_fd, int lnb_num, int voltage, int band,
|
||||
uint32_t version, uint32_t repeats);
|
||||
int diseqc_voltage_off(int fe_fd);
|
||||
|
||||
#endif
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_support.h"
|
||||
#include "dvb_charset.h"
|
||||
|
||||
void
|
||||
dvb_init(uint32_t adapter_mask, const char *rawfile)
|
||||
{
|
||||
TAILQ_INIT(&dvb_adapters);
|
||||
dvb_charset_init();
|
||||
dvb_network_init();
|
||||
dvb_linux_init();
|
||||
}
|
|
@ -1,640 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* 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 DVB_H_
|
||||
#define DVB_H_
|
||||
|
||||
#include <linux/dvb/version.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <pthread.h>
|
||||
#include "htsmsg.h"
|
||||
#include "psi.h"
|
||||
#include "idnode.h"
|
||||
|
||||
struct service;
|
||||
struct th_dvb_table;
|
||||
struct th_dvb_mux_instance;
|
||||
|
||||
#define TDA_OPT_FE 0x1
|
||||
#define TDA_OPT_DVR 0x2
|
||||
#define TDA_OPT_DMX 0x4
|
||||
#define TDA_OPT_PWR 0x8
|
||||
#define TDA_OPT_ALL (TDA_OPT_FE | TDA_OPT_DVR | TDA_OPT_DMX | TDA_OPT_PWR)
|
||||
|
||||
#define DVB_VER_INT(maj,min) (((maj) << 16) + (min))
|
||||
|
||||
#define DVB_VER_ATLEAST(maj, min) \
|
||||
(DVB_VER_INT(DVB_API_VERSION, DVB_API_VERSION_MINOR) >= DVB_VER_INT(maj, min))
|
||||
|
||||
TAILQ_HEAD(th_dvb_adapter_queue, th_dvb_adapter);
|
||||
LIST_HEAD(th_dvb_adapter_list, th_dvb_adapter);
|
||||
TAILQ_HEAD(th_dvb_mux_instance_queue, th_dvb_mux_instance);
|
||||
LIST_HEAD(th_dvb_mux_instance_list, th_dvb_mux_instance);
|
||||
TAILQ_HEAD(dvb_satconf_queue, dvb_satconf);
|
||||
LIST_HEAD(dvb_mux_list, dvb_mux);
|
||||
TAILQ_HEAD(dvb_mux_queue, dvb_mux);
|
||||
LIST_HEAD(dvb_network_list, dvb_network);
|
||||
TAILQ_HEAD(dvb_hardware_queue, dvb_hardware);
|
||||
|
||||
/**
|
||||
* Satconf
|
||||
*/
|
||||
typedef struct dvb_satconf {
|
||||
char *sc_id;
|
||||
TAILQ_ENTRY(dvb_satconf) sc_adapter_link;
|
||||
int sc_port; // diseqc switchport (0 - 63)
|
||||
|
||||
char *sc_name;
|
||||
char *sc_comment;
|
||||
char *sc_lnb;
|
||||
|
||||
} dvb_satconf_t;
|
||||
|
||||
|
||||
enum polarisation {
|
||||
POLARISATION_HORIZONTAL = 0x00,
|
||||
POLARISATION_VERTICAL = 0x01,
|
||||
POLARISATION_CIRCULAR_LEFT = 0x02,
|
||||
POLARISATION_CIRCULAR_RIGHT = 0x03
|
||||
};
|
||||
|
||||
#define DVB_FEC_ERROR_LIMIT 20
|
||||
|
||||
typedef struct dvb_frontend_parameters dvb_frontend_parameters_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct dvb_mux_conf {
|
||||
dvb_frontend_parameters_t dmc_fe_params;
|
||||
int dmc_polarisation;
|
||||
// dvb_satconf_t *dmc_satconf;
|
||||
#if DVB_API_VERSION >= 5
|
||||
fe_modulation_t dmc_fe_modulation;
|
||||
fe_delivery_system_t dmc_fe_delsys;
|
||||
fe_rolloff_t dmc_fe_rolloff;
|
||||
#endif
|
||||
} dvb_mux_conf_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct dvb_network {
|
||||
idnode_t dn_id;
|
||||
|
||||
LIST_ENTRY(dvb_network) dn_global_link;
|
||||
|
||||
struct dvb_mux_queue dn_initial_scan_pending_queue;
|
||||
struct dvb_mux_queue dn_initial_scan_current_queue;
|
||||
int dn_initial_scan_num_mux;
|
||||
gtimer_t dn_initial_scan_timer;
|
||||
|
||||
struct dvb_mux *dn_mux_epg;
|
||||
|
||||
int dn_fe_type; // Frontend types for this network (FE_QPSK, etc)
|
||||
|
||||
struct dvb_mux_list dn_muxes;
|
||||
|
||||
uint32_t dn_disable_pmt_monitor;
|
||||
uint32_t dn_autodiscovery;
|
||||
uint32_t dn_nitoid;
|
||||
uint32_t dn_skip_checksubscr;
|
||||
|
||||
char *dn_name; // User configured name
|
||||
|
||||
struct th_dvb_adapter_list dn_adapters;
|
||||
|
||||
} dvb_network_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct dvb_mux {
|
||||
idnode_t dm_id;
|
||||
LIST_ENTRY(dvb_mux) dm_network_link;
|
||||
dvb_network_t *dm_dn;
|
||||
|
||||
struct service_list dm_services;
|
||||
|
||||
dvb_mux_conf_t dm_conf;
|
||||
|
||||
uint32_t dm_network_id;
|
||||
uint16_t dm_transport_stream_id;
|
||||
char *dm_network_name; /* Name of network, from NIT table */
|
||||
char *dm_default_authority;
|
||||
|
||||
TAILQ_HEAD(, epggrab_ota_mux) dm_epg_grab;
|
||||
|
||||
gtimer_t dm_initial_scan_timeout;
|
||||
|
||||
TAILQ_ENTRY(dvb_mux) dm_scan_link;
|
||||
enum {
|
||||
DM_SCAN_DONE, // All done
|
||||
DM_SCAN_PENDING, // Waiting to be tuned for initial scan
|
||||
DM_SCAN_CURRENT, // Currently tuned for initial scan
|
||||
} dm_scan_status;
|
||||
|
||||
LIST_HEAD(, th_dvb_table) dm_tables;
|
||||
int dm_num_tables;
|
||||
|
||||
TAILQ_HEAD(, th_dvb_table) dm_table_queue;
|
||||
// int dm_table_initial;
|
||||
|
||||
struct th_dvb_mux_instance *dm_current_tdmi;
|
||||
|
||||
struct th_dvb_mux_instance_list dm_tdmis;
|
||||
|
||||
// Derived from dm_conf (more or less)
|
||||
char *dm_local_identifier;
|
||||
|
||||
int dm_enabled;
|
||||
|
||||
} dvb_mux_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DVB Mux instance
|
||||
*/
|
||||
typedef struct th_dvb_mux_instance {
|
||||
|
||||
dvb_mux_t *tdmi_mux;
|
||||
LIST_ENTRY(th_dvb_mux_instance) tdmi_mux_link;
|
||||
|
||||
struct th_dvb_adapter *tdmi_adapter;
|
||||
LIST_ENTRY(th_dvb_mux_instance) tdmi_adapter_link;
|
||||
|
||||
|
||||
uint16_t tdmi_signal;
|
||||
uint32_t tdmi_ber, tdmi_unc;
|
||||
float tdmi_unc_avg;
|
||||
float tdmi_snr;
|
||||
|
||||
#define TDMI_FEC_ERR_HISTOGRAM_SIZE 10
|
||||
uint32_t tdmi_fec_err_histogram[TDMI_FEC_ERR_HISTOGRAM_SIZE];
|
||||
int tdmi_fec_err_ptr;
|
||||
|
||||
|
||||
enum {
|
||||
TDMI_FE_UNKNOWN,
|
||||
TDMI_FE_NO_SIGNAL,
|
||||
TDMI_FE_FAINT_SIGNAL,
|
||||
TDMI_FE_BAD_SIGNAL,
|
||||
TDMI_FE_CONSTANT_FEC,
|
||||
TDMI_FE_BURSTY_FEC,
|
||||
TDMI_FE_OK,
|
||||
} tdmi_fe_status;
|
||||
|
||||
int tdmi_quality;
|
||||
|
||||
int tdmi_tune_failed; // Adapter failed to tune this frequency
|
||||
// Don't try again
|
||||
|
||||
struct th_subscription_list tdmi_subscriptions;
|
||||
|
||||
} th_dvb_mux_instance_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* When in raw mode we need to enqueue raw TS packet
|
||||
* to a different thread because we need to hold
|
||||
* global_lock when doing delivery of the tables
|
||||
*/
|
||||
TAILQ_HEAD(dvb_table_feed_queue, dvb_table_feed);
|
||||
|
||||
typedef struct dvb_table_feed {
|
||||
TAILQ_ENTRY(dvb_table_feed) dtf_link;
|
||||
uint8_t dtf_tsb[188];
|
||||
} dvb_table_feed_t;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dvb_hardware refers to any kind of DVB hardware
|
||||
*
|
||||
* This includes
|
||||
*
|
||||
* DVB Adapters (On linux: /dev/dvb/adapterX)
|
||||
* DVB Frontends (On linux: /dev/dvb/adapterX/frontendX)
|
||||
* DVB-S LNBs
|
||||
* Diseqc equipment (Switches, motors, etc)
|
||||
*
|
||||
*/
|
||||
typedef struct dvb_hardware {
|
||||
idnode_t dh_id;
|
||||
|
||||
// Hierarcy
|
||||
struct dvb_hardware *dh_parent;
|
||||
TAILQ_ENTRY(dvb_hardware) dh_parent_link;
|
||||
struct dvb_hardware_queue dh_childs;
|
||||
|
||||
// If attached to a network, this is set
|
||||
dvb_network_t *dh_dn;
|
||||
LIST_ENTRY(th_dvb_adapter) dh_network_link;
|
||||
|
||||
// These are created on-demand whenever this particular network
|
||||
// attachment point tunes to a mux
|
||||
struct th_dvb_mux_instance_list dh_tdmis;
|
||||
th_dvb_mux_instance_t *dh_current_tdmi;
|
||||
|
||||
char *dh_name;
|
||||
|
||||
} dvb_hardware_t;
|
||||
|
||||
|
||||
/**
|
||||
* DVB Adapter (one of these per physical adapter)
|
||||
*/
|
||||
typedef struct th_dvb_adapter {
|
||||
|
||||
#if 1
|
||||
int tda_instance;
|
||||
|
||||
|
||||
TAILQ_ENTRY(th_dvb_adapter) tda_global_link;
|
||||
|
||||
dvb_network_t *tda_dn;
|
||||
LIST_ENTRY(th_dvb_adapter) tda_network_link;
|
||||
|
||||
struct th_dvb_mux_instance_list tda_tdmis;
|
||||
|
||||
th_dvb_mux_instance_t *tda_current_tdmi;
|
||||
char *tda_tune_reason; // Reason for last tune
|
||||
|
||||
int tda_table_epollfd;
|
||||
|
||||
uint32_t tda_enabled;
|
||||
|
||||
int tda_locked;
|
||||
time_t tda_fe_monitor;
|
||||
|
||||
const char *tda_rootpath;
|
||||
char *tda_identifier;
|
||||
uint32_t tda_idleclose;
|
||||
uint32_t tda_skip_initialscan;
|
||||
uint32_t tda_qmon;
|
||||
uint32_t tda_poweroff;
|
||||
uint32_t tda_sidtochan;
|
||||
uint32_t tda_diseqc_version;
|
||||
uint32_t tda_diseqc_repeats;
|
||||
int32_t tda_full_mux_rx;
|
||||
uint32_t tda_grace_period;
|
||||
uint32_t tda_snr_valid;
|
||||
char *tda_displayname;
|
||||
|
||||
int tda_fe_type;
|
||||
struct dvb_frontend_info *tda_fe_info; // result of FE_GET_INFO ioctl()
|
||||
|
||||
char *tda_fe_path;
|
||||
int tda_fe_fd;
|
||||
|
||||
int tda_adapter_num;
|
||||
|
||||
char *tda_demux_path;
|
||||
|
||||
char *tda_dvr_path;
|
||||
pthread_t tda_dvr_thread;
|
||||
th_pipe_t tda_dvr_pipe;
|
||||
|
||||
int tda_hostconnection;
|
||||
|
||||
pthread_mutex_t tda_delivery_mutex;
|
||||
struct service_list tda_transports; /* Currently bound transports */
|
||||
|
||||
gtimer_t tda_fe_monitor_timer;
|
||||
|
||||
int tda_sat; // Set if this adapter is a satellite receiver (DVB-S, etc)
|
||||
|
||||
struct dvb_satconf_queue tda_satconfs;
|
||||
|
||||
|
||||
uint32_t tda_last_fec;
|
||||
|
||||
int tda_unc_is_delta; /* 1 if we believe FE_READ_UNCORRECTED_BLOCKS
|
||||
* return dela values */
|
||||
|
||||
uint32_t tda_extrapriority; // extra priority for choosing the best adapter/service
|
||||
|
||||
void (*tda_open_service)(struct th_dvb_adapter *tda, struct service *s);
|
||||
void (*tda_close_service)(struct th_dvb_adapter *tda, struct service *s);
|
||||
void (*tda_open_table)(struct dvb_mux *dm, struct th_dvb_table *s);
|
||||
void (*tda_close_table)(struct dvb_mux *dm, struct th_dvb_table *s);
|
||||
|
||||
int tda_rawmode;
|
||||
|
||||
int tda_bytes;
|
||||
|
||||
// Full mux streaming, protected via the delivery mutex
|
||||
|
||||
streaming_pad_t tda_streaming_pad;
|
||||
|
||||
|
||||
struct dvb_table_feed_queue tda_table_feed;
|
||||
pthread_cond_t tda_table_feed_cond; // Bound to tda_delivery_mutex
|
||||
|
||||
// PIDs that needs to be requeued and processed as tables
|
||||
uint8_t tda_table_filter[8192];
|
||||
|
||||
#endif
|
||||
|
||||
} th_dvb_adapter_t;
|
||||
|
||||
/**
|
||||
* DVB table
|
||||
*/
|
||||
typedef struct th_dvb_table {
|
||||
/**
|
||||
* Flags, must never be changed after creation.
|
||||
* We inspect it without holding global_lock
|
||||
*/
|
||||
int tdt_flags;
|
||||
|
||||
/**
|
||||
* Cycle queue
|
||||
* Tables that did not get a fd or filter in hardware will end up here
|
||||
* waiting for any other table to be received so it can reuse that fd.
|
||||
* Only linked if fd == -1
|
||||
*/
|
||||
TAILQ_ENTRY(th_dvb_table) tdt_pending_link;
|
||||
|
||||
/**
|
||||
* File descriptor for filter
|
||||
*/
|
||||
int tdt_fd;
|
||||
|
||||
LIST_ENTRY(th_dvb_table) tdt_link;
|
||||
th_dvb_mux_instance_t *tdt_tdmi;
|
||||
|
||||
char *tdt_name;
|
||||
|
||||
void *tdt_opaque;
|
||||
int (*tdt_callback)(dvb_mux_t *dm, uint8_t *buf, int len,
|
||||
uint8_t tableid, void *opaque);
|
||||
|
||||
|
||||
int tdt_count;
|
||||
int tdt_pid;
|
||||
|
||||
int tdt_id;
|
||||
|
||||
int tdt_table;
|
||||
int tdt_mask;
|
||||
|
||||
int tdt_destroyed;
|
||||
int tdt_refcount;
|
||||
|
||||
psi_section_t tdt_sect; // Manual reassembly
|
||||
|
||||
} th_dvb_table_t;
|
||||
|
||||
|
||||
extern struct dvb_network_list dvb_networks;
|
||||
extern struct dvb_hardware_queue dvb_adapters;
|
||||
|
||||
void dvb_init(uint32_t adapter_mask, const char *rawfile);
|
||||
|
||||
/**
|
||||
* DVB Adapter
|
||||
*/
|
||||
void dvb_adapter_init(uint32_t adapter_mask, const char *rawfile);
|
||||
|
||||
void dvb_adapter_start(th_dvb_adapter_t *tda, int opt);
|
||||
|
||||
void dvb_adapter_stop(th_dvb_adapter_t *tda, int opt);
|
||||
|
||||
void dvb_adapter_notify(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_adapter_build_msg(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_fe_opts(th_dvb_adapter_t *tda, const char *which);
|
||||
|
||||
void dvb_adapter_set_extrapriority(th_dvb_adapter_t *tda, int extrapriority);
|
||||
|
||||
void dvb_adapter_poweroff(th_dvb_adapter_t *tda);
|
||||
|
||||
void dvb_input_filtered_setup(th_dvb_adapter_t *tda);
|
||||
|
||||
void dvb_input_raw_setup(th_dvb_adapter_t *tda);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DVB Multiplex
|
||||
*/
|
||||
const char* dvb_mux_fec2str(int fec);
|
||||
const char* dvb_mux_delsys2str(int delsys);
|
||||
const char* dvb_mux_qam2str(int qam);
|
||||
const char* dvb_mux_rolloff2str(int rolloff);
|
||||
|
||||
int dvb_mux_str2bw(const char *str);
|
||||
int dvb_mux_str2qam(const char *str);
|
||||
int dvb_mux_str2fec(const char *str);
|
||||
int dvb_mux_str2mode(const char *str);
|
||||
int dvb_mux_str2guard(const char *str);
|
||||
int dvb_mux_str2hier(const char *str);
|
||||
|
||||
void dvb_mux_save(dvb_mux_t *dm);
|
||||
|
||||
void dvb_mux_load(dvb_network_t *dn);
|
||||
|
||||
void dvb_mux_destroy(dvb_mux_t *dm);
|
||||
|
||||
dvb_mux_t *dvb_mux_create(dvb_network_t *tda,
|
||||
const struct dvb_mux_conf *dmc,
|
||||
uint16_t onid, uint16_t tsid, const char *network,
|
||||
const char *logprefix, int enabled,
|
||||
int initialscan, const char *uuid,
|
||||
dvb_satconf_t *satconf, int create, dvb_mux_t *src);
|
||||
|
||||
int dvb_mux_tune(dvb_mux_t *dm, const char *reason, int weight);
|
||||
|
||||
void dvb_mux_set_networkname(dvb_mux_t *dm, const char *name);
|
||||
|
||||
void dvb_mux_set_tsid(dvb_mux_t *dm, uint16_t tsid, int force);
|
||||
|
||||
void dvb_mux_set_onid(dvb_mux_t *mux, uint16_t onid, int force);
|
||||
|
||||
void dvb_mux_set_enable(th_dvb_mux_instance_t *tdmi, int enabled);
|
||||
|
||||
void dvb_mux_set_satconf(th_dvb_mux_instance_t *tdmi, const char *scid,
|
||||
int save);
|
||||
|
||||
htsmsg_t *dvb_mux_build_msg(dvb_mux_t *dm);
|
||||
|
||||
void dvb_mux_notify(dvb_mux_t *dm);
|
||||
|
||||
const char *dvb_mux_add_by_params(dvb_network_t *dn,
|
||||
int freq,
|
||||
int symrate,
|
||||
int bw,
|
||||
int constellation,
|
||||
int delsys,
|
||||
int tmode,
|
||||
int guard,
|
||||
int hier,
|
||||
int fechi,
|
||||
int feclo,
|
||||
int fec,
|
||||
int polarisation,
|
||||
const char *satconf);
|
||||
#if 0
|
||||
int dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src,
|
||||
dvb_satconf_t *satconf);
|
||||
#endif
|
||||
|
||||
dvb_mux_t *dvb_mux_find(dvb_network_t *dn, const char *netname, uint16_t onid,
|
||||
uint16_t tsid, int enabled);
|
||||
|
||||
|
||||
void dvb_mux_stop(th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
void dvb_mux_initial_scan_done(dvb_mux_t *dm);
|
||||
|
||||
int dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi, const char *reason);
|
||||
|
||||
void dvb_create_tdmis(dvb_mux_t *dm);
|
||||
|
||||
int tdmi_current_weight(const th_dvb_mux_instance_t *tdmi);
|
||||
|
||||
|
||||
/**
|
||||
* DVB Transport (aka DVB service)
|
||||
*/
|
||||
void dvb_service_load(dvb_mux_t *dm);
|
||||
|
||||
struct service *dvb_service_find(dvb_mux_t *dm,
|
||||
uint16_t sid, int pmt_pid,
|
||||
const char *identifier);
|
||||
|
||||
struct service *dvb_service_find2(dvb_mux_t *dm,
|
||||
uint16_t sid, int pmt_pid,
|
||||
const char *identifier, int *save);
|
||||
|
||||
struct service *dvb_service_find3(dvb_network_t *dn,
|
||||
dvb_mux_t *dm,
|
||||
const char *netname, uint16_t onid,
|
||||
uint16_t tsid, uint16_t sid,
|
||||
int enabled, int epgprimary);
|
||||
|
||||
void dvb_service_notify(struct service *t);
|
||||
|
||||
void dvb_service_notify_by_adapter(th_dvb_adapter_t *tda);
|
||||
|
||||
/**
|
||||
* DVB Frontend
|
||||
*/
|
||||
|
||||
//void dvb_fe_stop(th_dvb_adapter_t *tda, int retune);
|
||||
|
||||
|
||||
/**
|
||||
* DVB Tables
|
||||
*/
|
||||
void dvb_table_init(th_dvb_adapter_t *tda);
|
||||
|
||||
void dvb_table_add_default(dvb_mux_t *dm);
|
||||
|
||||
void dvb_table_flush_all(dvb_mux_t *dm);
|
||||
|
||||
void dvb_table_add_pmt(dvb_mux_t *dm, int pmt_pid);
|
||||
|
||||
void dvb_table_rem_pmt(dvb_mux_t *dm, int pmt_pid);
|
||||
|
||||
void tdt_add(dvb_mux_t *dm, int table, int mask,
|
||||
int (*callback)(dvb_mux_t *dm, uint8_t *buf, int len,
|
||||
uint8_t tableid, void *opaque), void *opaque,
|
||||
const char *name, int flags, int pid);
|
||||
|
||||
int dvb_pidx11_callback(dvb_mux_t *dm, uint8_t *ptr, int len,
|
||||
uint8_t tableid, void *opaque);
|
||||
|
||||
#define TDT_CRC 0x1
|
||||
#define TDT_QUICKREQ 0x2
|
||||
#define TDT_CA 0x4
|
||||
#define TDT_TDT 0x8
|
||||
|
||||
void dvb_table_dispatch(uint8_t *sec, int r, th_dvb_table_t *tdt);
|
||||
|
||||
void dvb_table_release(th_dvb_table_t *tdt);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
dvb_network_t *dvb_network_create(int fe_type, const char *uuid);
|
||||
|
||||
//void dvb_network_mux_scanner(void *aux);
|
||||
|
||||
void dvb_network_init(void);
|
||||
|
||||
idnode_t **dvb_network_root(void);
|
||||
|
||||
void dvb_network_schedule_initial_scan(dvb_network_t *dn);
|
||||
|
||||
|
||||
/**
|
||||
* Satellite configuration
|
||||
*/
|
||||
void dvb_satconf_init(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_satconf_list(th_dvb_adapter_t *tda);
|
||||
|
||||
htsmsg_t *dvb_lnblist_get(void);
|
||||
|
||||
dvb_satconf_t *dvb_satconf_entry_find(th_dvb_adapter_t *tda,
|
||||
const char *id, int create);
|
||||
|
||||
void dvb_lnb_get_frequencies(const char *id,
|
||||
int *f_low, int *f_hi, int *f_switch);
|
||||
|
||||
|
||||
/**
|
||||
* Raw demux
|
||||
*/
|
||||
struct th_subscription;
|
||||
struct th_subscription *dvb_subscription_create_from_tdmi(th_dvb_mux_instance_t *tdmi,
|
||||
const char *name,
|
||||
streaming_target_t *st,
|
||||
const char *hostname,
|
||||
const char *username,
|
||||
const char *client);
|
||||
|
||||
|
||||
/**
|
||||
* DVB Hardware
|
||||
*/
|
||||
idnode_t **dvb_hardware_get_childs(struct idnode *self);
|
||||
const char *dvb_hardware_get_title(struct idnode *self);
|
||||
|
||||
void *dvb_hardware_create(const idclass_t *class, size_t size,
|
||||
dvb_hardware_t *parent, const char *uuid,
|
||||
const char *name);
|
||||
|
||||
void dvb_linux_init(void);
|
||||
|
||||
#endif /* DVB_H_ */
|
||||
|
|
@ -1,502 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_support.h"
|
||||
#include "tsdemux.h"
|
||||
#include "notify.h"
|
||||
#include "service.h"
|
||||
#include "epggrab.h"
|
||||
#include "diseqc.h"
|
||||
#include "atomic.h"
|
||||
|
||||
static void *dvb_adapter_input_dvr(void *aux);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_start ( th_dvb_adapter_t *tda, int opt )
|
||||
{
|
||||
if(tda->tda_enabled == 0) {
|
||||
tvhlog(LOG_INFO, "dvb", "Adapter \"%s\" cannot be started - it's disabled", tda->tda_displayname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Default to ALL */
|
||||
if (!opt)
|
||||
opt = TDA_OPT_ALL;
|
||||
|
||||
/* Open front end */
|
||||
if ((opt & TDA_OPT_FE) && (tda->tda_fe_fd == -1)) {
|
||||
tda->tda_fe_fd = tvh_open(tda->tda_fe_path, O_RDWR | O_NONBLOCK, 0);
|
||||
if (tda->tda_fe_fd == -1) return;
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s opened frontend %s", tda->tda_rootpath, tda->tda_fe_path);
|
||||
}
|
||||
|
||||
/* Start DVR thread */
|
||||
if ((opt & TDA_OPT_DVR) && (tda->tda_dvr_pipe.rd == -1)) {
|
||||
int err = tvh_pipe(O_NONBLOCK, &tda->tda_dvr_pipe);
|
||||
assert(err != -1);
|
||||
pthread_create(&tda->tda_dvr_thread, NULL, dvb_adapter_input_dvr, tda);
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s started dvr thread", tda->tda_rootpath);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dvb_adapter_stop ( th_dvb_adapter_t *tda, int opt )
|
||||
{
|
||||
assert(tda->tda_current_tdmi == NULL);
|
||||
|
||||
/* Poweroff */
|
||||
if (opt & TDA_OPT_PWR)
|
||||
dvb_adapter_poweroff(tda);
|
||||
|
||||
/* Stop DVR thread */
|
||||
if ((opt & TDA_OPT_DVR) && (tda->tda_dvr_pipe.rd != -1)) {
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s stopping thread", tda->tda_rootpath);
|
||||
int err = tvh_write(tda->tda_dvr_pipe.wr, "", 1);
|
||||
assert(!err);
|
||||
pthread_join(tda->tda_dvr_thread, NULL);
|
||||
close(tda->tda_dvr_pipe.rd);
|
||||
close(tda->tda_dvr_pipe.wr);
|
||||
tda->tda_dvr_pipe.rd = -1;
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s stopped thread", tda->tda_rootpath);
|
||||
}
|
||||
|
||||
dvb_adapter_notify(tda);
|
||||
|
||||
/* Don't close FE */
|
||||
if (!tda->tda_idleclose && tda->tda_enabled) return;
|
||||
|
||||
/* Close front end */
|
||||
if ((opt & TDA_OPT_FE) && (tda->tda_fe_fd != -1)) {
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s closing frontend", tda->tda_rootpath);
|
||||
close(tda->tda_fe_fd);
|
||||
tda->tda_fe_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install RAW PES filter
|
||||
*/
|
||||
static int
|
||||
dvb_adapter_raw_filter(th_dvb_adapter_t *tda)
|
||||
{
|
||||
int dmx = -1;
|
||||
struct dmx_pes_filter_params dmx_param;
|
||||
|
||||
dmx = tvh_open(tda->tda_demux_path, O_RDWR, 0);
|
||||
if(dmx == -1) {
|
||||
tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s",
|
||||
tda->tda_demux_path, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&dmx_param, 0, sizeof(dmx_param));
|
||||
dmx_param.pid = 0x2000;
|
||||
dmx_param.input = DMX_IN_FRONTEND;
|
||||
dmx_param.output = DMX_OUT_TS_TAP;
|
||||
dmx_param.pes_type = DMX_PES_OTHER;
|
||||
dmx_param.flags = DMX_IMMEDIATE_START;
|
||||
|
||||
if(ioctl(dmx, DMX_SET_PES_FILTER, &dmx_param) == -1) {
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"Unable to configure demuxer \"%s\" for all PIDs -- %s",
|
||||
tda->tda_demux_path, strerror(errno));
|
||||
close(dmx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dmx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void *
|
||||
dvb_adapter_input_dvr(void *aux)
|
||||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
int fd = -1, i, r, c, efd, nfds, dmx = -1;
|
||||
uint8_t tsb[188 * 10];
|
||||
service_t *t;
|
||||
struct epoll_event ev;
|
||||
int delay = 10;
|
||||
|
||||
/* Install RAW demux */
|
||||
if (tda->tda_rawmode) {
|
||||
if ((dmx = dvb_adapter_raw_filter(tda)) == -1) {
|
||||
tvhlog(LOG_ALERT, "dvb", "Unable to install raw mux filter");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open DVR */
|
||||
if ((fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0)) == -1) {
|
||||
close(dmx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create poll */
|
||||
efd = epoll_create(2);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = tda->tda_dvr_pipe.rd;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, tda->tda_dvr_pipe.rd, &ev);
|
||||
ev.data.fd = fd;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
|
||||
|
||||
r = i = 0;
|
||||
while(1) {
|
||||
|
||||
/* Wait for input */
|
||||
nfds = epoll_wait(efd, &ev, 1, delay);
|
||||
|
||||
/* No data */
|
||||
if (nfds < 1) continue;
|
||||
|
||||
/* Exit */
|
||||
if (ev.data.fd != fd) break;
|
||||
|
||||
/* Read data */
|
||||
c = read(fd, tsb+r, sizeof(tsb)-r);
|
||||
if (c < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
else if (errno == EOVERFLOW) {
|
||||
tvhlog(LOG_WARNING, "dvb", "\"%s\" read() EOVERFLOW",
|
||||
tda->tda_identifier);
|
||||
continue;
|
||||
} else {
|
||||
// TODO: should we try to recover?
|
||||
tvhlog(LOG_ERR, "dvb", "\"%s\" read() error %d",
|
||||
tda->tda_identifier, errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r += c;
|
||||
atomic_add(&tda->tda_bytes, c);
|
||||
|
||||
/* not enough data */
|
||||
if (r < 188) continue;
|
||||
|
||||
int wakeup_table_feed = 0; // Just wanna wakeup once
|
||||
|
||||
pthread_mutex_lock(&tda->tda_delivery_mutex);
|
||||
|
||||
if(LIST_FIRST(&tda->tda_streaming_pad.sp_targets) != NULL) {
|
||||
streaming_message_t sm;
|
||||
pktbuf_t *pb = pktbuf_alloc(tsb, r);
|
||||
memset(&sm, 0, sizeof(sm));
|
||||
sm.sm_type = SMT_MPEGTS;
|
||||
sm.sm_data = pb;
|
||||
streaming_pad_deliver(&tda->tda_streaming_pad, &sm);
|
||||
pktbuf_ref_dec(pb);
|
||||
}
|
||||
|
||||
/* Process */
|
||||
while (r >= 188) {
|
||||
|
||||
/* sync */
|
||||
if (tsb[i] == 0x47) {
|
||||
int pid = (tsb[i+1] & 0x1f) << 8 | tsb[i+2];
|
||||
|
||||
if(tda->tda_table_filter[pid]) {
|
||||
if(!(tsb[i+1] & 0x80)) { // Only dispatch to table parser if not error
|
||||
dvb_table_feed_t *dtf = malloc(sizeof(dvb_table_feed_t));
|
||||
memcpy(dtf->dtf_tsb, tsb + i, 188);
|
||||
TAILQ_INSERT_TAIL(&tda->tda_table_feed, dtf, dtf_link);
|
||||
wakeup_table_feed = 1;
|
||||
}
|
||||
} else {
|
||||
LIST_FOREACH(t, &tda->tda_transports, s_active_link)
|
||||
ts_recv_packet1(t, tsb + i, NULL);
|
||||
}
|
||||
|
||||
i += 188;
|
||||
r -= 188;
|
||||
|
||||
/* no sync */
|
||||
} else {
|
||||
tvhlog(LOG_DEBUG, "dvb", "\"%s\" ts sync lost", tda->tda_identifier);
|
||||
if (ts_resync(tsb, &r, &i)) break;
|
||||
tvhlog(LOG_DEBUG, "dvb", "\"%s\" ts sync found", tda->tda_identifier);
|
||||
}
|
||||
}
|
||||
|
||||
if(wakeup_table_feed)
|
||||
pthread_cond_signal(&tda->tda_table_feed_cond);
|
||||
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
/* reset buffer */
|
||||
if (r) memmove(tsb, tsb+i, r);
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if(dmx != -1)
|
||||
close(dmx);
|
||||
close(efd);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_adapter_build_msg(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
int fdiv;
|
||||
|
||||
htsmsg_add_str(m, "identifier", tda->tda_identifier);
|
||||
htsmsg_add_str(m, "name", tda->tda_displayname);
|
||||
|
||||
htsmsg_add_str(m, "type", "dvb");
|
||||
|
||||
if(tda->tda_current_tdmi != NULL) {
|
||||
th_dvb_mux_instance_t *tdmi = tda->tda_current_tdmi;
|
||||
|
||||
htsmsg_add_str(m, "currentMux",
|
||||
dvb_mux_nicename(tda->tda_current_tdmi->tdmi_mux));
|
||||
|
||||
htsmsg_add_u32(m, "signal", MIN(tdmi->tdmi_signal * 100 / 65535, 100));
|
||||
htsmsg_add_u32(m, "snr", tdmi->tdmi_snr);
|
||||
htsmsg_add_u32(m, "ber", tdmi->tdmi_ber);
|
||||
htsmsg_add_u32(m, "unc", tdmi->tdmi_unc);
|
||||
htsmsg_add_u32(m, "uncavg", tdmi->tdmi_unc_avg);
|
||||
htsmsg_add_str(m, "reason", tda->tda_tune_reason);
|
||||
} else {
|
||||
htsmsg_add_str(m, "currentMux", "");
|
||||
htsmsg_add_u32(m, "signal", 0);
|
||||
htsmsg_add_u32(m, "snr", 0);
|
||||
htsmsg_add_u32(m, "ber", 0);
|
||||
htsmsg_add_u32(m, "unc", 0);
|
||||
htsmsg_add_u32(m, "uncavg", 0);
|
||||
|
||||
if(tda->tda_fe_fd == -1) {
|
||||
htsmsg_add_str(m, "reason", "Closed");
|
||||
} else {
|
||||
htsmsg_add_str(m, "reason", "Idle");
|
||||
}
|
||||
}
|
||||
|
||||
if(tda->tda_rootpath == NULL)
|
||||
return m;
|
||||
|
||||
htsmsg_add_str(m, "path", tda->tda_rootpath);
|
||||
htsmsg_add_str(m, "hostconnection",
|
||||
hostconnection2str(tda->tda_hostconnection));
|
||||
htsmsg_add_str(m, "devicename", tda->tda_fe_info->name);
|
||||
|
||||
htsmsg_add_str(m, "deliverySystem",
|
||||
dvb_adaptertype_to_str(tda->tda_fe_type) ?: "");
|
||||
|
||||
htsmsg_add_u32(m, "satConf", tda->tda_sat);
|
||||
|
||||
fdiv = tda->tda_fe_type == FE_QPSK ? 1 : 1000;
|
||||
|
||||
htsmsg_add_u32(m, "freqMin", tda->tda_fe_info->frequency_min / fdiv);
|
||||
htsmsg_add_u32(m, "freqMax", tda->tda_fe_info->frequency_max / fdiv);
|
||||
htsmsg_add_u32(m, "freqStep", tda->tda_fe_info->frequency_stepsize / fdiv);
|
||||
|
||||
htsmsg_add_u32(m, "symrateMin", tda->tda_fe_info->symbol_rate_min);
|
||||
htsmsg_add_u32(m, "symrateMax", tda->tda_fe_info->symbol_rate_max);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_adapter_notify(th_dvb_adapter_t *tda)
|
||||
{
|
||||
notify_by_msg("tvAdapter", dvb_adapter_build_msg(tda));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
fe_opts_add(htsmsg_t *a, const char *title, int value)
|
||||
{
|
||||
htsmsg_t *v = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(v, "title", title);
|
||||
htsmsg_add_u32(v, "id", value);
|
||||
htsmsg_add_msg(a, NULL, v);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_fe_opts(th_dvb_adapter_t *tda, const char *which)
|
||||
{
|
||||
htsmsg_t *a = htsmsg_create_list();
|
||||
fe_caps_t c = tda->tda_fe_info->caps;
|
||||
|
||||
if(!strcmp(which, "constellations")) {
|
||||
if(c & FE_CAN_QAM_AUTO) fe_opts_add(a, "Auto", QAM_AUTO);
|
||||
if(c & FE_CAN_QPSK) {
|
||||
fe_opts_add(a, "QPSK", QPSK);
|
||||
#if DVB_API_VERSION >= 5
|
||||
fe_opts_add(a, "PSK_8", PSK_8);
|
||||
fe_opts_add(a, "APSK_16", APSK_16);
|
||||
fe_opts_add(a, "APSK_32", APSK_32);
|
||||
#endif
|
||||
}
|
||||
if(c & FE_CAN_QAM_16) fe_opts_add(a, "QAM-16", QAM_16);
|
||||
if(c & FE_CAN_QAM_32) fe_opts_add(a, "QAM-32", QAM_32);
|
||||
if(c & FE_CAN_QAM_64) fe_opts_add(a, "QAM-64", QAM_64);
|
||||
if(c & FE_CAN_QAM_128) fe_opts_add(a, "QAM-128", QAM_128);
|
||||
if(c & FE_CAN_QAM_256) fe_opts_add(a, "QAM-256", QAM_256);
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "delsys")) {
|
||||
if(c & FE_CAN_QPSK) {
|
||||
#if DVB_API_VERSION >= 5
|
||||
fe_opts_add(a, "SYS_DVBS", SYS_DVBS);
|
||||
fe_opts_add(a, "SYS_DVBS2", SYS_DVBS2);
|
||||
#else
|
||||
fe_opts_add(a, "SYS_DVBS", -1);
|
||||
#endif
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "transmissionmodes")) {
|
||||
if(c & FE_CAN_TRANSMISSION_MODE_AUTO)
|
||||
fe_opts_add(a, "Auto", TRANSMISSION_MODE_AUTO);
|
||||
|
||||
fe_opts_add(a, "2k", TRANSMISSION_MODE_2K);
|
||||
fe_opts_add(a, "8k", TRANSMISSION_MODE_8K);
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "bandwidths")) {
|
||||
if(c & FE_CAN_BANDWIDTH_AUTO)
|
||||
fe_opts_add(a, "Auto", BANDWIDTH_AUTO);
|
||||
|
||||
fe_opts_add(a, "8 MHz", BANDWIDTH_8_MHZ);
|
||||
fe_opts_add(a, "7 MHz", BANDWIDTH_7_MHZ);
|
||||
fe_opts_add(a, "6 MHz", BANDWIDTH_6_MHZ);
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "guardintervals")) {
|
||||
if(c & FE_CAN_GUARD_INTERVAL_AUTO)
|
||||
fe_opts_add(a, "Auto", GUARD_INTERVAL_AUTO);
|
||||
|
||||
fe_opts_add(a, "1/32", GUARD_INTERVAL_1_32);
|
||||
fe_opts_add(a, "1/16", GUARD_INTERVAL_1_16);
|
||||
fe_opts_add(a, "1/8", GUARD_INTERVAL_1_8);
|
||||
fe_opts_add(a, "1/4", GUARD_INTERVAL_1_4);
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "hierarchies")) {
|
||||
if(c & FE_CAN_HIERARCHY_AUTO)
|
||||
fe_opts_add(a, "Auto", HIERARCHY_AUTO);
|
||||
|
||||
fe_opts_add(a, "None", HIERARCHY_NONE);
|
||||
fe_opts_add(a, "1", HIERARCHY_1);
|
||||
fe_opts_add(a, "2", HIERARCHY_2);
|
||||
fe_opts_add(a, "4", HIERARCHY_4);
|
||||
return a;
|
||||
}
|
||||
|
||||
if(!strcmp(which, "fec")) {
|
||||
if(c & FE_CAN_FEC_AUTO)
|
||||
fe_opts_add(a, "Auto", FEC_AUTO);
|
||||
|
||||
fe_opts_add(a, "None", FEC_NONE);
|
||||
|
||||
fe_opts_add(a, "1/2", FEC_1_2);
|
||||
fe_opts_add(a, "2/3", FEC_2_3);
|
||||
fe_opts_add(a, "3/4", FEC_3_4);
|
||||
fe_opts_add(a, "4/5", FEC_4_5);
|
||||
#if DVB_API_VERSION >= 5
|
||||
fe_opts_add(a, "3/5", FEC_3_5);
|
||||
#endif
|
||||
fe_opts_add(a, "5/6", FEC_5_6);
|
||||
fe_opts_add(a, "6/7", FEC_6_7);
|
||||
fe_opts_add(a, "7/8", FEC_7_8);
|
||||
fe_opts_add(a, "8/9", FEC_8_9);
|
||||
#if DVB_API_VERSION >= 5
|
||||
fe_opts_add(a, "9/10", FEC_9_10);
|
||||
#endif
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
if(!strcmp(which, "polarisations")) {
|
||||
fe_opts_add(a, "Horizontal", POLARISATION_HORIZONTAL);
|
||||
fe_opts_add(a, "Vertical", POLARISATION_VERTICAL);
|
||||
fe_opts_add(a, "Circular left", POLARISATION_CIRCULAR_LEFT);
|
||||
fe_opts_add(a, "Circular right", POLARISATION_CIRCULAR_RIGHT);
|
||||
return a;
|
||||
}
|
||||
|
||||
htsmsg_destroy(a);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off the adapter
|
||||
*/
|
||||
void
|
||||
dvb_adapter_poweroff(th_dvb_adapter_t *tda)
|
||||
{
|
||||
if (tda->tda_fe_fd == -1) return;
|
||||
lock_assert(&global_lock);
|
||||
if (!tda->tda_poweroff || tda->tda_fe_type != FE_QPSK)
|
||||
return;
|
||||
diseqc_voltage_off(tda->tda_fe_fd);
|
||||
tvhlog(LOG_DEBUG, "dvb", "\"%s\" is off", tda->tda_rootpath);
|
||||
}
|
|
@ -1,474 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_support.h"
|
||||
#include "diseqc.h"
|
||||
#include "notify.h"
|
||||
#include "dvr/dvr.h"
|
||||
#include "service.h"
|
||||
#include "streaming.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#include "epggrab.h"
|
||||
|
||||
/**
|
||||
* Return uncorrected block (since last read)
|
||||
*
|
||||
* Some adapters report delta themselfs, some return ever increasing value
|
||||
* we need to deal with that ourselfs
|
||||
*/
|
||||
static int
|
||||
dvb_fe_get_unc(th_dvb_adapter_t *tda)
|
||||
{
|
||||
uint32_t fec;
|
||||
int d, r;
|
||||
|
||||
if(ioctl(tda->tda_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &fec))
|
||||
return 0; // read failed, just say 0
|
||||
|
||||
if(tda->tda_unc_is_delta)
|
||||
return fec;
|
||||
|
||||
d = (int)fec - (int)tda->tda_last_fec;
|
||||
|
||||
if(d < 0) {
|
||||
tda->tda_unc_is_delta = 1;
|
||||
tvhlog(LOG_DEBUG, "dvb",
|
||||
"%s: FE_READ_UNCORRECTED_BLOCKS returns delta updates (delta=%d)",
|
||||
tda->tda_displayname, d);
|
||||
return fec;
|
||||
}
|
||||
|
||||
r = fec - tda->tda_last_fec;
|
||||
|
||||
tda->tda_last_fec = fec;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Front end monitor
|
||||
*
|
||||
* Monitor status every second
|
||||
*/
|
||||
static void
|
||||
dvb_fe_monitor(void *aux)
|
||||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
fe_status_t fe_status;
|
||||
int status, v, vv, i, fec, q, bw;
|
||||
th_dvb_mux_instance_t *tdmi = tda->tda_current_tdmi;
|
||||
signal_status_t sigstat;
|
||||
streaming_message_t sm;
|
||||
struct service *t;
|
||||
|
||||
int notify = 0;
|
||||
|
||||
if(tdmi == NULL)
|
||||
return;
|
||||
|
||||
/**
|
||||
* Read out front end status
|
||||
*/
|
||||
|
||||
if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &fe_status))
|
||||
status = TDMI_FE_UNKNOWN;
|
||||
else if(fe_status & FE_HAS_LOCK)
|
||||
status = -1;
|
||||
else if(fe_status & (FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER))
|
||||
status = TDMI_FE_BAD_SIGNAL;
|
||||
else if(fe_status & FE_HAS_SIGNAL)
|
||||
status = TDMI_FE_FAINT_SIGNAL;
|
||||
else
|
||||
status = TDMI_FE_NO_SIGNAL;
|
||||
|
||||
/**
|
||||
* Waiting for initial lock
|
||||
*/
|
||||
if(tda->tda_locked == 0) {
|
||||
|
||||
/* Read */
|
||||
if (status == -1) {
|
||||
tda->tda_locked = 1;
|
||||
dvb_adapter_start(tda, TDA_OPT_ALL);
|
||||
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
|
||||
|
||||
/* Install table handlers */
|
||||
dvb_table_add_default(tdmi->tdmi_mux);
|
||||
epggrab_mux_start(tdmi->tdmi_mux);
|
||||
|
||||
/* Service filters */
|
||||
pthread_mutex_lock(&tda->tda_delivery_mutex);
|
||||
LIST_FOREACH(t, &tda->tda_transports, s_active_link) {
|
||||
if (t->s_dvb_mux == tdmi->tdmi_mux) {
|
||||
tda->tda_open_service(tda, t);
|
||||
dvb_table_add_pmt(tdmi->tdmi_mux, t->s_pmt_pid);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
/* Re-arm (50ms) */
|
||||
} else {
|
||||
gtimer_arm_ms(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 50);
|
||||
|
||||
/* Monitor (1 per sec) */
|
||||
if (dispatch_clock < tda->tda_fe_monitor)
|
||||
return;
|
||||
tda->tda_fe_monitor = dispatch_clock + 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update stats
|
||||
*/
|
||||
if(status == -1) {
|
||||
/* Read FEC counter (delta) */
|
||||
|
||||
fec = dvb_fe_get_unc(tda);
|
||||
|
||||
if(tdmi->tdmi_unc != fec) {
|
||||
tdmi->tdmi_unc = fec;
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
tdmi->tdmi_fec_err_histogram[tdmi->tdmi_fec_err_ptr++] = fec;
|
||||
if(tdmi->tdmi_fec_err_ptr == TDMI_FEC_ERR_HISTOGRAM_SIZE)
|
||||
tdmi->tdmi_fec_err_ptr = 0;
|
||||
|
||||
v = vv = 0;
|
||||
for(i = 0; i < TDMI_FEC_ERR_HISTOGRAM_SIZE; i++) {
|
||||
if(tdmi->tdmi_fec_err_histogram[i] > DVB_FEC_ERROR_LIMIT)
|
||||
v++;
|
||||
vv += tdmi->tdmi_fec_err_histogram[i];
|
||||
}
|
||||
|
||||
float avg = (float)vv / TDMI_FEC_ERR_HISTOGRAM_SIZE;
|
||||
|
||||
if(tdmi->tdmi_unc_avg != avg) {
|
||||
tdmi->tdmi_unc_avg = avg;
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
if(v == 0) {
|
||||
status = TDMI_FE_OK;
|
||||
} else if(v == 1) {
|
||||
status = TDMI_FE_BURSTY_FEC;
|
||||
} else {
|
||||
status = TDMI_FE_CONSTANT_FEC;
|
||||
}
|
||||
|
||||
int v;
|
||||
/* bit error rate */
|
||||
if(ioctl(tda->tda_fe_fd, FE_READ_BER, &v) != -1 && v != tdmi->tdmi_ber) {
|
||||
tdmi->tdmi_ber = v;
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
/* signal strength */
|
||||
if(ioctl(tda->tda_fe_fd, FE_READ_SIGNAL_STRENGTH, &v) != -1 && v != tdmi->tdmi_signal) {
|
||||
tdmi->tdmi_signal = v;
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
/* signal/noise ratio */
|
||||
if(tda->tda_snr_valid) {
|
||||
if(ioctl(tda->tda_fe_fd, FE_READ_SNR, &v) != -1) {
|
||||
float snr = v / 10.0;
|
||||
if(tdmi->tdmi_snr != snr) {
|
||||
tdmi->tdmi_snr = snr;
|
||||
notify = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(status != tdmi->tdmi_fe_status) {
|
||||
tdmi->tdmi_fe_status = status;
|
||||
|
||||
tvhlog(LOG_DEBUG,
|
||||
"dvb", "\"%s\" on adapter \"%s\", status changed to %s",
|
||||
dvb_mux_nicename(tdmi->tdmi_mux), tda->tda_displayname,
|
||||
dvb_mux_status(tdmi));
|
||||
notify = 1;
|
||||
}
|
||||
|
||||
if(status != TDMI_FE_UNKNOWN) {
|
||||
if(tda->tda_qmon) {
|
||||
q = tdmi->tdmi_quality + (status - TDMI_FE_OK + 1);
|
||||
q = MAX(MIN(q, 100), 0);
|
||||
} else {
|
||||
q = 100;
|
||||
}
|
||||
if(q != tdmi->tdmi_quality) {
|
||||
tdmi->tdmi_quality = q;
|
||||
notify = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bw = atomic_exchange(&tda->tda_bytes, 0);
|
||||
|
||||
if(notify) {
|
||||
|
||||
#if 0 // XXX(dvbreorg)
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
|
||||
htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
|
||||
htsmsg_add_u32(m, "signal", tdmi->tdmi_signal);
|
||||
|
||||
if(tda->tda_snr_valid)
|
||||
htsmsg_add_dbl(m, "snr", tdmi->tdmi_snr);
|
||||
htsmsg_add_u32(m, "ber", tdmi->tdmi_ber);
|
||||
htsmsg_add_u32(m, "unc", tdmi->tdmi_unc);
|
||||
notify_by_msg("dvbMux", m);
|
||||
#endif
|
||||
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "identifier", tda->tda_identifier);
|
||||
htsmsg_add_u32(m, "signal", MIN(tdmi->tdmi_signal * 100 / 65535, 100));
|
||||
if(tda->tda_snr_valid)
|
||||
htsmsg_add_dbl(m, "snr", tdmi->tdmi_snr);
|
||||
htsmsg_add_u32(m, "ber", tdmi->tdmi_ber);
|
||||
htsmsg_add_u32(m, "unc", tdmi->tdmi_unc);
|
||||
htsmsg_add_dbl(m, "uncavg", tdmi->tdmi_unc_avg);
|
||||
htsmsg_add_u32(m, "bw", bw);
|
||||
notify_by_msg("tvAdapter", m);
|
||||
}
|
||||
|
||||
#if 0 // XXX(dvbreorg)
|
||||
if(store)
|
||||
dvb_mux_save(tdmi);
|
||||
#endif
|
||||
|
||||
/* Streaming message */
|
||||
sigstat.status_text = dvb_mux_status(tdmi);
|
||||
sigstat.snr = tdmi->tdmi_snr;
|
||||
sigstat.signal = tdmi->tdmi_signal;
|
||||
sigstat.ber = tdmi->tdmi_ber;
|
||||
sigstat.unc = tdmi->tdmi_unc;
|
||||
sm.sm_type = SMT_SIGNAL_STATUS;
|
||||
sm.sm_data = &sigstat;
|
||||
LIST_FOREACH(t, &tda->tda_transports, s_active_link) {
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
streaming_pad_deliver(&t->s_streaming_pad, &sm);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
#if DVB_API_VERSION >= 5
|
||||
|
||||
static struct dtv_property clear_p[] = {
|
||||
{ .cmd = DTV_CLEAR },
|
||||
};
|
||||
|
||||
static struct dtv_properties clear_cmdseq = {
|
||||
.num = 1,
|
||||
.props = clear_p
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
dvb_fe_tune_s2(th_dvb_adapter_t *tda, dvb_mux_conf_t *dmc)
|
||||
{
|
||||
struct dvb_frontend_parameters *p = &dmc->dmc_fe_params;
|
||||
int r;
|
||||
|
||||
if ((ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &clear_cmdseq)) != 0)
|
||||
return -1;
|
||||
|
||||
struct dvb_frontend_event ev;
|
||||
|
||||
/* Support for legacy satellite tune, with the new API. */
|
||||
struct dtv_property _dvbs_cmdargs[] = {
|
||||
{ .cmd = DTV_DELIVERY_SYSTEM, .u.data = dmc->dmc_fe_delsys },
|
||||
{ .cmd = DTV_FREQUENCY, .u.data = p->frequency },
|
||||
{ .cmd = DTV_MODULATION, .u.data = dmc->dmc_fe_modulation },
|
||||
{ .cmd = DTV_SYMBOL_RATE, .u.data = p->u.qpsk.symbol_rate },
|
||||
{ .cmd = DTV_INNER_FEC, .u.data = p->u.qpsk.fec_inner },
|
||||
{ .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
|
||||
{ .cmd = DTV_ROLLOFF, .u.data = dmc->dmc_fe_rolloff },
|
||||
{ .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
|
||||
{ .cmd = DTV_TUNE },
|
||||
};
|
||||
|
||||
struct dtv_properties _dvbs_cmdseq = {
|
||||
.num = 9,
|
||||
.props = _dvbs_cmdargs
|
||||
};
|
||||
|
||||
/* discard stale QPSK events */
|
||||
while (1) {
|
||||
if (ioctl(tda->tda_fe_fd, FE_GET_EVENT, &ev) == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* do tuning now */
|
||||
r = ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &_dvbs_cmdseq);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi, const char *reason)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
dvb_mux_t *dm = tdmi->tdmi_mux;
|
||||
// copy dmc, cause frequency may be change with FE_QPSK
|
||||
dvb_mux_conf_t dmc = dm->dm_conf;
|
||||
dvb_frontend_parameters_t* p = &dmc.dmc_fe_params;
|
||||
int r;
|
||||
|
||||
if(tda->tda_enabled == 0)
|
||||
return SM_CODE_TUNING_FAILED;
|
||||
|
||||
if(tda->tda_current_tdmi != NULL) {
|
||||
|
||||
if(tda->tda_current_tdmi == tdmi)
|
||||
return 0; // Already currently tuned
|
||||
|
||||
/*
|
||||
* Adapter tuned to something else.
|
||||
* But at this stage we're no longer caring about such things.
|
||||
* That should have been sorted out by our callers.
|
||||
* So let's just kick it out the current occupant
|
||||
*/
|
||||
dvb_mux_stop(tda->tda_current_tdmi);
|
||||
}
|
||||
|
||||
free(tda->tda_tune_reason);
|
||||
tda->tda_tune_reason = strdup(reason);
|
||||
|
||||
//abort();
|
||||
dvb_adapter_start(tda, TDA_OPT_FE | TDA_OPT_PWR);
|
||||
|
||||
// Make sure dvb_mux_stop() did the right thing
|
||||
assert(tda->tda_current_tdmi == NULL);
|
||||
|
||||
if(tda->tda_fe_type == FE_QPSK) {
|
||||
|
||||
/* DVB-S */
|
||||
int port, lowfreq, hifreq, switchfreq, hiband, pol, dbsbs;
|
||||
|
||||
lowfreq = 9750000;
|
||||
hifreq = 10600000;
|
||||
switchfreq = 11700000;
|
||||
port = 0;
|
||||
dbsbs = 0;
|
||||
#if 0
|
||||
dvb_satconf_t *sc;
|
||||
if((sc = dm->dm_conf.dmc_satconf) != NULL) {
|
||||
port = sc->sc_port;
|
||||
|
||||
if(sc->sc_lnb != NULL)
|
||||
dvb_lnb_get_frequencies(sc->sc_lnb, &lowfreq, &hifreq, &switchfreq);
|
||||
if(!strcmp(sc->sc_id ?: "", "DBS Bandstacked"))
|
||||
dbsbs = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(dbsbs) {
|
||||
hiband = 0;
|
||||
if(dm->dm_conf.dmc_polarisation == POLARISATION_HORIZONTAL ||
|
||||
dm->dm_conf.dmc_polarisation == POLARISATION_CIRCULAR_LEFT)
|
||||
p->frequency = abs(p->frequency - hifreq);
|
||||
else
|
||||
p->frequency = abs(p->frequency - lowfreq);
|
||||
pol = POLARISATION_CIRCULAR_LEFT;
|
||||
} else {
|
||||
hiband = switchfreq && p->frequency > switchfreq;
|
||||
pol = dm->dm_conf.dmc_polarisation;
|
||||
if(hiband)
|
||||
p->frequency = abs(p->frequency - hifreq);
|
||||
else
|
||||
p->frequency = abs(p->frequency - lowfreq);
|
||||
}
|
||||
|
||||
if ((r = diseqc_setup(tda->tda_fe_fd, port,
|
||||
pol == POLARISATION_HORIZONTAL ||
|
||||
pol == POLARISATION_CIRCULAR_LEFT,
|
||||
hiband, tda->tda_diseqc_version,
|
||||
tda->tda_diseqc_repeats)) != 0)
|
||||
tvhlog(LOG_ERR, "dvb", "diseqc setup failed %d\n", r);
|
||||
}
|
||||
|
||||
#if DVB_API_VERSION >= 5
|
||||
if (tda->tda_fe_type == FE_QPSK) {
|
||||
tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning via s2api to \"%s\" (%d, %d Baud, "
|
||||
"%s, %s, %s)", tda->tda_rootpath, dvb_mux_nicename(dm), p->frequency, p->u.qpsk.symbol_rate,
|
||||
dvb_mux_fec2str(p->u.qpsk.fec_inner), dvb_mux_delsys2str(dmc.dmc_fe_delsys),
|
||||
dvb_mux_qam2str(dmc.dmc_fe_modulation));
|
||||
r = dvb_fe_tune_s2(tda, &dmc);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning to \"%s\"",
|
||||
tda->tda_rootpath, dvb_mux_nicename(dm));
|
||||
r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, p);
|
||||
}
|
||||
|
||||
if(r != 0) {
|
||||
tvhlog(LOG_ERR, "dvb", "\"%s\" tuning to \"%s\""
|
||||
" -- Front configuration failed -- %s, frequency: %u",
|
||||
tda->tda_rootpath, dvb_mux_nicename(dm), strerror(errno), p->frequency);
|
||||
if (errno == EINVAL)
|
||||
tdmi->tdmi_tune_failed = 1;
|
||||
return SM_CODE_TUNING_FAILED;
|
||||
}
|
||||
|
||||
dm->dm_current_tdmi = tdmi;
|
||||
|
||||
time(&tda->tda_fe_monitor);
|
||||
tda->tda_fe_monitor += 4; // wait a few secs before monitoring (unlocked)
|
||||
gtimer_arm_ms(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 50);
|
||||
|
||||
dvb_adapter_notify(tda);
|
||||
|
||||
return r;
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Generic DVB hardware stuff
|
||||
* Copyright (C) 2013 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
|
||||
|
||||
struct dvb_hardware_queue dvb_adapters;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
idnode_t **
|
||||
dvb_hardware_get_childs(struct idnode *self)
|
||||
{
|
||||
dvb_hardware_t *dh = (dvb_hardware_t *)self;
|
||||
dvb_hardware_t *c;
|
||||
int cnt = 1;
|
||||
|
||||
TAILQ_FOREACH(c, &dh->dh_childs, dh_parent_link)
|
||||
cnt++;
|
||||
|
||||
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
|
||||
cnt = 0;
|
||||
TAILQ_FOREACH(c, &dh->dh_childs, dh_parent_link)
|
||||
v[cnt++] = &c->dh_id;
|
||||
// qsort(v, cnt, sizeof(idnode_t *), svcsortcmp);
|
||||
v[cnt] = NULL;
|
||||
return v;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const char *
|
||||
dvb_hardware_get_title(struct idnode *self)
|
||||
{
|
||||
dvb_hardware_t *dh = (dvb_hardware_t *)self;
|
||||
return dh->dh_name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void *
|
||||
dvb_hardware_create(const idclass_t *class, size_t size,
|
||||
dvb_hardware_t *parent, const char *uuid,
|
||||
const char *name)
|
||||
{
|
||||
dvb_hardware_t *dh = calloc(1, size);
|
||||
idnode_insert(&dh->dh_id, uuid, class);
|
||||
|
||||
TAILQ_INIT(&dh->dh_childs);
|
||||
|
||||
if(parent == NULL) {
|
||||
TAILQ_INSERT_TAIL(&dvb_adapters, dh, dh_parent_link);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&parent->dh_childs, dh, dh_parent_link);
|
||||
}
|
||||
dh->dh_name = strdup(name);
|
||||
return dh;
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2012 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DVB input using hardware filters
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "service.h"
|
||||
|
||||
/**
|
||||
* Install filters for a service
|
||||
*
|
||||
* global_lock must be held
|
||||
*/
|
||||
static void
|
||||
open_service(th_dvb_adapter_t *tda, service_t *s)
|
||||
{
|
||||
struct dmx_pes_filter_params dmx_param;
|
||||
int fd;
|
||||
elementary_stream_t *st;
|
||||
|
||||
TAILQ_FOREACH(st, &s->s_components, es_link) {
|
||||
if(st->es_pid >= 0x2000)
|
||||
continue;
|
||||
|
||||
if(st->es_demuxer_fd != -1)
|
||||
continue;
|
||||
|
||||
fd = tvh_open(tda->tda_demux_path, O_RDWR, 0);
|
||||
st->es_cc_valid = 0;
|
||||
|
||||
if(fd == -1) {
|
||||
st->es_demuxer_fd = -1;
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"\"%s\" unable to open demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_nicename, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&dmx_param, 0, sizeof(dmx_param));
|
||||
dmx_param.pid = st->es_pid;
|
||||
dmx_param.input = DMX_IN_FRONTEND;
|
||||
dmx_param.output = DMX_OUT_TS_TAP;
|
||||
dmx_param.pes_type = DMX_PES_OTHER;
|
||||
dmx_param.flags = DMX_IMMEDIATE_START;
|
||||
|
||||
if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) {
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_nicename, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
st->es_demuxer_fd = fd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove filters for a service
|
||||
*
|
||||
* global_lock must be held
|
||||
*/
|
||||
static void
|
||||
close_service(th_dvb_adapter_t *tda, service_t *s)
|
||||
{
|
||||
elementary_stream_t *es;
|
||||
|
||||
TAILQ_FOREACH(es, &s->s_components, es_link) {
|
||||
if(es->es_demuxer_fd != -1) {
|
||||
close(es->es_demuxer_fd);
|
||||
es->es_demuxer_fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
open_table(dvb_mux_t *dm, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
|
||||
struct epoll_event e;
|
||||
static int tdt_id_tally;
|
||||
|
||||
tdt->tdt_fd = tvh_open(tda->tda_demux_path, O_RDWR, 0);
|
||||
|
||||
if(tdt->tdt_fd != -1) {
|
||||
|
||||
tdt->tdt_id = ++tdt_id_tally;
|
||||
|
||||
e.events = EPOLLIN;
|
||||
e.data.u64 = ((uint64_t)tdt->tdt_fd << 32) | tdt->tdt_id;
|
||||
|
||||
if(epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_ADD, tdt->tdt_fd, &e)) {
|
||||
close(tdt->tdt_fd);
|
||||
tdt->tdt_fd = -1;
|
||||
} else {
|
||||
|
||||
struct dmx_sct_filter_params fp = {0};
|
||||
|
||||
fp.filter.filter[0] = tdt->tdt_table;
|
||||
fp.filter.mask[0] = tdt->tdt_mask;
|
||||
|
||||
if(tdt->tdt_flags & TDT_CRC)
|
||||
fp.flags |= DMX_CHECK_CRC;
|
||||
fp.flags |= DMX_IMMEDIATE_START;
|
||||
fp.pid = tdt->tdt_pid;
|
||||
|
||||
if(ioctl(tdt->tdt_fd, DMX_SET_FILTER, &fp)) {
|
||||
close(tdt->tdt_fd);
|
||||
tdt->tdt_fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(tdt->tdt_fd == -1)
|
||||
TAILQ_INSERT_TAIL(&dm->dm_table_queue, tdt, tdt_pending_link);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close FD for the given table and put table on the pending list
|
||||
*/
|
||||
static void
|
||||
tdt_close_fd(dvb_mux_t *dm, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
|
||||
|
||||
assert(tdt->tdt_fd != -1);
|
||||
|
||||
epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_DEL, tdt->tdt_fd, NULL);
|
||||
close(tdt->tdt_fd);
|
||||
|
||||
tdt->tdt_fd = -1;
|
||||
TAILQ_INSERT_TAIL(&dm->dm_table_queue, tdt, tdt_pending_link);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void *
|
||||
dvb_table_input(void *aux)
|
||||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
int r, i, tid, fd, x;
|
||||
struct epoll_event ev[1];
|
||||
uint8_t sec[4096];
|
||||
dvb_mux_t *dm;
|
||||
th_dvb_table_t *tdt;
|
||||
int64_t cycle_barrier = 0;
|
||||
|
||||
while(1) {
|
||||
x = epoll_wait(tda->tda_table_epollfd, ev, sizeof(ev) / sizeof(ev[0]), -1);
|
||||
|
||||
for(i = 0; i < x; i++) {
|
||||
|
||||
tid = ev[i].data.u64 & 0xffffffff;
|
||||
fd = ev[i].data.u64 >> 32;
|
||||
|
||||
if(!(ev[i].events & EPOLLIN))
|
||||
continue;
|
||||
|
||||
if((r = read(fd, sec, sizeof(sec))) < 3)
|
||||
continue;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if((dm = tda->tda_current_tdmi->tdmi_mux) != NULL) {
|
||||
LIST_FOREACH(tdt, &dm->dm_tables, tdt_link)
|
||||
if(tdt->tdt_id == tid)
|
||||
break;
|
||||
|
||||
if(tdt != NULL) {
|
||||
dvb_table_dispatch(sec, r, tdt);
|
||||
|
||||
/* Any tables pending (that wants a filter/fd), close this one */
|
||||
if(TAILQ_FIRST(&dm->dm_table_queue) != NULL &&
|
||||
cycle_barrier < getmonoclock()) {
|
||||
tdt_close_fd(dm, tdt);
|
||||
cycle_barrier = getmonoclock() + 100000;
|
||||
tdt = TAILQ_FIRST(&dm->dm_table_queue);
|
||||
assert(tdt != NULL);
|
||||
TAILQ_REMOVE(&dm->dm_table_queue, tdt, tdt_pending_link);
|
||||
|
||||
open_table(dm, tdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
close_table(dvb_mux_t *dm, th_dvb_table_t *tdt)
|
||||
{
|
||||
|
||||
if(tdt->tdt_fd == -1) {
|
||||
TAILQ_REMOVE(&dm->dm_table_queue, tdt, tdt_pending_link);
|
||||
} else {
|
||||
th_dvb_mux_instance_t *tdmi = dm->dm_current_tdmi;
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
|
||||
epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_DEL, tdt->tdt_fd, NULL);
|
||||
close(tdt->tdt_fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_input_filtered_setup(th_dvb_adapter_t *tda)
|
||||
{
|
||||
tda->tda_open_service = open_service;
|
||||
tda->tda_close_service = close_service;
|
||||
tda->tda_open_table = open_table;
|
||||
tda->tda_close_table = close_table;
|
||||
|
||||
pthread_t ptid;
|
||||
tda->tda_table_epollfd = epoll_create(50);
|
||||
pthread_create(&ptid, NULL, dvb_table_input, tda);
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2012 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DVB input from a raw transport stream
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "service.h"
|
||||
|
||||
/**
|
||||
* Install filters for a service
|
||||
*
|
||||
* global_lock must be held
|
||||
*/
|
||||
static void
|
||||
open_service(th_dvb_adapter_t *tda, service_t *s)
|
||||
{
|
||||
// NOP -- We receive all PIDs anyway
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove filters for a service
|
||||
*
|
||||
* global_lock must be held
|
||||
*/
|
||||
static void
|
||||
close_service(th_dvb_adapter_t *tda, service_t *s)
|
||||
{
|
||||
// NOP -- open_service() is a NOP
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
open_table(dvb_mux_t *dm, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi = dm->dm_current_tdmi;
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
assert(tdt->tdt_pid < 0x2000);
|
||||
tda->tda_table_filter[tdt->tdt_pid] = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
close_table(dvb_mux_t *dm, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi = dm->dm_current_tdmi;
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
assert(tdt->tdt_pid < 0x2000);
|
||||
tda->tda_table_filter[tdt->tdt_pid] = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
got_section(const uint8_t *data, size_t len, void *opaque)
|
||||
{
|
||||
th_dvb_table_t *tdt = opaque;
|
||||
dvb_table_dispatch((uint8_t *)data, len, tdt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* All the tables can be destroyed from any of the callbacks
|
||||
* so we need to be a bit careful here
|
||||
*/
|
||||
static void
|
||||
dvb_table_raw_dispatch(dvb_mux_t *dm, const dvb_table_feed_t *dtf)
|
||||
{
|
||||
int pid = (dtf->dtf_tsb[1] & 0x1f) << 8 | dtf->dtf_tsb[2];
|
||||
th_dvb_table_t *vec[dm->dm_num_tables], *tdt;
|
||||
int i = 0;
|
||||
LIST_FOREACH(tdt, &dm->dm_tables, tdt_link) {
|
||||
vec[i++] = tdt;
|
||||
tdt->tdt_refcount++;
|
||||
}
|
||||
assert(i == dm->dm_num_tables);
|
||||
int len = dm->dm_num_tables; // can change during callbacks
|
||||
for(i = 0; i < len; i++) {
|
||||
tdt = vec[i];
|
||||
if(!tdt->tdt_destroyed) {
|
||||
if(tdt->tdt_pid == pid)
|
||||
psi_section_reassemble(&tdt->tdt_sect, dtf->dtf_tsb,
|
||||
0, got_section, tdt);
|
||||
}
|
||||
dvb_table_release(tdt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void *
|
||||
dvb_table_input(void *aux)
|
||||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
dvb_table_feed_t *dtf;
|
||||
|
||||
while(1) {
|
||||
|
||||
pthread_mutex_lock(&tda->tda_delivery_mutex);
|
||||
|
||||
while((dtf = TAILQ_FIRST(&tda->tda_table_feed)) == NULL)
|
||||
pthread_cond_wait(&tda->tda_table_feed_cond, &tda->tda_delivery_mutex);
|
||||
TAILQ_REMOVE(&tda->tda_table_feed, dtf, dtf_link);
|
||||
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if((tdmi = tda->tda_current_tdmi) != NULL)
|
||||
dvb_table_raw_dispatch(tdmi->tdmi_mux, dtf);
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
free(dtf);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_input_raw_setup(th_dvb_adapter_t *tda)
|
||||
{
|
||||
tda->tda_rawmode = 1;
|
||||
tda->tda_open_service = open_service;
|
||||
tda->tda_close_service = close_service;
|
||||
tda->tda_open_table = open_table;
|
||||
tda->tda_close_table = close_table;
|
||||
|
||||
TAILQ_INIT(&tda->tda_table_feed);
|
||||
pthread_cond_init(&tda->tda_table_feed_cond, NULL);
|
||||
|
||||
pthread_t ptid;
|
||||
pthread_create(&ptid, NULL, dvb_table_input, tda);
|
||||
|
||||
}
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* DVB for Linux
|
||||
* Copyright (C) 2013 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_support.h"
|
||||
|
||||
|
||||
typedef struct linux_dvb_frontend {
|
||||
dvb_hardware_t ldf_dh;
|
||||
int ldf_adapterid;
|
||||
int ldf_frontend;
|
||||
|
||||
int ldf_fd; // if -1, frontend is closed
|
||||
|
||||
} linux_dvb_frontend_t;
|
||||
|
||||
|
||||
|
||||
|
||||
static const idclass_t linux_dvb_hardware_class = {
|
||||
.ic_class = "linux_dvb_hardware",
|
||||
.ic_get_childs = dvb_hardware_get_childs,
|
||||
.ic_get_title = dvb_hardware_get_title,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
"name", "Name", PT_STR,
|
||||
offsetof(dvb_hardware_t, dh_name),
|
||||
.notify = &idnode_notify_title_changed,
|
||||
}, {}},
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const idclass_t linux_dvb_adapter_class = {
|
||||
.ic_class = "linux_dvb_adapter",
|
||||
.ic_super = &linux_dvb_hardware_class,
|
||||
};
|
||||
|
||||
|
||||
static const idclass_t linux_dvb_frontend_class = {
|
||||
.ic_class = "linux_dvb_frontend",
|
||||
.ic_super = &linux_dvb_hardware_class,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static const idclass_t linux_dvbc_frontend_class = {
|
||||
.ic_leaf = 1,
|
||||
.ic_class = "linux_dvbc_frontend",
|
||||
.ic_super = &linux_dvb_frontend_class,
|
||||
};
|
||||
|
||||
static const idclass_t linux_dvbt_frontend_class = {
|
||||
.ic_leaf = 1,
|
||||
.ic_class = "linux_dvbt_frontend",
|
||||
.ic_super = &linux_dvb_frontend_class,
|
||||
};
|
||||
|
||||
static const idclass_t linux_atsc_frontend_class = {
|
||||
.ic_leaf = 1,
|
||||
.ic_class = "linux_atsc_frontend",
|
||||
.ic_super = &linux_dvb_frontend_class,
|
||||
};
|
||||
|
||||
static const idclass_t linux_dvbs_frontend_class = {
|
||||
.ic_class = "linux_dvbs_frontend",
|
||||
.ic_super = &linux_dvb_frontend_class,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
linux_dvb_frontend_create(dvb_hardware_t *parent, int adapterid,
|
||||
int frontendid, const struct dvb_frontend_info *dfi)
|
||||
{
|
||||
const idclass_t *class;
|
||||
|
||||
switch(dfi->type) {
|
||||
case FE_OFDM:
|
||||
class = &linux_dvbt_frontend_class;
|
||||
break;
|
||||
case FE_QAM:
|
||||
class = &linux_dvbc_frontend_class;
|
||||
break;
|
||||
case FE_QPSK:
|
||||
class = &linux_dvbs_frontend_class;
|
||||
break;
|
||||
case FE_ATSC:
|
||||
class = &linux_atsc_frontend_class;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// dvb_hardware_t *fe =
|
||||
dvb_hardware_create(class,
|
||||
sizeof(linux_dvb_frontend_t), parent, NULL, dfi->name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
add_adapter(int aid)
|
||||
{
|
||||
int frontends;
|
||||
int demuxers;
|
||||
int dvrs;
|
||||
int i;
|
||||
char path[PATH_MAX];
|
||||
dvb_hardware_t *a = NULL;
|
||||
|
||||
for(frontends = 0; frontends < 32; frontends++) {
|
||||
snprintf(path, sizeof(path), "/dev/dvb/adapter%d/frontend%d",
|
||||
aid, frontends);
|
||||
if(access(path, R_OK | W_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
if(frontends == 0)
|
||||
return; // Nothing here
|
||||
|
||||
for(demuxers = 0; demuxers < 32; demuxers++) {
|
||||
snprintf(path, sizeof(path), "/dev/dvb/adapter%d/demux%d",
|
||||
aid, demuxers);
|
||||
if(access(path, R_OK | W_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
for(dvrs = 0; dvrs < 32; dvrs++) {
|
||||
snprintf(path, sizeof(path), "/dev/dvb/adapter%d/dvr%d",
|
||||
aid, dvrs);
|
||||
if(access(path, R_OK | W_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
tvhlog(LOG_INFO, "DVB",
|
||||
"Linux DVB adapter %d: %d frontends, %d demuxers, %d DVRs",
|
||||
aid, frontends, demuxers, dvrs);
|
||||
|
||||
for(i = 0; i < frontends; i++) {
|
||||
|
||||
snprintf(path, sizeof(path), "/dev/dvb/adapter%d/frontend%d", aid, i);
|
||||
|
||||
int fd = tvh_open(path, O_RDWR | O_NONBLOCK, 0);
|
||||
if(fd == -1) {
|
||||
tvhlog(LOG_ALERT, "DVB",
|
||||
"Unable to open %s -- %s", path, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dvb_frontend_info dfi;
|
||||
|
||||
int r = ioctl(fd, FE_GET_INFO, &dfi);
|
||||
close(fd);
|
||||
if(r) {
|
||||
tvhlog(LOG_ALERT, "DVB", "%s: Unable to query adapter", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(a == NULL) {
|
||||
char name[512];
|
||||
snprintf(name, sizeof(name), "/dev/dvb/adapter%d", aid);
|
||||
|
||||
a = dvb_hardware_create(&linux_dvb_adapter_class, sizeof(dvb_hardware_t),
|
||||
NULL, NULL, name);
|
||||
}
|
||||
linux_dvb_frontend_create(a, aid, i, &dfi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_linux_init(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0 ; i < 32; i++)
|
||||
add_adapter(i);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,255 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2007 - 2012 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "packet.h"
|
||||
#include "dvb.h"
|
||||
#include "epggrab.h"
|
||||
#include "settings.h"
|
||||
#include "dvb_support.h"
|
||||
|
||||
|
||||
const static struct strtab typetab[] = {
|
||||
{"DVB-T", FE_OFDM},
|
||||
{"DVB-C", FE_QAM},
|
||||
{"DVB-S", FE_QPSK},
|
||||
{"ATSC", FE_ATSC},
|
||||
};
|
||||
|
||||
|
||||
struct dvb_network_list dvb_networks;
|
||||
|
||||
static idnode_t **dvb_network_get_childs(struct idnode *self);
|
||||
static const char *dvb_network_get_title(struct idnode *self);
|
||||
static void dvb_network_save(idnode_t *in);
|
||||
|
||||
static const idclass_t dvb_network_class = {
|
||||
.ic_class = "dvbnetwork",
|
||||
.ic_get_childs = dvb_network_get_childs,
|
||||
.ic_get_title = dvb_network_get_title,
|
||||
.ic_save = dvb_network_save,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
"name", "Name", PT_STR,
|
||||
offsetof(dvb_network_t, dn_name),
|
||||
.notify = &idnode_notify_title_changed,
|
||||
}, {
|
||||
"autodiscovery", "Auto discovery", PT_BOOL,
|
||||
offsetof(dvb_network_t, dn_autodiscovery)
|
||||
}, {
|
||||
"nitoid", "NIT OID", PT_INT,
|
||||
offsetof(dvb_network_t, dn_nitoid)
|
||||
}, {
|
||||
"disable_pmt_monitor", "Disable PMT monitor", PT_BOOL,
|
||||
offsetof(dvb_network_t, dn_disable_pmt_monitor)
|
||||
}, {}},
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
dvb_network_t *
|
||||
dvb_network_create(int fe_type, const char *uuid)
|
||||
{
|
||||
char defname[64];
|
||||
dvb_network_t *dn = calloc(1, sizeof(dvb_network_t));
|
||||
if(idnode_insert(&dn->dn_id, uuid, &dvb_network_class)) {
|
||||
free(dn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dn->dn_fe_type = fe_type;
|
||||
TAILQ_INIT(&dn->dn_initial_scan_pending_queue);
|
||||
TAILQ_INIT(&dn->dn_initial_scan_current_queue);
|
||||
|
||||
dn->dn_autodiscovery = fe_type != FE_QPSK;
|
||||
snprintf(defname, sizeof(defname), "%s network", val2str(fe_type, typetab));
|
||||
dn->dn_name = strdup(defname);
|
||||
LIST_INSERT_HEAD(&dvb_networks, dn, dn_global_link);
|
||||
return dn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const char *
|
||||
dvb_network_get_title(struct idnode *self)
|
||||
{
|
||||
dvb_network_t *dn = (dvb_network_t *)self;
|
||||
return dn->dn_name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
muxsortcmp(const void *A, const void *B)
|
||||
{
|
||||
const dvb_mux_t *a = *(dvb_mux_t **)A;
|
||||
const dvb_mux_t *b = *(dvb_mux_t **)B;
|
||||
if(a->dm_conf.dmc_fe_params.frequency < b->dm_conf.dmc_fe_params.frequency)
|
||||
return -1;
|
||||
if(a->dm_conf.dmc_fe_params.frequency > b->dm_conf.dmc_fe_params.frequency)
|
||||
return 1;
|
||||
return a->dm_conf.dmc_polarisation - b->dm_conf.dmc_polarisation;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static idnode_t **
|
||||
dvb_network_get_childs(struct idnode *self)
|
||||
{
|
||||
dvb_network_t *dn = (dvb_network_t *)self;
|
||||
dvb_mux_t *dm;
|
||||
int cnt = 1;
|
||||
LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link)
|
||||
cnt++;
|
||||
|
||||
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
|
||||
cnt = 0;
|
||||
LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link)
|
||||
v[cnt++] = (idnode_t *)dm;
|
||||
qsort(v, cnt, sizeof(idnode_t *), muxsortcmp);
|
||||
v[cnt] = NULL;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_network_load(htsmsg_t *m, const char *uuid)
|
||||
{
|
||||
const char *s = htsmsg_get_str(m, "type");
|
||||
if(s == NULL)
|
||||
return;
|
||||
|
||||
int fetype = str2val(s, typetab);
|
||||
if(fetype == -1)
|
||||
return;
|
||||
|
||||
dvb_network_t *dn = dvb_network_create(fetype, uuid);
|
||||
if(dn == NULL)
|
||||
return;
|
||||
|
||||
htsmsg_delete_field(m, "type");
|
||||
prop_write_values(dn, dvb_network_class.ic_properties, m);
|
||||
dvb_mux_load(dn);
|
||||
dvb_network_schedule_initial_scan(dn);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_network_save(idnode_t *in)
|
||||
{
|
||||
dvb_network_t *dn = (dvb_network_t *)in;
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_str(m, "type", val2str(dn->dn_fe_type, typetab));
|
||||
prop_read_values(in, dvb_network_class.ic_properties, m);
|
||||
|
||||
hts_settings_save(m, "dvb/networks/%s/config",
|
||||
idnode_uuid_as_str(in));
|
||||
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_network_initial_scan(void *aux)
|
||||
{
|
||||
dvb_network_t *dn = aux;
|
||||
dvb_mux_t *dm;
|
||||
|
||||
while((dm = TAILQ_FIRST(&dn->dn_initial_scan_pending_queue)) != NULL) {
|
||||
assert(dm->dm_scan_status == DM_SCAN_PENDING);
|
||||
if(dvb_mux_tune(dm, "initial scan", 1))
|
||||
break;
|
||||
assert(dm->dm_scan_status == DM_SCAN_CURRENT);
|
||||
}
|
||||
gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_network_schedule_initial_scan(dvb_network_t *dn)
|
||||
{
|
||||
gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_network_init(void)
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
if((l = hts_settings_load_r(1, "dvb/networks")) == NULL)
|
||||
return;
|
||||
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
|
||||
if((c = htsmsg_get_map(c, "config")) == NULL)
|
||||
continue;
|
||||
|
||||
dvb_network_load(c, f->hmf_name);
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
idnode_t **
|
||||
dvb_network_root(void)
|
||||
{
|
||||
dvb_network_t *dn;
|
||||
int cnt = 1;
|
||||
LIST_FOREACH(dn, &dvb_networks, dn_global_link)
|
||||
cnt++;
|
||||
|
||||
idnode_t **v = malloc(sizeof(idnode_t *) * cnt);
|
||||
cnt = 0;
|
||||
LIST_FOREACH(dn, &dvb_networks, dn_global_link)
|
||||
v[cnt++] = &dn->dn_id;
|
||||
v[cnt] = NULL;
|
||||
return v;
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* TV headend - Code for configuring DVB muxes
|
||||
* This code is based on code from linux dvb-apps
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_preconf.h"
|
||||
#include "muxes.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_mux_preconf_add(dvb_network_t *dn, const network_t *net,
|
||||
const char *source)
|
||||
{
|
||||
const mux_t *m;
|
||||
struct dvb_mux_conf dmc;
|
||||
|
||||
LIST_FOREACH(m, &net->muxes, link) {
|
||||
|
||||
memset(&dmc, 0, sizeof(dmc));
|
||||
|
||||
dmc.dmc_fe_params.inversion = INVERSION_AUTO;
|
||||
dmc.dmc_fe_params.frequency = m->freq;
|
||||
|
||||
switch(dn->dn_fe_type) {
|
||||
case FE_OFDM:
|
||||
dmc.dmc_fe_params.u.ofdm.bandwidth = m->bw;
|
||||
dmc.dmc_fe_params.u.ofdm.constellation = m->constellation;
|
||||
dmc.dmc_fe_params.u.ofdm.transmission_mode = m->tmode;
|
||||
dmc.dmc_fe_params.u.ofdm.guard_interval = m->guard;
|
||||
dmc.dmc_fe_params.u.ofdm.hierarchy_information = m->hierarchy;
|
||||
dmc.dmc_fe_params.u.ofdm.code_rate_HP = m->fechp;
|
||||
dmc.dmc_fe_params.u.ofdm.code_rate_LP = m->feclp;
|
||||
break;
|
||||
|
||||
case FE_QPSK:
|
||||
#if DVB_API_VERSION >= 5
|
||||
dmc.dmc_fe_delsys = SYS_DVBS;
|
||||
#endif
|
||||
dmc.dmc_fe_params.u.qpsk.symbol_rate = m->symrate;
|
||||
dmc.dmc_fe_params.u.qpsk.fec_inner = m->fec;
|
||||
|
||||
switch(m->polarisation) {
|
||||
case 'V':
|
||||
dmc.dmc_polarisation = POLARISATION_VERTICAL;
|
||||
break;
|
||||
case 'H':
|
||||
dmc.dmc_polarisation = POLARISATION_HORIZONTAL;
|
||||
break;
|
||||
case 'L':
|
||||
dmc.dmc_polarisation = POLARISATION_CIRCULAR_LEFT;
|
||||
break;
|
||||
case 'R':
|
||||
dmc.dmc_polarisation = POLARISATION_CIRCULAR_RIGHT;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FE_QAM:
|
||||
dmc.dmc_fe_params.u.qam.symbol_rate = m->symrate;
|
||||
dmc.dmc_fe_params.u.qam.modulation = m->constellation;
|
||||
dmc.dmc_fe_params.u.qam.fec_inner = m->fec;
|
||||
break;
|
||||
|
||||
case FE_ATSC:
|
||||
dmc.dmc_fe_params.u.vsb.modulation = m->constellation;
|
||||
break;
|
||||
}
|
||||
|
||||
#if TODO_FIX_THIS
|
||||
dmc.dmc_satconf = dvb_satconf_entry_find(tda, satconf, 0);
|
||||
#endif
|
||||
|
||||
dvb_mux_create(dn, &dmc, 0, 0xffff, NULL, source, 1, 1, NULL, NULL, 1, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int
|
||||
dvb_mux_preconf_add_network(dvb_network_t *dn, const char *id)
|
||||
{
|
||||
region_list_t *list;
|
||||
const region_t *r;
|
||||
const network_t *n;
|
||||
char source[100];
|
||||
|
||||
snprintf(source, sizeof(source), "built-in configuration from \"%s\"", id);
|
||||
|
||||
switch(dn->dn_fe_type) {
|
||||
case FE_QAM:
|
||||
list = ®ions_DVBC;
|
||||
break;
|
||||
case FE_QPSK:
|
||||
list = ®ions_DVBS;
|
||||
break;
|
||||
case FE_OFDM:
|
||||
list = ®ions_DVBT;
|
||||
break;
|
||||
case FE_ATSC:
|
||||
list = ®ions_ATSC;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
LIST_FOREACH(r, list, link) {
|
||||
LIST_FOREACH(n, &r->networks, link) {
|
||||
if(!strcmp(n->id, id)) {
|
||||
dvb_mux_preconf_add(dn, n, source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_mux_preconf_get_node(int fetype, const char *node)
|
||||
{
|
||||
region_list_t *list = NULL;
|
||||
const region_t *r;
|
||||
const network_t *n;
|
||||
htsmsg_t *out, *e;
|
||||
|
||||
switch(fetype) {
|
||||
case FE_QAM:
|
||||
list = ®ions_DVBC;
|
||||
break;
|
||||
case FE_QPSK:
|
||||
list = ®ions_DVBS;
|
||||
break;
|
||||
case FE_OFDM:
|
||||
list = ®ions_DVBT;
|
||||
break;
|
||||
case FE_ATSC:
|
||||
list = ®ions_ATSC;
|
||||
break;
|
||||
default:
|
||||
tvhlog(LOG_ERR, "DVB", "No built-in config for fetype %d", fetype);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = htsmsg_create_list();
|
||||
|
||||
if(!strcmp(node, "root")) {
|
||||
LIST_FOREACH(r, list, link) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_u32(e, "leaf", 0);
|
||||
htsmsg_add_str(e, "text", r->name);
|
||||
htsmsg_add_str(e, "id", r->id);
|
||||
htsmsg_add_msg(out, NULL, e);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
LIST_FOREACH(r, list, link)
|
||||
if (!strcmp(node, r->id))
|
||||
break;
|
||||
if (!r) return out;
|
||||
|
||||
LIST_FOREACH(n, &r->networks, link) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_u32(e, "leaf", 1);
|
||||
htsmsg_add_str(e, "text", n->name);
|
||||
htsmsg_add_str(e, "id", n->id);
|
||||
htsmsg_add_msg(out, NULL, e);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* TV headend - Code for configuring DVB muxes
|
||||
* 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 DVB_MUXCONFIG_H_
|
||||
#define DVB_MUXCONFIG_H_
|
||||
|
||||
#include "htsmsg.h"
|
||||
|
||||
htsmsg_t *dvb_mux_preconf_get_node(int fetype, const char *node);
|
||||
|
||||
int dvb_mux_preconf_add_network(dvb_network_t *dn, const char *id);
|
||||
|
||||
#endif /* DVB_MUXCONFIG_H */
|
|
@ -1,340 +0,0 @@
|
|||
/*
|
||||
* Satconf
|
||||
* Copyright (C) 2009 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dtable.h"
|
||||
#include "notify.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
satconf_notify(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "adapterId", tda->tda_identifier);
|
||||
notify_by_msg("dvbSatConf", m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
dvb_satconf_t *
|
||||
dvb_satconf_entry_find(th_dvb_adapter_t *tda, const char *id, int create)
|
||||
{
|
||||
char buf[20];
|
||||
dvb_satconf_t *sc;
|
||||
static int tally;
|
||||
|
||||
if(id != NULL) {
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link)
|
||||
if(!strcmp(sc->sc_id, id))
|
||||
return sc;
|
||||
}
|
||||
if(create == 0)
|
||||
return NULL;
|
||||
|
||||
if(id == NULL) {
|
||||
tally++;
|
||||
snprintf(buf, sizeof(buf), "%d", tally);
|
||||
id = buf;
|
||||
} else {
|
||||
tally = MAX(atoi(id), tally);
|
||||
}
|
||||
|
||||
sc = calloc(1, sizeof(dvb_satconf_t));
|
||||
sc->sc_id = strdup(id);
|
||||
sc->sc_lnb = strdup("Universal");
|
||||
TAILQ_INSERT_TAIL(&tda->tda_satconfs, sc, sc_adapter_link);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
satconf_destroy(th_dvb_adapter_t *tda, dvb_satconf_t *sc)
|
||||
{
|
||||
TAILQ_REMOVE(&tda->tda_satconfs, sc, sc_adapter_link);
|
||||
free(sc->sc_id);
|
||||
free(sc->sc_name);
|
||||
free(sc->sc_comment);
|
||||
free(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_record_build(dvb_satconf_t *sc)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "id", sc->sc_id);
|
||||
htsmsg_add_u32(m, "port", sc->sc_port);
|
||||
htsmsg_add_str(m, "name", sc->sc_name ?: "");
|
||||
htsmsg_add_str(m, "comment", sc->sc_comment ?: "");
|
||||
htsmsg_add_str(m, "lnb", sc->sc_lnb);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_update(void *opaque, const char *id, htsmsg_t *values,
|
||||
int maycreate)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
uint32_t u32;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
if((sc = dvb_satconf_entry_find(tda, id, maycreate)) == NULL)
|
||||
return NULL;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvh_str_update(&sc->sc_name, htsmsg_get_str(values, "name"));
|
||||
tvh_str_update(&sc->sc_comment, htsmsg_get_str(values, "comment"));
|
||||
tvh_str_update(&sc->sc_lnb, htsmsg_get_str(values, "lnb"));
|
||||
|
||||
if(!htsmsg_get_u32(values, "port", &u32))
|
||||
sc->sc_port = u32;
|
||||
|
||||
satconf_notify(tda);
|
||||
|
||||
return satconf_record_build(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
satconf_entry_delete(void *opaque, const char *id)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
if((sc = dvb_satconf_entry_find(tda, id, 0)) == NULL)
|
||||
return -1;
|
||||
satconf_destroy(tda, sc);
|
||||
satconf_notify(tda);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_get_all(void *opaque)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
htsmsg_t *r = htsmsg_create_list();
|
||||
dvb_satconf_t *sc;
|
||||
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link)
|
||||
htsmsg_add_msg(r, NULL, satconf_record_build(sc));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_get(void *opaque, const char *id)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
dvb_satconf_t *sc;
|
||||
if((sc = dvb_satconf_entry_find(tda, id, 0)) == NULL)
|
||||
return NULL;
|
||||
return satconf_record_build(sc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
satconf_entry_create(void *opaque)
|
||||
{
|
||||
th_dvb_adapter_t *tda = opaque;
|
||||
return satconf_record_build(dvb_satconf_entry_find(tda, NULL, 1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const dtable_class_t satconf_dtc = {
|
||||
.dtc_record_get = satconf_entry_get,
|
||||
.dtc_record_get_all = satconf_entry_get_all,
|
||||
.dtc_record_create = satconf_entry_create,
|
||||
.dtc_record_update = satconf_entry_update,
|
||||
.dtc_record_delete = satconf_entry_delete,
|
||||
.dtc_read_access = ACCESS_ADMIN,
|
||||
.dtc_write_access = ACCESS_ADMIN,
|
||||
.dtc_mutex = &global_lock,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_satconf_init(th_dvb_adapter_t *tda)
|
||||
{
|
||||
dtable_t *dt;
|
||||
char name[256];
|
||||
dvb_satconf_t *sc;
|
||||
htsmsg_t *r;
|
||||
|
||||
snprintf(name, sizeof(name), "dvbsatconf/%s", tda->tda_identifier);
|
||||
|
||||
dt = dtable_create(&satconf_dtc, name, tda);
|
||||
if(!dtable_load(dt)) {
|
||||
sc = dvb_satconf_entry_find(tda, NULL, 1);
|
||||
sc->sc_comment = strdup("Default satconf entry");
|
||||
sc->sc_name = strdup("Default (Port 0, Universal LNB)");
|
||||
|
||||
r = satconf_record_build(sc);
|
||||
dtable_record_store(dt, sc->sc_id, r);
|
||||
htsmsg_destroy(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_satconf_list(th_dvb_adapter_t *tda)
|
||||
{
|
||||
dvb_satconf_t *sc;
|
||||
htsmsg_t *array = htsmsg_create_list();
|
||||
htsmsg_t *m;
|
||||
|
||||
TAILQ_FOREACH(sc, &tda->tda_satconfs, sc_adapter_link) {
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "identifier", sc->sc_id);
|
||||
htsmsg_add_str(m, "name", sc->sc_name ?: "");
|
||||
htsmsg_add_msg(array, NULL, m);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
add_to_lnblist(htsmsg_t *array, const char *n)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "identifier", n);
|
||||
htsmsg_add_msg(array, NULL, m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
htsmsg_t *
|
||||
dvb_lnblist_get(void)
|
||||
{
|
||||
htsmsg_t *array = htsmsg_create_list();
|
||||
|
||||
add_to_lnblist(array, "Universal");
|
||||
add_to_lnblist(array, "DBS");
|
||||
add_to_lnblist(array, "DBS Bandstacked");
|
||||
add_to_lnblist(array, "Standard");
|
||||
add_to_lnblist(array, "Enhanced");
|
||||
add_to_lnblist(array, "C-Band");
|
||||
add_to_lnblist(array, "C-Multi");
|
||||
add_to_lnblist(array, "Circular 10750");
|
||||
add_to_lnblist(array, "Ku 11300");
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_lnb_get_frequencies(const char *id, int *f_low, int *f_hi, int *f_switch)
|
||||
{
|
||||
if(!strcmp(id, "Universal")) {
|
||||
*f_low = 9750000;
|
||||
*f_hi = 10600000;
|
||||
*f_switch = 11700000;
|
||||
} else if(!strcmp(id, "DBS")) {
|
||||
*f_low = 11250000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "DBS Bandstacked")) {
|
||||
*f_low = 11250000;
|
||||
*f_hi = 14350000;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Standard")) {
|
||||
*f_low = 10000000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Enhanced")) {
|
||||
*f_low = 9750000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "C-Band")) {
|
||||
*f_low = 5150000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "C-Multi")) {
|
||||
*f_low = 5150000;
|
||||
*f_hi = 5750000;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Circular 10750")) {
|
||||
*f_low = 10750000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Ku 11300")) {
|
||||
*f_low = 11300000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
}
|
||||
}
|
|
@ -1,499 +0,0 @@
|
|||
/*
|
||||
* TV Input - Linux DVB interface
|
||||
* Copyright (C) 2007 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "channels.h"
|
||||
#include "subscriptions.h"
|
||||
#include "psi.h"
|
||||
#include "dvb_support.h"
|
||||
#include "notify.h"
|
||||
|
||||
static const char *dvb_service_get_title(struct idnode *self);
|
||||
|
||||
const idclass_t dvb_service_class = {
|
||||
.ic_super = &service_class,
|
||||
.ic_class = "dvbservice",
|
||||
.ic_get_title = dvb_service_get_title,
|
||||
// .ic_get_childs = dvb_service_get_childs,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
"dvb_eit_enable", "Use EPG", PT_BOOL,
|
||||
offsetof(service_t, s_dvb_eit_enable)
|
||||
}, {
|
||||
}}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Switch the adapter (which is implicitly tied to our transport)
|
||||
* to receive the given transport.
|
||||
*
|
||||
* But we only do this if 'weight' is higher than all of the current
|
||||
* transports that is subscribing to the adapter
|
||||
*/
|
||||
static int
|
||||
dvb_service_start(service_t *s, int instance)
|
||||
{
|
||||
int r;
|
||||
dvb_mux_t *dm = s->s_dvb_mux;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
||||
assert(s->s_status == SERVICE_IDLE);
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
|
||||
if(tdmi->tdmi_adapter->tda_instance == instance)
|
||||
break;
|
||||
|
||||
assert(tdmi != NULL); // We should always find this instance
|
||||
|
||||
r = dvb_fe_tune_tdmi(tdmi, "service start");
|
||||
|
||||
if(!r) {
|
||||
th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
|
||||
pthread_mutex_lock(&tda->tda_delivery_mutex);
|
||||
LIST_INSERT_HEAD(&tda->tda_transports, s, s_active_link);
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
if (tda->tda_locked) {
|
||||
tda->tda_open_service(tda, s);
|
||||
dvb_table_add_pmt(dm, s->s_pmt_pid);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static th_dvb_adapter_t *
|
||||
dvb_service_get_tda(service_t *s)
|
||||
{
|
||||
dvb_mux_t *dm = s->s_dvb_mux;
|
||||
assert(dm->dm_current_tdmi != NULL);
|
||||
th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
|
||||
assert(tda != NULL);
|
||||
return tda;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_service_stop(service_t *s)
|
||||
{
|
||||
th_dvb_adapter_t *tda = dvb_service_get_tda(s);
|
||||
lock_assert(&global_lock);
|
||||
|
||||
pthread_mutex_lock(&tda->tda_delivery_mutex);
|
||||
LIST_REMOVE(s, s_active_link);
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
tda->tda_close_service(tda, s);
|
||||
|
||||
s->s_status = SERVICE_IDLE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_service_refresh(service_t *s)
|
||||
{
|
||||
th_dvb_adapter_t *tda = dvb_service_get_tda(s);
|
||||
lock_assert(&global_lock);
|
||||
tda->tda_open_service(tda, s);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_service_enlist(struct service *s, struct service_instance_list *sil)
|
||||
{
|
||||
dvb_mux_t *dm = s->s_dvb_mux;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
||||
dvb_create_tdmis(dm);
|
||||
|
||||
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
|
||||
if(tdmi->tdmi_tune_failed)
|
||||
continue; // The hardware is not able to tune to this frequency, never consider it
|
||||
|
||||
service_instance_add(sil, s, tdmi->tdmi_adapter->tda_instance, 100,
|
||||
tdmi_current_weight(tdmi));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
dvb_service_is_enabled(service_t *t)
|
||||
{
|
||||
return t->s_dvb_mux->dm_enabled;
|
||||
#if TODO_FIX_THIS
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
return tda->tda_enabled && tdmi->tdmi_enabled && t->s_enabled && t->s_pmt_pid;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_service_save(service_t *t)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&t->s_id));
|
||||
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->s_provider != NULL)
|
||||
htsmsg_add_str(m, "provider", t->s_provider);
|
||||
|
||||
if(t->s_svcname != NULL)
|
||||
htsmsg_add_str(m, "servicename", t->s_svcname);
|
||||
|
||||
if(t->s_ch != NULL) {
|
||||
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
|
||||
htsmsg_add_u32(m, "mapped", 1);
|
||||
}
|
||||
|
||||
if(t->s_dvb_charset != NULL)
|
||||
htsmsg_add_str(m, "dvb_charset", t->s_dvb_charset);
|
||||
|
||||
htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable);
|
||||
|
||||
if(t->s_default_authority)
|
||||
htsmsg_add_str(m, "default_authority", t->s_default_authority);
|
||||
|
||||
if(t->s_prefcapid)
|
||||
htsmsg_add_u32(m, "prefcapid", t->s_prefcapid);
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
psi_save_service_settings(m, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
dvb_mux_t *dm = t->s_dvb_mux;
|
||||
|
||||
hts_settings_save(m, "dvb/networks/%s/muxes/%s/services/%04x",
|
||||
idnode_uuid_as_str(&dm->dm_dn->dn_id),
|
||||
dm->dm_local_identifier,
|
||||
t->s_dvb_service_id);
|
||||
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load config for the given mux
|
||||
*/
|
||||
void
|
||||
dvb_service_load(dvb_mux_t *dm)
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
uint32_t sid, pmt;
|
||||
const char *s;
|
||||
unsigned int u32;
|
||||
service_t *t;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
l = hts_settings_load("dvb/networks/%s/muxes/%s/services",
|
||||
idnode_uuid_as_str(&dm->dm_dn->dn_id),
|
||||
dm->dm_local_identifier);
|
||||
if(l == NULL)
|
||||
return;
|
||||
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
|
||||
if(htsmsg_get_u32(c, "service_id", &sid))
|
||||
continue;
|
||||
|
||||
if(htsmsg_get_u32(c, "pmt", &pmt))
|
||||
continue;
|
||||
|
||||
const char *uuid = htsmsg_get_str(c, "uuid");
|
||||
t = dvb_service_find(dm, sid, pmt, uuid);
|
||||
|
||||
htsmsg_get_u32(c, "stype", &t->s_servicetype);
|
||||
if(htsmsg_get_u32(c, "scrambled", &u32))
|
||||
u32 = 0;
|
||||
t->s_scrambled = u32;
|
||||
|
||||
if(htsmsg_get_u32(c, "channel", &u32))
|
||||
u32 = 0;
|
||||
t->s_channel_number = u32;
|
||||
|
||||
s = htsmsg_get_str(c, "provider");
|
||||
t->s_provider = s ? strdup(s) : NULL;
|
||||
|
||||
s = htsmsg_get_str(c, "servicename");
|
||||
t->s_svcname = s ? strdup(s) : NULL;
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
service_make_nicename(t);
|
||||
psi_load_service_settings(c, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
if (!(s = htsmsg_get_str(c, "dvb_charset")))
|
||||
s = htsmsg_get_str(c, "dvb_default_charset");
|
||||
t->s_dvb_charset = s ? strdup(s) : NULL;
|
||||
|
||||
s = htsmsg_get_str(c, "default_authority");
|
||||
t->s_default_authority = s ? strdup(s) : NULL;
|
||||
|
||||
if(htsmsg_get_u32(c, "dvb_eit_enable", &u32))
|
||||
u32 = 1;
|
||||
t->s_dvb_eit_enable = u32;
|
||||
|
||||
s = htsmsg_get_str(c, "channelname");
|
||||
if(htsmsg_get_u32(c, "mapped", &u32))
|
||||
u32 = 0;
|
||||
|
||||
if(s && u32)
|
||||
service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
|
||||
|
||||
if(htsmsg_get_u32(c, "prefcapid", &u32))
|
||||
u32 = 0;
|
||||
t->s_prefcapid = u32;
|
||||
|
||||
/* HACK - force save for old config */
|
||||
if(uuid == NULL) {
|
||||
// If service config on disk lacked UUID (for whatever reason),
|
||||
// write it back
|
||||
dvb_service_save(t);
|
||||
}
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a descriptive name for the source
|
||||
*/
|
||||
static void
|
||||
dvb_service_setsourceinfo(service_t *t, struct source_info *si)
|
||||
{
|
||||
dvb_mux_t *dm = t->s_dvb_mux;
|
||||
|
||||
memset(si, 0, sizeof(struct source_info));
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
si->si_type = S_MPEG_TS;
|
||||
|
||||
if(dm->dm_network_name != NULL)
|
||||
si->si_network = strdup(dm->dm_network_name);
|
||||
|
||||
si->si_mux = strdup(dvb_mux_nicename(dm));
|
||||
|
||||
if(t->s_provider != NULL)
|
||||
si->si_provider = strdup(t->s_provider);
|
||||
|
||||
if(t->s_svcname != NULL)
|
||||
si->si_service = strdup(t->s_svcname);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
dvb_grace_period(service_t *t)
|
||||
{
|
||||
#if TODO_FIX_THIS
|
||||
if (t->s_dvb_mux_instance && t->s_dvb_mux_instance->tdmi_adapter)
|
||||
return t->s_dvb_mux_instance->tdmi_adapter->tda_grace_period ?: 10;
|
||||
#endif
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Find transport based on the DVB identification
|
||||
*/
|
||||
service_t *
|
||||
dvb_service_find3(dvb_network_t *dn, dvb_mux_t *dm,
|
||||
const char *netname, uint16_t onid, uint16_t tsid,
|
||||
uint16_t sid, int enabled, int epgprimary)
|
||||
{
|
||||
service_t *svc;
|
||||
if (dm != NULL) {
|
||||
LIST_FOREACH(svc, &dm->dm_services, s_group_link) {
|
||||
if (sid != svc->s_dvb_service_id) continue;
|
||||
if (enabled && !svc->s_enabled) continue;
|
||||
if (epgprimary && !service_is_primary_epg(svc)) continue;
|
||||
return svc;
|
||||
}
|
||||
} else if (dn) {
|
||||
LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link) {
|
||||
if (enabled && !dm->dm_enabled) continue;
|
||||
if (onid && onid != dm->dm_network_id) continue;
|
||||
if (tsid && tsid != dm->dm_transport_stream_id) continue;
|
||||
if (netname && strcmp(netname, dm->dm_network_name ?: "")) continue;
|
||||
if ((svc = dvb_service_find3(dn, dm, NULL, 0, 0, sid,
|
||||
enabled, epgprimary)))
|
||||
return svc;
|
||||
}
|
||||
} else {
|
||||
LIST_FOREACH(dn, &dvb_networks, dn_global_link)
|
||||
if ((svc = dvb_service_find3(dn, NULL, netname, onid, tsid,
|
||||
sid, enabled, epgprimary)))
|
||||
return svc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a transport based on 'serviceid' on the given mux
|
||||
*
|
||||
* If it cannot be found we create it if 'pmt_pid' is also set
|
||||
*/
|
||||
service_t *
|
||||
dvb_service_find(dvb_mux_t *dm, uint16_t sid, int pmt_pid, const char *uuid)
|
||||
{
|
||||
return dvb_service_find2(dm, sid, pmt_pid, uuid, NULL);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
service_t *
|
||||
dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid,
|
||||
const char *uuid, int *save)
|
||||
{
|
||||
service_t *t;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
LIST_FOREACH(t, &dm->dm_services, s_group_link) {
|
||||
if(t->s_dvb_service_id == sid)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Existing - updated PMT_PID if required */
|
||||
if (t) {
|
||||
if (pmt_pid && pmt_pid != t->s_pmt_pid) {
|
||||
t->s_pmt_pid = pmt_pid;
|
||||
*save = 1;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
if(pmt_pid == 0)
|
||||
return NULL;
|
||||
|
||||
tvhlog(LOG_DEBUG, "dvb", "Add service \"0x%x\" on \"%s\"", sid,
|
||||
dvb_mux_nicename(dm));
|
||||
|
||||
t = service_create(uuid, S_MPEG_TS, &dvb_service_class);
|
||||
|
||||
if (save) *save = 1;
|
||||
|
||||
t->s_dvb_service_id = sid;
|
||||
t->s_pmt_pid = pmt_pid;
|
||||
|
||||
t->s_start_feed = dvb_service_start;
|
||||
t->s_refresh_feed = dvb_service_refresh;
|
||||
t->s_stop_feed = dvb_service_stop;
|
||||
t->s_config_save = dvb_service_save;
|
||||
t->s_setsourceinfo = dvb_service_setsourceinfo;
|
||||
t->s_grace_period = dvb_grace_period;
|
||||
t->s_is_enabled = dvb_service_is_enabled;
|
||||
t->s_enlist = dvb_service_enlist;
|
||||
|
||||
t->s_dvb_mux = dm;
|
||||
LIST_INSERT_HEAD(&dm->dm_services, t, s_group_link);
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
service_make_nicename(t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const char *
|
||||
dvb_service_get_title(struct idnode *self)
|
||||
{
|
||||
service_t *s = (service_t *)self;
|
||||
static char buf[100];
|
||||
|
||||
if(s->s_svcname) {
|
||||
return s->s_svcname;
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Service-0x%04x", s->s_dvb_service_id);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvb_service_notify_by_adapter(th_dvb_adapter_t *tda)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "adapterId", tda->tda_identifier);
|
||||
notify_by_msg("dvbService", m);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue