linxudvb: remove deprecated code

Some bits are still incomplete, but I can refer to copies from now on.
This commit is contained in:
Adam Sutton 2013-06-24 10:09:47 +01:00
parent 9c40f25c6f
commit e4a510deb6
17 changed files with 0 additions and 6584 deletions

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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_ */

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 = &regions_DVBC;
break;
case FE_QPSK:
list = &regions_DVBS;
break;
case FE_OFDM:
list = &regions_DVBT;
break;
case FE_ATSC:
list = &regions_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 = &regions_DVBC;
break;
case FE_QPSK:
list = &regions_DVBS;
break;
case FE_OFDM:
list = &regions_DVBT;
break;
case FE_ATSC:
list = &regions_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;
}

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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