Add SAT>IP support (remote network tuners)
This commit is contained in:
parent
4830879ab2
commit
8583936c71
12 changed files with 3179 additions and 0 deletions
7
Makefile
7
Makefile
|
@ -209,6 +209,13 @@ SRCS-${CONFIG_LINUXDVB} += \
|
||||||
src/input/mpegts/linuxdvb/linuxdvb_rotor.c \
|
src/input/mpegts/linuxdvb/linuxdvb_rotor.c \
|
||||||
src/input/mpegts/linuxdvb/linuxdvb_en50494.c
|
src/input/mpegts/linuxdvb/linuxdvb_en50494.c
|
||||||
|
|
||||||
|
# SATIP
|
||||||
|
SRCS-${CONFIG_SATIP_CLIENT} += \
|
||||||
|
src/input/mpegts/satip/satip.c \
|
||||||
|
src/input/mpegts/satip/satip_frontend.c \
|
||||||
|
src/input/mpegts/satip/satip_satconf.c \
|
||||||
|
src/input/mpegts/satip/satip_rtsp.c
|
||||||
|
|
||||||
# IPTV
|
# IPTV
|
||||||
SRCS-${CONFIG_IPTV} += \
|
SRCS-${CONFIG_IPTV} += \
|
||||||
src/input/mpegts/iptv/iptv.c \
|
src/input/mpegts/iptv/iptv.c \
|
||||||
|
|
12
configure
vendored
12
configure
vendored
|
@ -19,6 +19,7 @@ OPTIONS=(
|
||||||
"cwc:yes"
|
"cwc:yes"
|
||||||
"v4l:no"
|
"v4l:no"
|
||||||
"linuxdvb:yes"
|
"linuxdvb:yes"
|
||||||
|
"satip_client:yes"
|
||||||
"iptv:yes"
|
"iptv:yes"
|
||||||
"tsfile:yes"
|
"tsfile:yes"
|
||||||
"dvbscan:yes"
|
"dvbscan:yes"
|
||||||
|
@ -174,6 +175,17 @@ if enabled_or_auto curl; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# SAT>IP client
|
||||||
|
#
|
||||||
|
if enabled_or_auto satip_client; then
|
||||||
|
if enabled curl; then
|
||||||
|
enable upnp
|
||||||
|
else
|
||||||
|
die "SAT>IP client requires curl enabled"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# uriparser
|
# uriparser
|
||||||
#
|
#
|
||||||
|
|
|
@ -59,6 +59,7 @@ void api_init ( void );
|
||||||
void api_done ( void );
|
void api_done ( void );
|
||||||
void api_idnode_init ( void );
|
void api_idnode_init ( void );
|
||||||
void api_input_init ( void );
|
void api_input_init ( void );
|
||||||
|
void api_input_satip_init ( void );
|
||||||
void api_service_init ( void );
|
void api_service_init ( void );
|
||||||
void api_channel_init ( void );
|
void api_channel_init ( void );
|
||||||
void api_mpegts_init ( void );
|
void api_mpegts_init ( void );
|
||||||
|
|
|
@ -128,6 +128,9 @@ void tvh_input_stream_destroy ( tvh_input_stream_t *st );
|
||||||
#if ENABLE_LINUXDVB
|
#if ENABLE_LINUXDVB
|
||||||
#include "input/mpegts/linuxdvb.h"
|
#include "input/mpegts/linuxdvb.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_SATIP_CLIENT
|
||||||
|
#include "input/mpegts/satip/satip.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __TVH_INPUT_H__ */
|
#endif /* __TVH_INPUT_H__ */
|
||||||
|
|
|
@ -51,6 +51,11 @@ mpegts_init ( int linuxdvb_mask, str_list_t *tsfiles, int tstuners )
|
||||||
linuxdvb_init(linuxdvb_mask);
|
linuxdvb_init(linuxdvb_mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* SAT>IP DVB client */
|
||||||
|
#if ENABLE_SATIP_CLIENT
|
||||||
|
satip_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Mux schedulers */
|
/* Mux schedulers */
|
||||||
#if ENABLE_MPEGTS
|
#if ENABLE_MPEGTS
|
||||||
mpegts_mux_sched_init();
|
mpegts_mux_sched_init();
|
||||||
|
@ -71,6 +76,9 @@ mpegts_done ( void )
|
||||||
#if ENABLE_LINUXDVB
|
#if ENABLE_LINUXDVB
|
||||||
tvhftrace("main", linuxdvb_done);
|
tvhftrace("main", linuxdvb_done);
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_SATIP_CLIENT
|
||||||
|
tvhftrace("main", satip_done);
|
||||||
|
#endif
|
||||||
#if ENABLE_TSFILE
|
#if ENABLE_TSFILE
|
||||||
tvhftrace("main", tsfile_done);
|
tvhftrace("main", tsfile_done);
|
||||||
#endif
|
#endif
|
||||||
|
|
818
src/input/mpegts/satip/satip.c
Normal file
818
src/input/mpegts/satip/satip.c
Normal file
|
@ -0,0 +1,818 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - SAT-IP client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* 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 "input.h"
|
||||||
|
#include "htsbuf.h"
|
||||||
|
#include "htsmsg_xml.h"
|
||||||
|
#include "upnp.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "satip_private.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SAT-IP client
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_device_class_save ( idnode_t *in )
|
||||||
|
{
|
||||||
|
satip_device_save((satip_device_t *)in);
|
||||||
|
}
|
||||||
|
|
||||||
|
static idnode_set_t *
|
||||||
|
satip_device_class_get_childs ( idnode_t *in )
|
||||||
|
{
|
||||||
|
satip_device_t *sd = (satip_device_t *)in;
|
||||||
|
idnode_set_t *is = idnode_set_create();
|
||||||
|
satip_frontend_t *lfe;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
|
||||||
|
idnode_set_add(is, &lfe->ti_id, NULL);
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
satip_device_class_get_title( idnode_t *in )
|
||||||
|
{
|
||||||
|
static char buf[256];
|
||||||
|
satip_device_t *sd = (satip_device_t *)in;
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"%s - %s", sd->sd_info.friendlyname, sd->sd_info.addr);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const idclass_t satip_device_class =
|
||||||
|
{
|
||||||
|
.ic_class = "satip_client",
|
||||||
|
.ic_caption = "SAT>IP Client",
|
||||||
|
.ic_save = satip_device_class_save,
|
||||||
|
.ic_get_childs = satip_device_class_get_childs,
|
||||||
|
.ic_get_title = satip_device_class_get_title,
|
||||||
|
.ic_properties = (const property_t[]){
|
||||||
|
{
|
||||||
|
.type = PT_BOOL,
|
||||||
|
.id = "fullmux_ok",
|
||||||
|
.name = "Full Mux Rx mode supported",
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
.off = offsetof(satip_device_t, sd_fullmux_ok),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_INT,
|
||||||
|
.id = "sigscale",
|
||||||
|
.name = "Signal scale (240 or 100)",
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
.off = offsetof(satip_device_t, sd_sig_scale),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_INT,
|
||||||
|
.id = "pids_max",
|
||||||
|
.name = "Maximum PIDs",
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
.off = offsetof(satip_device_t, sd_pids_max),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_INT,
|
||||||
|
.id = "pids_len",
|
||||||
|
.name = "Maximum length of PIDs",
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
.off = offsetof(satip_device_t, sd_pids_len),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_BOOL,
|
||||||
|
.id = "pids_deladd",
|
||||||
|
.name = "addpids/delpids supported",
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
.off = offsetof(satip_device_t, sd_pids_deladd),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "addr",
|
||||||
|
.name = "IP Address",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.addr),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "device_uuid",
|
||||||
|
.name = "UUID",
|
||||||
|
.opts = PO_RDONLY,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.uuid),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "friendly",
|
||||||
|
.name = "Friendly Name",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.friendlyname),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "serialnum",
|
||||||
|
.name = "Serial Number",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.serialnum),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "tunercfg",
|
||||||
|
.name = "Tuner Configuration",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.tunercfg),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "manufacturer",
|
||||||
|
.name = "Manufacturer",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.manufacturer),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "manufurl",
|
||||||
|
.name = "Manufacturer URL",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.manufacturerURL),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "modeldesc",
|
||||||
|
.name = "Model Description",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.modeldesc),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "modelname",
|
||||||
|
.name = "Model Name",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.modelname),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "modelnum",
|
||||||
|
.name = "Model Number",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.modelnum),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "bootid",
|
||||||
|
.name = "Boot ID",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.bootid),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "configid",
|
||||||
|
.name = "Config ID",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.configid),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "deviceid",
|
||||||
|
.name = "Device ID",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.deviceid),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "presentation",
|
||||||
|
.name = "Presentation",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.presentation),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "location",
|
||||||
|
.name = "Location",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.location),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "server",
|
||||||
|
.name = "Server",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.server),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "myaddr",
|
||||||
|
.name = "Local IP Address",
|
||||||
|
.opts = PO_RDONLY | PO_NOSAVE,
|
||||||
|
.off = offsetof(satip_device_t, sd_info.myaddr),
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create entry
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
satip_device_calc_bin_uuid( uint8_t *uuid, const char *satip_uuid )
|
||||||
|
{
|
||||||
|
SHA_CTX sha1;
|
||||||
|
|
||||||
|
SHA1_Init(&sha1);
|
||||||
|
SHA1_Update(&sha1, (void*)satip_uuid, strlen(satip_uuid));
|
||||||
|
SHA1_Final(uuid, &sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_device_calc_uuid( uuid_t *uuid, const char *satip_uuid )
|
||||||
|
{
|
||||||
|
uint8_t uuidbin[20];
|
||||||
|
|
||||||
|
satip_device_calc_bin_uuid(uuidbin, satip_uuid);
|
||||||
|
bin2hex(uuid->hex, sizeof(uuid->hex), uuidbin, sizeof(uuidbin));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_device_hack( satip_device_t *sd )
|
||||||
|
{
|
||||||
|
if (sd->sd_info.deviceid[0] &&
|
||||||
|
strcmp(sd->sd_info.server, "Linux/1.0 UPnP/1.1 IDL4K/1.0") == 0) {
|
||||||
|
/* AXE Linux distribution - Inverto firmware */
|
||||||
|
/* version V1.13.0.105 and probably less */
|
||||||
|
/* really ugly firmware - soooooo much restrictions */
|
||||||
|
sd->sd_fullmux_ok = 0;
|
||||||
|
sd->sd_pids_max = 32;
|
||||||
|
sd->sd_pids_deladd = 0;
|
||||||
|
tvhwarn("satip", "Detected old Inverto firmware V1.13.0.105 and less");
|
||||||
|
tvhwarn("satip", "Upgrade to V1.16.0.120 - http://http://www.inverto.tv/support/ - IDL400s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static satip_device_t *
|
||||||
|
satip_device_create( satip_device_info_t *info )
|
||||||
|
{
|
||||||
|
satip_device_t *sd = calloc(1, sizeof(satip_device_t));
|
||||||
|
uuid_t uuid;
|
||||||
|
htsmsg_t *conf = NULL, *feconf = NULL;
|
||||||
|
char *argv[10];
|
||||||
|
int i, j, n, m, fenum, t2, save = 0;
|
||||||
|
dvb_fe_type_t type;
|
||||||
|
|
||||||
|
satip_device_calc_uuid(&uuid, info->uuid);
|
||||||
|
|
||||||
|
conf = hts_settings_load("input/satip/adapters/%s", uuid.hex);
|
||||||
|
|
||||||
|
/* some sane defaults */
|
||||||
|
sd->sd_fullmux_ok = 1;
|
||||||
|
sd->sd_pids_len = 127;
|
||||||
|
sd->sd_pids_max = 32;
|
||||||
|
sd->sd_pids_deladd = 1;
|
||||||
|
sd->sd_sig_scale = 240;
|
||||||
|
|
||||||
|
if (!tvh_hardware_create0((tvh_hardware_t*)sd, &satip_device_class,
|
||||||
|
uuid.hex, conf)) {
|
||||||
|
free(sd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAILQ_INIT(&sd->sd_frontends);
|
||||||
|
|
||||||
|
/* we may check if uuid matches, but the SHA hash should be enough */
|
||||||
|
if (sd->sd_info.uuid)
|
||||||
|
free(sd->sd_info.uuid);
|
||||||
|
|
||||||
|
#define ASSIGN(x) sd->sd_info.x = info->x; info->x = NULL
|
||||||
|
ASSIGN(myaddr);
|
||||||
|
ASSIGN(addr);
|
||||||
|
ASSIGN(uuid);
|
||||||
|
ASSIGN(bootid);
|
||||||
|
ASSIGN(configid);
|
||||||
|
ASSIGN(deviceid);
|
||||||
|
ASSIGN(server);
|
||||||
|
ASSIGN(location);
|
||||||
|
ASSIGN(friendlyname);
|
||||||
|
ASSIGN(manufacturer);
|
||||||
|
ASSIGN(manufacturerURL);
|
||||||
|
ASSIGN(modeldesc);
|
||||||
|
ASSIGN(modelname);
|
||||||
|
ASSIGN(modelnum);
|
||||||
|
ASSIGN(serialnum);
|
||||||
|
ASSIGN(presentation);
|
||||||
|
ASSIGN(tunercfg);
|
||||||
|
#undef ASSIGN
|
||||||
|
|
||||||
|
/*
|
||||||
|
* device specific hacks
|
||||||
|
*/
|
||||||
|
satip_device_hack(sd);
|
||||||
|
|
||||||
|
if (conf)
|
||||||
|
feconf = htsmsg_get_map(conf, "frontends");
|
||||||
|
save = !conf || !feconf;
|
||||||
|
|
||||||
|
n = http_tokenize(sd->sd_info.tunercfg, argv, 10, ',');
|
||||||
|
for (i = 0, fenum = 1; i < n; i++) {
|
||||||
|
type = DVB_TYPE_NONE;
|
||||||
|
t2 = 0;
|
||||||
|
if (strncmp(argv[i], "DVBS2-", 6) == 0) {
|
||||||
|
type = DVB_TYPE_S;
|
||||||
|
m = atoi(argv[i] + 6);
|
||||||
|
} else if (strncmp(argv[i], "DVBT2-", 6) == 0) {
|
||||||
|
type = DVB_TYPE_T;
|
||||||
|
m = atoi(argv[i] + 6);
|
||||||
|
t2 = 1;
|
||||||
|
} else if (strncmp(argv[i], "DVBT-", 5) == 0) {
|
||||||
|
type = DVB_TYPE_T;
|
||||||
|
m = atoi(argv[i] + 5);
|
||||||
|
}
|
||||||
|
if (type == DVB_TYPE_NONE) {
|
||||||
|
tvhlog(LOG_ERR, "satip", "%s: bad tuner type [%s]", sd->sd_info.addr, argv[i]);
|
||||||
|
} else if (m < 0 || m > 32) {
|
||||||
|
tvhlog(LOG_ERR, "satip", "%s: bad tuner count [%s]", sd->sd_info.addr, argv[i]);
|
||||||
|
} else {
|
||||||
|
for (j = 0; j < m; j++)
|
||||||
|
if (satip_frontend_create(feconf, sd, type, t2, fenum))
|
||||||
|
fenum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save)
|
||||||
|
satip_device_save(sd);
|
||||||
|
|
||||||
|
htsmsg_destroy(conf);
|
||||||
|
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static satip_device_t *
|
||||||
|
satip_device_find( const char *satip_uuid )
|
||||||
|
{
|
||||||
|
tvh_hardware_t *th;
|
||||||
|
uint8_t binuuid[20];
|
||||||
|
|
||||||
|
satip_device_calc_bin_uuid(binuuid, satip_uuid);
|
||||||
|
TVH_HARDWARE_FOREACH(th) {
|
||||||
|
if (idnode_is_instance(&th->th_id, &satip_device_class) &&
|
||||||
|
memcmp(th->th_id.in_uuid, binuuid, UUID_BIN_SIZE) == 0)
|
||||||
|
return (satip_device_t *)th;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_device_save( satip_device_t *sd )
|
||||||
|
{
|
||||||
|
satip_frontend_t *lfe;
|
||||||
|
htsmsg_t *m, *l;
|
||||||
|
|
||||||
|
m = htsmsg_create_map();
|
||||||
|
idnode_save(&sd->th_id, m);
|
||||||
|
|
||||||
|
l = htsmsg_create_map();
|
||||||
|
TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
|
||||||
|
satip_frontend_save(lfe, l);
|
||||||
|
htsmsg_add_msg(m, "frontends", l);
|
||||||
|
|
||||||
|
hts_settings_save(m, "input/satip/adapters/%s",
|
||||||
|
idnode_uuid_as_str(&sd->th_id));
|
||||||
|
htsmsg_destroy(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_device_destroy( satip_device_t *sd )
|
||||||
|
{
|
||||||
|
satip_frontend_t *lfe;
|
||||||
|
|
||||||
|
lock_assert(&global_lock);
|
||||||
|
|
||||||
|
while ((lfe = TAILQ_FIRST(&sd->sd_frontends)) != NULL)
|
||||||
|
satip_frontend_delete(lfe);
|
||||||
|
|
||||||
|
#define FREEM(x) free(sd->sd_info.x)
|
||||||
|
FREEM(myaddr);
|
||||||
|
FREEM(addr);
|
||||||
|
FREEM(uuid);
|
||||||
|
FREEM(bootid);
|
||||||
|
FREEM(configid);
|
||||||
|
FREEM(deviceid);
|
||||||
|
FREEM(location);
|
||||||
|
FREEM(server);
|
||||||
|
FREEM(friendlyname);
|
||||||
|
FREEM(manufacturer);
|
||||||
|
FREEM(manufacturerURL);
|
||||||
|
FREEM(modeldesc);
|
||||||
|
FREEM(modelname);
|
||||||
|
FREEM(modelnum);
|
||||||
|
FREEM(serialnum);
|
||||||
|
FREEM(presentation);
|
||||||
|
FREEM(tunercfg);
|
||||||
|
#undef FREEM
|
||||||
|
|
||||||
|
tvh_hardware_delete((tvh_hardware_t*)sd);
|
||||||
|
free(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discovery job
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct satip_discovery {
|
||||||
|
TAILQ_ENTRY(satip_discovery) disc_link;
|
||||||
|
char *myaddr;
|
||||||
|
char *location;
|
||||||
|
char *server;
|
||||||
|
char *uuid;
|
||||||
|
char *bootid;
|
||||||
|
char *configid;
|
||||||
|
char *deviceid;
|
||||||
|
url_t url;
|
||||||
|
http_client_t *http_client;
|
||||||
|
time_t http_start;
|
||||||
|
char *desc;
|
||||||
|
} satip_discovery_t;
|
||||||
|
|
||||||
|
TAILQ_HEAD(satip_discovery_queue, satip_discovery);
|
||||||
|
|
||||||
|
static int satip_discoveries_count;
|
||||||
|
static struct satip_discovery_queue satip_discoveries;
|
||||||
|
static upnp_service_t *satip_discovery_service;
|
||||||
|
static gtimer_t satip_discovery_timer;
|
||||||
|
static gtimer_t satip_discovery_timerq;
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_destroy(satip_discovery_t *d, int unlink)
|
||||||
|
{
|
||||||
|
if (d == NULL)
|
||||||
|
return;
|
||||||
|
if (unlink) {
|
||||||
|
satip_discoveries_count--;
|
||||||
|
TAILQ_REMOVE(&satip_discoveries, d, disc_link);
|
||||||
|
}
|
||||||
|
if (d->http_client)
|
||||||
|
http_close(d->http_client);
|
||||||
|
free(d->myaddr);
|
||||||
|
free(d->location);
|
||||||
|
free(d->server);
|
||||||
|
free(d->uuid);
|
||||||
|
free(d->bootid);
|
||||||
|
free(d->configid);
|
||||||
|
free(d->deviceid);
|
||||||
|
free(d->desc);
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static satip_discovery_t *
|
||||||
|
satip_discovery_find(satip_discovery_t *d)
|
||||||
|
{
|
||||||
|
satip_discovery_t *sd;
|
||||||
|
|
||||||
|
TAILQ_FOREACH(sd, &satip_discoveries, disc_link)
|
||||||
|
if (strcmp(sd->uuid, d->uuid) == 0)
|
||||||
|
return sd;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
satip_discovery_http_data(void *p, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
satip_discovery_t *d = p;
|
||||||
|
size_t size;
|
||||||
|
char *s;
|
||||||
|
htsmsg_t *xml = NULL, *tags, *root, *device;
|
||||||
|
const char *friendlyname, *manufacturer, *manufacturerURL, *modeldesc;
|
||||||
|
const char *modelname, *modelnum, *serialnum;
|
||||||
|
const char *presentation, *tunercfg;
|
||||||
|
const char *cs;
|
||||||
|
satip_device_info_t info;
|
||||||
|
char errbuf[100];
|
||||||
|
|
||||||
|
size = d->desc ? strlen(d->desc) : 0;
|
||||||
|
if (len + size > 16384)
|
||||||
|
goto finish;
|
||||||
|
d->desc = realloc(d->desc, size + len + 1);
|
||||||
|
memcpy(d->desc + size, buf, len);
|
||||||
|
size += len;
|
||||||
|
d->desc[size] = '\0';
|
||||||
|
|
||||||
|
s = d->desc + size - 1;
|
||||||
|
while (s != d->desc && *s != '/')
|
||||||
|
s--;
|
||||||
|
if (s != d->desc)
|
||||||
|
s--;
|
||||||
|
if (strncmp(s, "</root>", 7))
|
||||||
|
return len;
|
||||||
|
/* Parse */
|
||||||
|
xml = htsmsg_xml_deserialize(d->desc, errbuf, sizeof(errbuf));
|
||||||
|
d->desc = NULL;
|
||||||
|
if (!xml) {
|
||||||
|
tvhlog(LOG_ERR, "satip_discovery_desc", "htsmsg_xml_deserialize error %s", errbuf);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if ((tags = htsmsg_get_map(xml, "tags")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((root = htsmsg_get_map(tags, "root")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((device = htsmsg_get_map(root, "tags")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((device = htsmsg_get_map(device, "device")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((device = htsmsg_get_map(device, "tags")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((cs = htsmsg_xml_get_cdata_str(device, "deviceType")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if (strcmp(cs, "urn:ses-com:device:SatIPServer:1"))
|
||||||
|
goto finish;
|
||||||
|
if ((friendlyname = htsmsg_xml_get_cdata_str(device, "friendlyName")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((manufacturer = htsmsg_xml_get_cdata_str(device, "manufacturer")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((manufacturerURL = htsmsg_xml_get_cdata_str(device, "manufacturerURL")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((modeldesc = htsmsg_xml_get_cdata_str(device, "modelDescription")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((modelname = htsmsg_xml_get_cdata_str(device, "modelName")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((modelnum = htsmsg_xml_get_cdata_str(device, "modelNumber")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((serialnum = htsmsg_xml_get_cdata_str(device, "serialNumber")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((presentation = htsmsg_xml_get_cdata_str(device, "presentationURL")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
if ((tunercfg = htsmsg_xml_get_cdata_str(device, "urn:ses-com:satipX_SATIPCAP")) == NULL)
|
||||||
|
goto finish;
|
||||||
|
info.myaddr = strdup(d->myaddr);
|
||||||
|
info.addr = strdup(d->url.host);
|
||||||
|
info.uuid = strdup(d->uuid);
|
||||||
|
info.bootid = strdup(d->bootid);
|
||||||
|
info.configid = strdup(d->configid);
|
||||||
|
info.deviceid = strdup(d->deviceid);
|
||||||
|
info.location = strdup(d->location);
|
||||||
|
info.server = strdup(d->server);
|
||||||
|
info.friendlyname = strdup(friendlyname);
|
||||||
|
info.manufacturer = strdup(manufacturer);
|
||||||
|
info.manufacturerURL = strdup(manufacturerURL);
|
||||||
|
info.modeldesc = strdup(modeldesc);
|
||||||
|
info.modelname = strdup(modelname);
|
||||||
|
info.modelnum = strdup(modelnum);
|
||||||
|
info.serialnum = strdup(serialnum);
|
||||||
|
info.presentation = strdup(presentation);
|
||||||
|
info.tunercfg = strdup(tunercfg);
|
||||||
|
htsmsg_destroy(xml);
|
||||||
|
xml = NULL;
|
||||||
|
pthread_mutex_lock(&global_lock);
|
||||||
|
if (!satip_device_find(info.uuid))
|
||||||
|
satip_device_create(&info);
|
||||||
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
free(info.myaddr);
|
||||||
|
free(info.location);
|
||||||
|
free(info.server);
|
||||||
|
free(info.addr);
|
||||||
|
free(info.uuid);
|
||||||
|
free(info.bootid);
|
||||||
|
free(info.configid);
|
||||||
|
free(info.deviceid);
|
||||||
|
free(info.friendlyname);
|
||||||
|
free(info.manufacturer);
|
||||||
|
free(info.manufacturerURL);
|
||||||
|
free(info.modeldesc);
|
||||||
|
free(info.modelname);
|
||||||
|
free(info.modelnum);
|
||||||
|
free(info.serialnum);
|
||||||
|
free(info.presentation);
|
||||||
|
free(info.tunercfg);
|
||||||
|
finish:
|
||||||
|
htsmsg_destroy(xml);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_http_fail(void *p)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&global_lock);
|
||||||
|
satip_discovery_destroy((satip_discovery_t *)p, 1);
|
||||||
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_timerq_cb(void *aux)
|
||||||
|
{
|
||||||
|
satip_discovery_t *d, *next;
|
||||||
|
|
||||||
|
lock_assert(&global_lock);
|
||||||
|
|
||||||
|
next = TAILQ_FIRST(&satip_discoveries);
|
||||||
|
while (next) {
|
||||||
|
d = next;
|
||||||
|
next = TAILQ_NEXT(d, disc_link);
|
||||||
|
if (d->http_client) {
|
||||||
|
if (dispatch_clock - d->http_start > 4)
|
||||||
|
satip_discovery_destroy(d, 1);;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
d->http_client = http_connect(&d->url, NULL,
|
||||||
|
satip_discovery_http_data,
|
||||||
|
satip_discovery_http_fail,
|
||||||
|
d);
|
||||||
|
if (d->http_client == NULL)
|
||||||
|
satip_discovery_destroy(d, 1);
|
||||||
|
d->http_start = dispatch_clock;
|
||||||
|
}
|
||||||
|
if (TAILQ_FIRST(&satip_discoveries))
|
||||||
|
gtimer_arm(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_service_received
|
||||||
|
(uint8_t *data, size_t len, udp_connection_t *conn,
|
||||||
|
struct sockaddr_storage *storage)
|
||||||
|
{
|
||||||
|
char *buf, *ptr, *saveptr;
|
||||||
|
char *argv[10];
|
||||||
|
char *st = NULL;
|
||||||
|
char *location = NULL;
|
||||||
|
char *server = NULL;
|
||||||
|
char *uuid = NULL;
|
||||||
|
char *bootid = NULL;
|
||||||
|
char *configid = NULL;
|
||||||
|
char *deviceid = NULL;
|
||||||
|
char sockbuf[128];
|
||||||
|
satip_discovery_t *d;
|
||||||
|
int n, i;
|
||||||
|
|
||||||
|
if (len > 8191 || satip_discoveries_count > 100)
|
||||||
|
return;
|
||||||
|
buf = alloca(len+1);
|
||||||
|
memcpy(buf, data, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
ptr = strtok_r(buf, "\r\n", &saveptr);
|
||||||
|
/* Request decoder */
|
||||||
|
if (ptr) {
|
||||||
|
if (http_tokenize(ptr, argv, 3, -1) != 3)
|
||||||
|
return;
|
||||||
|
if (conn->multicast) {
|
||||||
|
if (strcmp(argv[0], "NOTIFY"))
|
||||||
|
return;
|
||||||
|
if (strcmp(argv[1], "*"))
|
||||||
|
return;
|
||||||
|
if (strcmp(argv[2], "HTTP/1.1"))
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (strcmp(argv[0], "HTTP/1.1"))
|
||||||
|
return;
|
||||||
|
if (strcmp(argv[1], "200"))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ptr = strtok_r(NULL, "\r\n", &saveptr);
|
||||||
|
}
|
||||||
|
/* Header decoder */
|
||||||
|
while (1) {
|
||||||
|
if (ptr == NULL)
|
||||||
|
break;
|
||||||
|
if (http_tokenize(ptr, argv, 2, -1) == 2) {
|
||||||
|
if (strcmp(argv[0], "ST:") == 0)
|
||||||
|
st = argv[1];
|
||||||
|
else if (strcmp(argv[0], "LOCATION:") == 0)
|
||||||
|
location = argv[1];
|
||||||
|
else if (strcmp(argv[0], "SERVER:") == 0)
|
||||||
|
server = argv[1];
|
||||||
|
else if (strcmp(argv[0], "BOOTID.UPNP.ORG:") == 0)
|
||||||
|
bootid = argv[1];
|
||||||
|
else if (strcmp(argv[0], "CONFIGID.UPNP.ORG:") == 0)
|
||||||
|
configid = argv[1];
|
||||||
|
else if (strcmp(argv[0], "DEVICEID.SES.COM:") == 0)
|
||||||
|
deviceid = argv[1];
|
||||||
|
else if (strcmp(argv[0], "USN:") == 0) {
|
||||||
|
n = http_tokenize(argv[1], argv, 10, ':');
|
||||||
|
for (i = 0; i < n+1; i++)
|
||||||
|
if (argv[i] && strcmp(argv[i], "uuid") == 0) {
|
||||||
|
uuid = argv[++i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptr = strtok_r(NULL, "\r\n", &saveptr);
|
||||||
|
}
|
||||||
|
/* Sanity checks */
|
||||||
|
if (st == NULL || strcmp(st, "urn:ses-com:device:SatIPServer:1"))
|
||||||
|
return;
|
||||||
|
if (uuid == NULL && strlen(uuid) < 16)
|
||||||
|
return;
|
||||||
|
if (location == NULL && strncmp(location, "http://", 7))
|
||||||
|
return;
|
||||||
|
if (bootid == NULL || configid == NULL || server == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Forward information to next layer */
|
||||||
|
|
||||||
|
d = calloc(1, sizeof(satip_discovery_t));
|
||||||
|
if (inet_ntop(storage->ss_family, IP_IN_ADDR(conn->ip),
|
||||||
|
sockbuf, sizeof(sockbuf)) == NULL) {
|
||||||
|
satip_discovery_destroy(d, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->myaddr = strdup(sockbuf);
|
||||||
|
d->location = strdup(location);
|
||||||
|
d->server = strdup(server);
|
||||||
|
d->uuid = strdup(uuid);
|
||||||
|
d->bootid = strdup(bootid);
|
||||||
|
d->configid = strdup(configid);
|
||||||
|
d->deviceid = strdup(deviceid ? deviceid : "");
|
||||||
|
if (urlparse(d->location, &d->url)) {
|
||||||
|
satip_discovery_destroy(d, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&global_lock);
|
||||||
|
i = 1;
|
||||||
|
if (!satip_discovery_find(d) && !satip_device_find(d->uuid)) {
|
||||||
|
TAILQ_INSERT_TAIL(&satip_discoveries, d, disc_link);
|
||||||
|
satip_discoveries_count++;
|
||||||
|
gtimer_arm_ms(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, 250);
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
if (i) /* duplicate */
|
||||||
|
satip_discovery_destroy(d, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_service_destroy(upnp_service_t *us)
|
||||||
|
{
|
||||||
|
satip_discovery_service = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_discovery_timer_cb(void *aux)
|
||||||
|
{
|
||||||
|
#define MSG "\
|
||||||
|
M-SEARCH * HTTP/1.1\r\n\
|
||||||
|
HOST: 239.255.255.250:1900\r\n\
|
||||||
|
MAN: \"ssdp:discover\"\r\n\
|
||||||
|
MX: 2\r\n\
|
||||||
|
ST: urn:ses-com:device:SatIPServer:1\r\n\
|
||||||
|
\r\n"
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
|
||||||
|
if (!tvheadend_running)
|
||||||
|
return;
|
||||||
|
if (!upnp_running) {
|
||||||
|
gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (satip_discovery_service == NULL) {
|
||||||
|
satip_discovery_service = upnp_service_create(upnp_service);
|
||||||
|
satip_discovery_service->us_received = satip_discovery_service_received;
|
||||||
|
satip_discovery_service->us_destroy = satip_discovery_service_destroy;
|
||||||
|
}
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_append(&q, MSG, sizeof(MSG)-1);
|
||||||
|
upnp_send(&q, NULL);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 3600);
|
||||||
|
#undef MSG
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialization
|
||||||
|
*/
|
||||||
|
|
||||||
|
void satip_init ( void )
|
||||||
|
{
|
||||||
|
TAILQ_INIT(&satip_discoveries);
|
||||||
|
gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void satip_done ( void )
|
||||||
|
{
|
||||||
|
tvh_hardware_t *th, *n;
|
||||||
|
satip_discovery_t *d, *nd;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&global_lock);
|
||||||
|
for (th = LIST_FIRST(&tvh_hardware); th != NULL; th = n) {
|
||||||
|
n = LIST_NEXT(th, th_link);
|
||||||
|
if (idnode_is_instance(&th->th_id, &satip_device_class)) {
|
||||||
|
satip_device_destroy((satip_device_t *)th);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (d = TAILQ_FIRST(&satip_discoveries); d != NULL; d = nd) {
|
||||||
|
nd = TAILQ_NEXT(d, disc_link);
|
||||||
|
satip_discovery_destroy(d, 1);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
}
|
26
src/input/mpegts/satip/satip.h
Normal file
26
src/input/mpegts/satip/satip.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - SAT-IP DVB private data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* 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 __TVH_SATIP_H__
|
||||||
|
#define __TVH_SATIP_H__
|
||||||
|
|
||||||
|
void satip_init( void );
|
||||||
|
void satip_done( void );
|
||||||
|
|
||||||
|
#endif /* __TVH_SATIP_H__ */
|
1120
src/input/mpegts/satip/satip_frontend.c
Normal file
1120
src/input/mpegts/satip/satip_frontend.c
Normal file
File diff suppressed because it is too large
Load diff
279
src/input/mpegts/satip/satip_private.h
Normal file
279
src/input/mpegts/satip/satip_private.h
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - SAT-IP DVB private data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* 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 __TVH_SATIP_PRIVATE_H__
|
||||||
|
#define __TVH_SATIP_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
|
#include "htsbuf.h"
|
||||||
|
#include "udp.h"
|
||||||
|
#include "satip.h"
|
||||||
|
|
||||||
|
#define SATIP_BUF_SIZE (4000*188)
|
||||||
|
|
||||||
|
typedef struct satip_device_info satip_device_info_t;
|
||||||
|
typedef struct satip_device satip_device_t;
|
||||||
|
typedef struct satip_frontend satip_frontend_t;
|
||||||
|
typedef struct satip_satconf satip_satconf_t;
|
||||||
|
|
||||||
|
struct satip_device_info
|
||||||
|
{
|
||||||
|
char *myaddr; /* IP address of this host received data from the SAT>IP device */
|
||||||
|
char *addr; /* IP address */
|
||||||
|
char *uuid;
|
||||||
|
char *bootid;
|
||||||
|
char *configid;
|
||||||
|
char *deviceid;
|
||||||
|
char *location; /*< URL of the XML file */
|
||||||
|
char *server;
|
||||||
|
char *friendlyname;
|
||||||
|
char *manufacturer;
|
||||||
|
char *manufacturerURL;
|
||||||
|
char *modeldesc;
|
||||||
|
char *modelname;
|
||||||
|
char *modelnum;
|
||||||
|
char *serialnum;
|
||||||
|
char *presentation;
|
||||||
|
char *tunercfg; /*< XML urn:ses-com:satipX_SATIPCAP contents */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct satip_device
|
||||||
|
{
|
||||||
|
tvh_hardware_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adapter info
|
||||||
|
*/
|
||||||
|
satip_device_info_t sd_info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frontends
|
||||||
|
*/
|
||||||
|
TAILQ_HEAD(,satip_frontend) sd_frontends;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTSP
|
||||||
|
*/
|
||||||
|
int sd_fullmux_ok;
|
||||||
|
int sd_pids_max;
|
||||||
|
int sd_pids_len;
|
||||||
|
int sd_pids_deladd;
|
||||||
|
int sd_sig_scale;
|
||||||
|
|
||||||
|
int sd_rtsp_running;
|
||||||
|
pthread_t sd_rtsp_tid;
|
||||||
|
pthread_mutex_t sd_rtsp_lock;
|
||||||
|
pthread_cond_t sd_rtsp_cond;
|
||||||
|
TAILQ_HEAD(,satip_rtsp_request) sd_rtsp_queue;
|
||||||
|
time_t sd_rtsp_ping;
|
||||||
|
gtimer_t sd_rtsp_shutdown;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct satip_frontend
|
||||||
|
{
|
||||||
|
mpegts_input_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device
|
||||||
|
*/
|
||||||
|
satip_device_t *sf_device;
|
||||||
|
TAILQ_ENTRY(satip_frontend) sf_link;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frontend info
|
||||||
|
*/
|
||||||
|
int sf_number;
|
||||||
|
dvb_fe_type_t sf_type;
|
||||||
|
int sf_type_t2;
|
||||||
|
int sf_udp_rtp_port;
|
||||||
|
int sf_fullmux;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reception
|
||||||
|
*/
|
||||||
|
pthread_t sf_dvr_thread;
|
||||||
|
th_pipe_t sf_dvr_pipe;
|
||||||
|
pthread_mutex_t sf_dvr_lock;
|
||||||
|
pthread_cond_t sf_dvr_cond;
|
||||||
|
uint16_t *sf_pids;
|
||||||
|
uint16_t *sf_pids_tuned;
|
||||||
|
int sf_pids_any;
|
||||||
|
int sf_pids_any_tuned;
|
||||||
|
int sf_pids_size;
|
||||||
|
int sf_pids_count;
|
||||||
|
int sf_pids_tcount; /*< tuned count */
|
||||||
|
int sf_running;
|
||||||
|
int sf_position;
|
||||||
|
udp_connection_t *sf_rtp;
|
||||||
|
udp_connection_t *sf_rtcp;
|
||||||
|
int sf_rtp_port;
|
||||||
|
mpegts_mux_instance_t *sf_mmi;
|
||||||
|
signal_state_t sf_status;
|
||||||
|
gtimer_t sf_monitor_timer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration
|
||||||
|
*/
|
||||||
|
int sf_positions;
|
||||||
|
TAILQ_HEAD(,satip_satconf) sf_satconf;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct satip_satconf
|
||||||
|
{
|
||||||
|
|
||||||
|
idnode_t sfc_id;
|
||||||
|
/*
|
||||||
|
* Parent
|
||||||
|
*/
|
||||||
|
satip_frontend_t *sfc_lfe;
|
||||||
|
TAILQ_ENTRY(satip_satconf) sfc_link;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Config
|
||||||
|
*/
|
||||||
|
int sfc_enabled;
|
||||||
|
int sfc_position;
|
||||||
|
int sfc_priority;
|
||||||
|
char *sfc_name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assigned networks to this SAT configuration
|
||||||
|
*/
|
||||||
|
idnode_set_t *sfc_networks;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
void satip_device_init ( void );
|
||||||
|
|
||||||
|
void satip_device_done ( void );
|
||||||
|
|
||||||
|
void satip_device_save ( satip_device_t *sd );
|
||||||
|
|
||||||
|
void satip_device_destroy ( satip_device_t *sd );
|
||||||
|
|
||||||
|
satip_frontend_t *
|
||||||
|
satip_frontend_create
|
||||||
|
( htsmsg_t *conf, satip_device_t *sd, dvb_fe_type_t type, int t2, int num );
|
||||||
|
|
||||||
|
void satip_frontend_save ( satip_frontend_t *lfe, htsmsg_t *m );
|
||||||
|
|
||||||
|
void satip_frontend_delete ( satip_frontend_t *lfe );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SAT>IP Satconf configuration
|
||||||
|
*/
|
||||||
|
void satip_satconf_save ( satip_frontend_t *lfe, htsmsg_t *m );
|
||||||
|
|
||||||
|
void satip_satconf_destroy ( satip_frontend_t *lfe );
|
||||||
|
|
||||||
|
void satip_satconf_create
|
||||||
|
( satip_frontend_t *lfe, htsmsg_t *conf );
|
||||||
|
|
||||||
|
void satip_satconf_updated_positions
|
||||||
|
( satip_frontend_t *lfe );
|
||||||
|
|
||||||
|
int satip_satconf_get_priority
|
||||||
|
( satip_frontend_t *lfe, mpegts_mux_t *mm );
|
||||||
|
|
||||||
|
int satip_satconf_get_position
|
||||||
|
( satip_frontend_t *lfe, mpegts_mux_t *mm );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RTSP part
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SATIP_RTSP_CMD_NONE,
|
||||||
|
SATIP_RTSP_CMD_OPTIONS,
|
||||||
|
SATIP_RTSP_CMD_SETUP,
|
||||||
|
SATIP_RTSP_CMD_PLAY,
|
||||||
|
SATIP_RTSP_CMD_TEARDOWN,
|
||||||
|
SATIP_RTSP_CMD_DESCRIBE
|
||||||
|
} satip_rtsp_cmd_t;
|
||||||
|
|
||||||
|
typedef struct satip_rtsp_connection {
|
||||||
|
/* decoded answer */
|
||||||
|
int cseq;
|
||||||
|
int code;
|
||||||
|
char *header;
|
||||||
|
char *data;
|
||||||
|
/* state variables */
|
||||||
|
int sending;
|
||||||
|
satip_rtsp_cmd_t cmd;
|
||||||
|
int port;
|
||||||
|
int client_port;
|
||||||
|
int timeout;
|
||||||
|
char *session;
|
||||||
|
uint64_t stream_id;
|
||||||
|
/* internal data */
|
||||||
|
satip_device_t *device;
|
||||||
|
int fd;
|
||||||
|
char rbuf[4096];
|
||||||
|
size_t rsize;
|
||||||
|
char *wbuf;
|
||||||
|
size_t wpos;
|
||||||
|
size_t wsize;
|
||||||
|
htsbuf_queue_t wq2;
|
||||||
|
satip_rtsp_cmd_t wq2_cmd;
|
||||||
|
int wq2_loaded;
|
||||||
|
time_t ping_time;
|
||||||
|
} satip_rtsp_connection_t;
|
||||||
|
|
||||||
|
satip_rtsp_connection_t *
|
||||||
|
satip_rtsp_connection( satip_device_t *sd );
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_rtsp_connection_close( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_send_partial( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_send( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
||||||
|
satip_rtsp_cmd_t cmd );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_receive( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_options_decode( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_rtsp_options( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_setup_decode( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_setup( satip_rtsp_connection_t *conn,
|
||||||
|
int src, int fe, int udp_port,
|
||||||
|
const dvb_mux_conf_t *dmc,
|
||||||
|
int connection_close );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_play( satip_rtsp_connection_t *sd, const char *pids,
|
||||||
|
const char *addpids, const char *delpids );
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_teardown( satip_rtsp_connection_t *conn );
|
||||||
|
|
||||||
|
#endif /* __TVH_SATIP_PRIVATE_H__ */
|
580
src/input/mpegts/satip/satip_rtsp.c
Normal file
580
src/input/mpegts/satip/satip_rtsp.c
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - SAT>IP DVB RTSP client
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* 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 <signal.h>
|
||||||
|
#include "tvheadend.h"
|
||||||
|
#include "htsbuf.h"
|
||||||
|
#include "tcp.h"
|
||||||
|
#include "http.h"
|
||||||
|
#include "satip_private.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
satip_rtsp_connection_t *
|
||||||
|
satip_rtsp_connection( satip_device_t *sd )
|
||||||
|
{
|
||||||
|
satip_rtsp_connection_t *conn;
|
||||||
|
char errbuf[256];
|
||||||
|
|
||||||
|
conn = calloc(1, sizeof(satip_rtsp_connection_t));
|
||||||
|
htsbuf_queue_init(&conn->wq2, 0);
|
||||||
|
conn->port = 554;
|
||||||
|
conn->timeout = 60;
|
||||||
|
conn->fd = tcp_connect(sd->sd_info.addr, conn->port,
|
||||||
|
errbuf, sizeof(errbuf), 2);
|
||||||
|
if (conn->fd < 0) {
|
||||||
|
tvhlog(LOG_ERR, "satip", "RTSP - unable to connect - %s", errbuf);
|
||||||
|
free(conn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
conn->device = sd;
|
||||||
|
conn->ping_time = dispatch_clock;
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_rtsp_connection_close( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
|
||||||
|
htsbuf_queue_flush(&conn->wq2);
|
||||||
|
free(conn->session);
|
||||||
|
free(conn->header);
|
||||||
|
free(conn->data);
|
||||||
|
free(conn->wbuf);
|
||||||
|
if (conn->fd > 0)
|
||||||
|
close(conn->fd);
|
||||||
|
free(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_send_partial( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
conn->sending = 1;
|
||||||
|
while (1) {
|
||||||
|
r = send(conn->fd, conn->wbuf + conn->wpos, conn->wsize - conn->wpos, MSG_DONTWAIT);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
|
continue;
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
conn->wpos += r;
|
||||||
|
if (conn->wpos >= conn->wsize) {
|
||||||
|
conn->sending = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_send( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
||||||
|
satip_rtsp_cmd_t cmd )
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
conn->ping_time = dispatch_clock;
|
||||||
|
conn->cmd = cmd;
|
||||||
|
free(conn->wbuf);
|
||||||
|
htsbuf_qprintf(q, "CSeq: %i\r\n\r\n", ++conn->cseq);
|
||||||
|
conn->wbuf = htsbuf_to_string(q);
|
||||||
|
conn->wsize = strlen(conn->wbuf);
|
||||||
|
conn->wpos = 0;
|
||||||
|
#if ENABLE_TRACE
|
||||||
|
tvhtrace("satip", "%s - sending RTSP cmd", conn->device->sd_info.addr);
|
||||||
|
tvhlog_hexdump("satip", conn->wbuf, conn->wsize);
|
||||||
|
#endif
|
||||||
|
while (!(r = satip_rtsp_send_partial(conn))) ;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
satip_rtsp_send2( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
||||||
|
satip_rtsp_cmd_t cmd )
|
||||||
|
{
|
||||||
|
conn->wq2_loaded = 1;
|
||||||
|
conn->wq2_cmd = cmd;
|
||||||
|
htsbuf_appendq(&conn->wq2, q);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_receive( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
char buf[1024], *saveptr, *argv[3], *d, *p, *p1;
|
||||||
|
htsbuf_queue_t header, data;
|
||||||
|
int cseq_seen;
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
r = recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||||
|
if (r == 0)
|
||||||
|
return -ESTRPIPE;
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
|
return 0;
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
#if ENABLE_TRACE
|
||||||
|
if (r > 0) {
|
||||||
|
tvhtrace("satip", "%s - received RTSP answer", conn->device->sd_info.addr);
|
||||||
|
tvhlog_hexdump("satip", buf, r);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (r + conn->rsize >= sizeof(conn->rbuf))
|
||||||
|
return -EINVAL;
|
||||||
|
memcpy(conn->rbuf + conn->rsize, buf, r);
|
||||||
|
conn->rsize += r;
|
||||||
|
conn->rbuf[conn->rsize] = '\0';
|
||||||
|
if (conn->rsize > 3 &&
|
||||||
|
(d = strstr(conn->rbuf, "\r\n\r\n")) != NULL) {
|
||||||
|
*d = '\0';
|
||||||
|
htsbuf_queue_init(&header, 0);
|
||||||
|
htsbuf_queue_init(&data, 0);
|
||||||
|
p = strtok_r(conn->rbuf, "\r\n", &saveptr);
|
||||||
|
if (p == NULL)
|
||||||
|
goto fail;
|
||||||
|
tvhtrace("satip", "%s - RTSP answer '%s'", conn->device->sd_info.addr, p);
|
||||||
|
if (http_tokenize(p, argv, 3, -1) != 3)
|
||||||
|
goto fail;
|
||||||
|
if (strcmp(argv[0], "RTSP/1.0"))
|
||||||
|
goto fail;
|
||||||
|
if ((conn->code = atoi(argv[1])) <= 0)
|
||||||
|
goto fail;
|
||||||
|
cseq_seen = 0;
|
||||||
|
while ((p = strtok_r(NULL, "\r\n", &saveptr)) != NULL) {
|
||||||
|
p1 = strdup(p);
|
||||||
|
if (http_tokenize(p, argv, 2, ':') != 2)
|
||||||
|
goto fail;
|
||||||
|
if (strcmp(argv[0], "CSeq") == 0) {
|
||||||
|
cseq_seen = conn->cseq == atoi(argv[1]);
|
||||||
|
} else {
|
||||||
|
htsbuf_append(&header, p1, strlen(p1));
|
||||||
|
htsbuf_append(&header, "\n", 1);
|
||||||
|
}
|
||||||
|
free(p1);
|
||||||
|
}
|
||||||
|
if (!cseq_seen)
|
||||||
|
goto fail;
|
||||||
|
free(conn->header);
|
||||||
|
free(conn->data);
|
||||||
|
conn->header = htsbuf_to_string(&header);
|
||||||
|
conn->data = htsbuf_to_string(&data);
|
||||||
|
#if ENABLE_TRACE
|
||||||
|
tvhtrace("satip", "%s - received RTSP header", conn->device->sd_info.addr);
|
||||||
|
tvhlog_hexdump("satip", conn->header, strlen(conn->header));
|
||||||
|
if (strlen(conn->data)) {
|
||||||
|
tvhtrace("satip", "%s - received RTSP data", conn->device->sd_info.addr);
|
||||||
|
tvhlog_hexdump("satip", conn->data, strlen(conn->data));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
htsbuf_queue_flush(&header);
|
||||||
|
htsbuf_queue_flush(&data);
|
||||||
|
conn->rsize = 0;
|
||||||
|
/* second write */
|
||||||
|
if (conn->wq2_loaded && conn->code == 200) {
|
||||||
|
r = satip_rtsp_send(conn, &conn->wq2, conn->wq2_cmd);
|
||||||
|
htsbuf_queue_flush(&conn->wq2);
|
||||||
|
conn->wq2_loaded = 0;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
htsbuf_queue_flush(&header);
|
||||||
|
htsbuf_queue_flush(&data);
|
||||||
|
conn->rsize = 0;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* unfinished */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_options_decode( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
char *argv[32], *s, *saveptr;
|
||||||
|
int i, n, what = 0;
|
||||||
|
|
||||||
|
s = strtok_r(conn->header, "\n", &saveptr);
|
||||||
|
while (s) {
|
||||||
|
n = http_tokenize(s, argv, 32, ',');
|
||||||
|
if (strcmp(argv[0], "Public:") == 0)
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (strcmp(argv[i], "DESCRIBE") == 0)
|
||||||
|
what |= 1;
|
||||||
|
else if (strcmp(argv[i], "SETUP") == 0)
|
||||||
|
what |= 2;
|
||||||
|
else if (strcmp(argv[i], "PLAY") == 0)
|
||||||
|
what |= 4;
|
||||||
|
else if (strcmp(argv[i], "TEARDOWN") == 0)
|
||||||
|
what |= 8;
|
||||||
|
}
|
||||||
|
s = strtok_r(NULL, "\n", &saveptr);
|
||||||
|
}
|
||||||
|
return (conn->code != 200 && what != 0x0f) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_rtsp_options( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_qprintf(&q,
|
||||||
|
"OPTIONS rtsp://%s/ RTSP/1.0\r\n",
|
||||||
|
conn->device->sd_info.addr);
|
||||||
|
satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_OPTIONS);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_setup_decode( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
char *argv[32], *s, *saveptr;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
if (conn->code >= 400)
|
||||||
|
return -1;
|
||||||
|
if (conn->code != 200)
|
||||||
|
return 0;
|
||||||
|
conn->client_port = 0;
|
||||||
|
s = strtok_r(conn->header, "\n", &saveptr);
|
||||||
|
while (s) {
|
||||||
|
n = http_tokenize(s, argv, 32, ';');
|
||||||
|
if (strcmp(argv[0], "Session:") == 0) {
|
||||||
|
conn->session = strdup(argv[1]);
|
||||||
|
for (i = 2; i < n; i++) {
|
||||||
|
if (strncmp(argv[i], "timeout=", 8) == 0) {
|
||||||
|
conn->timeout = atoi(argv[i] + 8);
|
||||||
|
if (conn->timeout <= 20 || conn->timeout > 3600)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[0], "com.ses.streamID:") == 0) {
|
||||||
|
conn->stream_id = atoll(argv[1]);
|
||||||
|
/* zero is valid stream id per specification */
|
||||||
|
if (argv[1][0] == '0' && argv[1][0] == '\0')
|
||||||
|
conn->stream_id = 0;
|
||||||
|
else if (conn->stream_id <= 0)
|
||||||
|
return -1;
|
||||||
|
} else if (strcmp(argv[0], "Transport:") == 0) {
|
||||||
|
if (strcmp(argv[1], "RTP/AVP"))
|
||||||
|
return -1;
|
||||||
|
if (strcmp(argv[2], "unicast"))
|
||||||
|
return -1;
|
||||||
|
for (i = 2; i < n; i++) {
|
||||||
|
if (strncmp(argv[i], "client_port=", 12) == 0)
|
||||||
|
conn->client_port = atoi(argv[i] + 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = strtok_r(NULL, "\n", &saveptr);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct tvh2satip {
|
||||||
|
int t; ///< TVH internal value
|
||||||
|
const char *s; ///< SATIP API value
|
||||||
|
} tvh2satip_t;
|
||||||
|
|
||||||
|
#define TABLE_EOD -1
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
satip_rtsp_setup_find(const char *prefix, tvh2satip_t *tbl,
|
||||||
|
int src, const char *defval)
|
||||||
|
{
|
||||||
|
while (tbl->t >= 0) {
|
||||||
|
if (tbl->t == src)
|
||||||
|
return tbl->s;
|
||||||
|
tbl++;
|
||||||
|
}
|
||||||
|
tvhtrace("satip", "%s - cannot translate %d", prefix, src);
|
||||||
|
return defval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD(s, d, def) \
|
||||||
|
strcat(buf, "&" #d "="), strcat(buf, satip_rtsp_setup_find(#d, d, dmc->s, def))
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_rtsp_add_val(const char *name, char *buf, uint32_t val)
|
||||||
|
{
|
||||||
|
char sec[4];
|
||||||
|
|
||||||
|
sprintf(buf + strlen(buf), "&%s=%i", name, val / 1000);
|
||||||
|
if (val % 1000) {
|
||||||
|
sprintf(sec, ".%03i", val % 1000);
|
||||||
|
if (sec[3] == '0') {
|
||||||
|
sec[3] = '\0';
|
||||||
|
if (sec[2] == '0')
|
||||||
|
sec[2] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_setup( satip_rtsp_connection_t *conn, int src, int fe,
|
||||||
|
int udp_port, const dvb_mux_conf_t *dmc,
|
||||||
|
int connection_close )
|
||||||
|
{
|
||||||
|
static tvh2satip_t msys[] = {
|
||||||
|
{ .t = DVB_SYS_DVBT, "dvbt" },
|
||||||
|
{ .t = DVB_SYS_DVBT2, "dvbt2" },
|
||||||
|
{ .t = DVB_SYS_DVBS, "dvbs" },
|
||||||
|
{ .t = DVB_SYS_DVBS2, "dvbs2" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t pol[] = {
|
||||||
|
{ .t = DVB_POLARISATION_HORIZONTAL, "h" },
|
||||||
|
{ .t = DVB_POLARISATION_VERTICAL, "v" },
|
||||||
|
{ .t = DVB_POLARISATION_CIRCULAR_LEFT, "l" },
|
||||||
|
{ .t = DVB_POLARISATION_CIRCULAR_RIGHT, "r" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t ro[] = {
|
||||||
|
{ .t = DVB_ROLLOFF_AUTO, "0.35" },
|
||||||
|
{ .t = DVB_ROLLOFF_20, "0.20" },
|
||||||
|
{ .t = DVB_ROLLOFF_25, "0.25" },
|
||||||
|
{ .t = DVB_ROLLOFF_35, "0.35" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t mtype[] = {
|
||||||
|
{ .t = DVB_MOD_AUTO, "auto" },
|
||||||
|
{ .t = DVB_MOD_QAM_16, "16qam" },
|
||||||
|
{ .t = DVB_MOD_QAM_32, "32qam" },
|
||||||
|
{ .t = DVB_MOD_QAM_64, "64qam" },
|
||||||
|
{ .t = DVB_MOD_QAM_128, "128qam"},
|
||||||
|
{ .t = DVB_MOD_QAM_256, "256qam"},
|
||||||
|
{ .t = DVB_MOD_QPSK, "qpsk" },
|
||||||
|
{ .t = DVB_MOD_PSK_8, "8psk" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t plts[] = {
|
||||||
|
{ .t = DVB_PILOT_AUTO, "auto" },
|
||||||
|
{ .t = DVB_PILOT_ON, "on" },
|
||||||
|
{ .t = DVB_PILOT_OFF, "off" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t fec[] = {
|
||||||
|
{ .t = DVB_FEC_AUTO, "auto" },
|
||||||
|
{ .t = DVB_FEC_1_2, "12" },
|
||||||
|
{ .t = DVB_FEC_2_3, "23" },
|
||||||
|
{ .t = DVB_FEC_3_4, "34" },
|
||||||
|
{ .t = DVB_FEC_3_5, "35" },
|
||||||
|
{ .t = DVB_FEC_4_5, "45" },
|
||||||
|
{ .t = DVB_FEC_5_6, "56" },
|
||||||
|
{ .t = DVB_FEC_7_8, "78" },
|
||||||
|
{ .t = DVB_FEC_8_9, "89" },
|
||||||
|
{ .t = DVB_FEC_9_10, "910" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t tmode[] = {
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_AUTO, "auto" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_1K, "1k" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_2K, "2k" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_4K, "4k" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_8K, "8k" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_16K, "16k" },
|
||||||
|
{ .t = DVB_TRANSMISSION_MODE_32K, "32k" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
static tvh2satip_t gi[] = {
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_AUTO, "auto" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_1_4, "14" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_1_8, "18" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_1_16, "116" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_1_32, "132" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_1_128, "1128" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_19_128, "19128" },
|
||||||
|
{ .t = DVB_GUARD_INTERVAL_19_256, "19256" },
|
||||||
|
{ .t = TABLE_EOD }
|
||||||
|
};
|
||||||
|
|
||||||
|
char buf[512];
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
if (src > 0)
|
||||||
|
sprintf(buf, "src=%i&", src);
|
||||||
|
else
|
||||||
|
buf[0] = '\0';
|
||||||
|
sprintf(buf + strlen(buf), "fe=%i", fe);
|
||||||
|
satip_rtsp_add_val("freq", buf, dmc->dmc_fe_freq);
|
||||||
|
if (dmc->dmc_fe_delsys == DVB_SYS_DVBS ||
|
||||||
|
dmc->dmc_fe_delsys == DVB_SYS_DVBS2) {
|
||||||
|
satip_rtsp_add_val("sr", buf, dmc->u.dmc_fe_qpsk.symbol_rate);
|
||||||
|
ADD(dmc_fe_delsys, msys, "dvbs");
|
||||||
|
ADD(dmc_fe_modulation, mtype, "qpsk");
|
||||||
|
ADD(u.dmc_fe_qpsk.polarisation, pol, "h" );
|
||||||
|
ADD(u.dmc_fe_qpsk.fec_inner, fec, "auto");
|
||||||
|
ADD(dmc_fe_rolloff, ro, "0.35");
|
||||||
|
if (dmc->dmc_fe_pilot != DVB_PILOT_AUTO)
|
||||||
|
ADD(dmc_fe_pilot, plts, "auto");
|
||||||
|
} else {
|
||||||
|
if (dmc->u.dmc_fe_ofdm.bandwidth != DVB_BANDWIDTH_AUTO &&
|
||||||
|
dmc->u.dmc_fe_ofdm.bandwidth != DVB_BANDWIDTH_NONE)
|
||||||
|
satip_rtsp_add_val("bw", buf, dmc->u.dmc_fe_ofdm.bandwidth);
|
||||||
|
ADD(dmc_fe_delsys, msys, "dvbt");
|
||||||
|
if (dmc->dmc_fe_modulation != DVB_MOD_AUTO &&
|
||||||
|
dmc->dmc_fe_modulation != DVB_MOD_NONE &&
|
||||||
|
dmc->dmc_fe_modulation != DVB_MOD_QAM_AUTO)
|
||||||
|
ADD(dmc_fe_modulation, mtype, "64qam");
|
||||||
|
if (dmc->u.dmc_fe_ofdm.transmission_mode != DVB_TRANSMISSION_MODE_AUTO &&
|
||||||
|
dmc->u.dmc_fe_ofdm.transmission_mode != DVB_TRANSMISSION_MODE_NONE)
|
||||||
|
ADD(u.dmc_fe_ofdm.transmission_mode, tmode, "8k");
|
||||||
|
if (dmc->u.dmc_fe_ofdm.guard_interval != DVB_GUARD_INTERVAL_AUTO &&
|
||||||
|
dmc->u.dmc_fe_ofdm.guard_interval != DVB_GUARD_INTERVAL_NONE)
|
||||||
|
ADD(u.dmc_fe_ofdm.guard_interval, gi, "18");
|
||||||
|
}
|
||||||
|
tvhtrace("satip", "setup params - %s", buf);
|
||||||
|
if (conn->stream_id > 0)
|
||||||
|
htsbuf_qprintf(&q, "SETUP rtsp://%s/stream=%li?",
|
||||||
|
conn->device->sd_info.addr, conn->stream_id);
|
||||||
|
else
|
||||||
|
htsbuf_qprintf(&q, "SETUP rtsp://%s/?", conn->device->sd_info.addr);
|
||||||
|
htsbuf_qprintf(&q,
|
||||||
|
"%s RTSP/1.0\r\nTransport: RTP/AVP;unicast;client_port=%i-%i\r\n",
|
||||||
|
buf, udp_port, udp_port+1);
|
||||||
|
if (conn->session)
|
||||||
|
htsbuf_qprintf(&q, "Session: %s\r\n", conn->session);
|
||||||
|
if (connection_close)
|
||||||
|
htsbuf_qprintf(&q, "Connection: close\r\n");
|
||||||
|
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_SETUP);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
satip_rtsp_pids_strip( satip_rtsp_connection_t *conn, const char *s )
|
||||||
|
{
|
||||||
|
int maxlen = conn->device->sd_pids_len;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
return NULL;
|
||||||
|
while (*s == ',')
|
||||||
|
s++;
|
||||||
|
while (strlen(s) > maxlen) {
|
||||||
|
ptr = rindex(s, ',');
|
||||||
|
if (ptr == NULL)
|
||||||
|
abort();
|
||||||
|
*ptr = '\0';
|
||||||
|
}
|
||||||
|
if (*s == '\0')
|
||||||
|
return NULL;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_play( satip_rtsp_connection_t *conn, const char *pids,
|
||||||
|
const char *addpids, const char *delpids )
|
||||||
|
{
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
int r, split = 0;
|
||||||
|
|
||||||
|
pids = satip_rtsp_pids_strip(conn, pids);
|
||||||
|
addpids = satip_rtsp_pids_strip(conn, addpids);
|
||||||
|
delpids = satip_rtsp_pids_strip(conn, delpids);
|
||||||
|
|
||||||
|
if (pids == NULL && addpids == NULL && delpids == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// printf("pids = '%s' addpids = '%s' delpids = '%s'\n", pids, addpids, delpids);
|
||||||
|
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_qprintf(&q, "PLAY rtsp://%s/stream=%li?",
|
||||||
|
conn->device->sd_info.addr, conn->stream_id);
|
||||||
|
/* pids setup and add/del requests cannot be mixed per specification */
|
||||||
|
if (pids) {
|
||||||
|
htsbuf_qprintf(&q, "pids=%s", pids);
|
||||||
|
} else {
|
||||||
|
if (delpids)
|
||||||
|
htsbuf_qprintf(&q, "delpids=%s", delpids);
|
||||||
|
if (addpids) {
|
||||||
|
if (delpids) {
|
||||||
|
/* try to maintain the maximum request size - simple split */
|
||||||
|
if (strlen(addpids) + strlen(delpids) <= conn->device->sd_pids_len)
|
||||||
|
split = 1;
|
||||||
|
else
|
||||||
|
htsbuf_append(&q, "&", 1);
|
||||||
|
}
|
||||||
|
if (!split)
|
||||||
|
htsbuf_qprintf(&q, "addpids=%s", addpids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
htsbuf_qprintf(&q, " RTSP/1.0\r\nSession: %s\r\n", conn->session);
|
||||||
|
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_PLAY);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
if (r || !split)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_qprintf(&q, "PLAY rtsp://%s/stream=%li?",
|
||||||
|
conn->device->sd_info.addr, conn->stream_id);
|
||||||
|
htsbuf_qprintf(&q, "addpids=%s", addpids);
|
||||||
|
htsbuf_qprintf(&q, " RTSP/1.0\r\nSession: %s\r\n", conn->session);
|
||||||
|
r = satip_rtsp_send2(conn, &q, SATIP_RTSP_CMD_PLAY);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_rtsp_teardown( satip_rtsp_connection_t *conn )
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_qprintf(&q,
|
||||||
|
"TEARDOWN rtsp://%s/stream=%li RTSP/1.0\r\nSession: %s\r\n",
|
||||||
|
conn->device->sd_info.addr, conn->stream_id, conn->session);
|
||||||
|
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_TEARDOWN);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int
|
||||||
|
satip_rtsp_describe_decode
|
||||||
|
( satip_connection_t *conn )
|
||||||
|
{
|
||||||
|
if (header == NULL)
|
||||||
|
return 1;
|
||||||
|
printf("describe: %i\n", conn->code);
|
||||||
|
printf("header:\n%s\n", conn->header);
|
||||||
|
printf("data:\n%s\n", conn->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_rtsp_describe( satip_connection_t *conn )
|
||||||
|
{
|
||||||
|
htsbuf_queue_t q;
|
||||||
|
htsbuf_queue_init(&q, 0);
|
||||||
|
htsbuf_qprintf(&q,
|
||||||
|
"DESCRIBE rtsp://%s/ RTSP/1.0\r\n", sd->sd_info.addr);
|
||||||
|
satip_rtsp_write(conn, &q);
|
||||||
|
htsbuf_queue_flush(&q);
|
||||||
|
}
|
||||||
|
#endif
|
322
src/input/mpegts/satip/satip_satconf.c
Normal file
322
src/input/mpegts/satip/satip_satconf.c
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - SAT>IP DVB satconf
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* 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 "satip_private.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
/* **************************************************************************
|
||||||
|
* Frontend callbacks
|
||||||
|
* *************************************************************************/
|
||||||
|
|
||||||
|
static satip_satconf_t *
|
||||||
|
satip_satconf_find_ele( satip_frontend_t *lfe, mpegts_mux_t *mux )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc;
|
||||||
|
TAILQ_FOREACH(sfc, &lfe->sf_satconf, sfc_link) {
|
||||||
|
if (idnode_set_exists(sfc->sfc_networks, &mux->mm_network->mn_id))
|
||||||
|
return sfc;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_satconf_get_priority
|
||||||
|
( satip_frontend_t *lfe, mpegts_mux_t *mm )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = satip_satconf_find_ele(lfe, mm);
|
||||||
|
return sfc->sfc_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
satip_satconf_get_position
|
||||||
|
( satip_frontend_t *lfe, mpegts_mux_t *mm )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = satip_satconf_find_ele(lfe, mm);
|
||||||
|
return sfc->sfc_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************************************
|
||||||
|
* Class definition
|
||||||
|
* *************************************************************************/
|
||||||
|
|
||||||
|
static const void *
|
||||||
|
satip_satconf_class_network_get( void *o )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = o;
|
||||||
|
return idnode_set_as_htsmsg(sfc->sfc_networks);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
satip_satconf_class_network_set( void *o, const void *p )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = o;
|
||||||
|
const htsmsg_t *msg = p;
|
||||||
|
mpegts_network_t *mn;
|
||||||
|
idnode_set_t *n = idnode_set_create();
|
||||||
|
htsmsg_field_t *f;
|
||||||
|
const char *str;
|
||||||
|
int i, save;
|
||||||
|
|
||||||
|
HTSMSG_FOREACH(f, msg) {
|
||||||
|
if (!(str = htsmsg_field_get_str(f))) continue;
|
||||||
|
if (!(mn = mpegts_network_find(str))) continue;
|
||||||
|
idnode_set_add(n, &mn->mn_id, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
save = n->is_count != sfc->sfc_networks->is_count;
|
||||||
|
if (!save) {
|
||||||
|
for (i = 0; i < n->is_count; i++)
|
||||||
|
if (!idnode_set_exists(sfc->sfc_networks, n->is_array[i])) {
|
||||||
|
save = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (save) {
|
||||||
|
/* update the local (antenna satconf) network list */
|
||||||
|
idnode_set_free(sfc->sfc_networks);
|
||||||
|
sfc->sfc_networks = n;
|
||||||
|
/* update the input (frontend) network list */
|
||||||
|
htsmsg_t *l = htsmsg_create_list();
|
||||||
|
satip_frontend_t *lfe = sfc->sfc_lfe;
|
||||||
|
satip_satconf_t *sfc2;
|
||||||
|
TAILQ_FOREACH(sfc2, &lfe->sf_satconf, sfc_link) {
|
||||||
|
for (i = 0; i < sfc2->sfc_networks->is_count; i++)
|
||||||
|
htsmsg_add_str(l, NULL,
|
||||||
|
idnode_uuid_as_str(sfc2->sfc_networks->is_array[i]));
|
||||||
|
}
|
||||||
|
mpegts_input_class_network_set(lfe, l);
|
||||||
|
htsmsg_destroy(l);
|
||||||
|
} else {
|
||||||
|
idnode_set_free(n);
|
||||||
|
}
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
static htsmsg_t *
|
||||||
|
satip_satconf_class_network_enum( void *o )
|
||||||
|
{
|
||||||
|
htsmsg_t *m = htsmsg_create_map();
|
||||||
|
htsmsg_t *p = htsmsg_create_map();
|
||||||
|
htsmsg_add_str(m, "type", "api");
|
||||||
|
htsmsg_add_str(m, "uri", "idnode/load");
|
||||||
|
htsmsg_add_str(m, "event", "mpegts_network");
|
||||||
|
htsmsg_add_u32(p, "enum", 1);
|
||||||
|
htsmsg_add_str(p, "class", dvb_network_dvbs_class.ic_class);
|
||||||
|
htsmsg_add_msg(m, "params", p);
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
satip_satconf_class_network_rend( void *o )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = o;
|
||||||
|
htsmsg_t *l = idnode_set_as_htsmsg(sfc->sfc_networks);
|
||||||
|
char *str = htsmsg_list_2_csv(l);
|
||||||
|
htsmsg_destroy(l);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
satip_satconf_class_get_title ( idnode_t *o )
|
||||||
|
{
|
||||||
|
return ((satip_satconf_t *)o)->sfc_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_satconf_class_save ( idnode_t *in )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc = (satip_satconf_t*)in;
|
||||||
|
satip_device_save(sfc->sfc_lfe->sf_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
const idclass_t satip_satconf_class =
|
||||||
|
{
|
||||||
|
.ic_class = "satip_satconf",
|
||||||
|
.ic_caption = "Satconf",
|
||||||
|
.ic_get_title = satip_satconf_class_get_title,
|
||||||
|
.ic_save = satip_satconf_class_save,
|
||||||
|
.ic_properties = (const property_t[]) {
|
||||||
|
{
|
||||||
|
.type = PT_BOOL,
|
||||||
|
.id = "enabled",
|
||||||
|
.name = "Enabled",
|
||||||
|
.off = offsetof(satip_satconf_t, sfc_enabled),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "displayname",
|
||||||
|
.name = "Name",
|
||||||
|
.off = offsetof(satip_satconf_t, sfc_name),
|
||||||
|
.notify = idnode_notify_title_changed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_INT,
|
||||||
|
.id = "priority",
|
||||||
|
.name = "Priority",
|
||||||
|
.off = offsetof(satip_satconf_t, sfc_priority),
|
||||||
|
.opts = PO_ADVANCED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_INT,
|
||||||
|
.id = "position",
|
||||||
|
.name = "Position",
|
||||||
|
.off = offsetof(satip_satconf_t, sfc_position),
|
||||||
|
.def.i = 1,
|
||||||
|
.opts = PO_RDONLY | PO_ADVANCED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = PT_STR,
|
||||||
|
.id = "networks",
|
||||||
|
.name = "Networks",
|
||||||
|
.islist = 1,
|
||||||
|
.set = satip_satconf_class_network_set,
|
||||||
|
.get = satip_satconf_class_network_get,
|
||||||
|
.list = satip_satconf_class_network_enum,
|
||||||
|
.rend = satip_satconf_class_network_rend,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* **************************************************************************
|
||||||
|
* Creation/Config
|
||||||
|
* *************************************************************************/
|
||||||
|
|
||||||
|
static satip_satconf_t *
|
||||||
|
satip_satconf_create0
|
||||||
|
( satip_frontend_t *lfe, htsmsg_t *conf, int position )
|
||||||
|
{
|
||||||
|
static const char *tbl[] = {" (AA)", " (AB)", " (BA)", " (BB)"};
|
||||||
|
const char *uuid = NULL;
|
||||||
|
satip_satconf_t *sfc = calloc(1, sizeof(*sfc));
|
||||||
|
char buf[32];
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
/* defaults */
|
||||||
|
sfc->sfc_priority = 1;
|
||||||
|
|
||||||
|
if (conf)
|
||||||
|
uuid = htsmsg_get_str(conf, "uuid");
|
||||||
|
if (idnode_insert(&sfc->sfc_id, uuid, &satip_satconf_class)) {
|
||||||
|
free(sfc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sfc->sfc_networks = idnode_set_create();
|
||||||
|
sfc->sfc_lfe = lfe;
|
||||||
|
sfc->sfc_position = position + 1;
|
||||||
|
TAILQ_INSERT_TAIL(&lfe->sf_satconf, sfc, sfc_link);
|
||||||
|
if (conf)
|
||||||
|
idnode_load(&sfc->sfc_id, conf);
|
||||||
|
if (sfc->sfc_name == NULL || sfc->sfc_name[0] == '\0') {
|
||||||
|
free(sfc->sfc_name);
|
||||||
|
s = position < 4 ? tbl[position] : "";
|
||||||
|
snprintf(buf, sizeof(buf), "Position #%i%s", position + 1, s);
|
||||||
|
sfc->sfc_name = strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_satconf_create
|
||||||
|
( satip_frontend_t *lfe, htsmsg_t *conf )
|
||||||
|
{
|
||||||
|
htsmsg_t *l, *e;
|
||||||
|
htsmsg_field_t *f;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
if (conf && (l = htsmsg_get_list(conf, "satconf"))) {
|
||||||
|
satip_satconf_destroy(lfe);
|
||||||
|
HTSMSG_FOREACH(f, l) {
|
||||||
|
if (!(e = htsmsg_field_get_map(f))) continue;
|
||||||
|
if (satip_satconf_create0(lfe, e, pos++))
|
||||||
|
lfe->sf_positions++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lfe->sf_positions == 0)
|
||||||
|
for ( ; lfe->sf_positions < 4; lfe->sf_positions++)
|
||||||
|
satip_satconf_create0(lfe, NULL, lfe->sf_positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
satip_satconf_destroy0
|
||||||
|
( satip_satconf_t *sfc )
|
||||||
|
{
|
||||||
|
satip_frontend_t *lfe = sfc->sfc_lfe;
|
||||||
|
TAILQ_REMOVE(&lfe->sf_satconf, sfc, sfc_link);
|
||||||
|
idnode_unlink(&sfc->sfc_id);
|
||||||
|
idnode_set_free(sfc->sfc_networks);
|
||||||
|
free(sfc->sfc_name);
|
||||||
|
free(sfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_satconf_updated_positions
|
||||||
|
( satip_frontend_t *lfe )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc, *sfc_old;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sfc = TAILQ_FIRST(&lfe->sf_satconf);
|
||||||
|
for (i = 0; i < lfe->sf_positions; i++) {
|
||||||
|
if (sfc == NULL)
|
||||||
|
satip_satconf_create0(lfe, NULL, i);
|
||||||
|
sfc = sfc ? TAILQ_NEXT(sfc, sfc_link) : NULL;
|
||||||
|
}
|
||||||
|
while (sfc) {
|
||||||
|
sfc_old = sfc;
|
||||||
|
sfc = TAILQ_NEXT(sfc, sfc_link);
|
||||||
|
satip_satconf_destroy0(sfc_old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_satconf_destroy ( satip_frontend_t *lfe )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc;
|
||||||
|
|
||||||
|
while ((sfc = TAILQ_FIRST(&lfe->sf_satconf)) != NULL)
|
||||||
|
satip_satconf_destroy0(sfc);
|
||||||
|
lfe->sf_positions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
satip_satconf_save ( satip_frontend_t *lfe, htsmsg_t *m )
|
||||||
|
{
|
||||||
|
satip_satconf_t *sfc;
|
||||||
|
htsmsg_t *l, *e;
|
||||||
|
|
||||||
|
l = htsmsg_create_list();
|
||||||
|
TAILQ_FOREACH(sfc, &lfe->sf_satconf, sfc_link) {
|
||||||
|
e = htsmsg_create_map();
|
||||||
|
idnode_save(&sfc->sfc_id, e);
|
||||||
|
htsmsg_add_msg(l, NULL, e);
|
||||||
|
}
|
||||||
|
htsmsg_add_msg(m, "satconf", l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* Editor Configuration
|
||||||
|
*
|
||||||
|
* vim:sts=2:ts=2:sw=2:et
|
||||||
|
*****************************************************************************/
|
|
@ -134,6 +134,9 @@ const tvh_caps_t tvheadend_capabilities[] = {
|
||||||
#if ENABLE_LINUXDVB
|
#if ENABLE_LINUXDVB
|
||||||
{ "linuxdvb", NULL },
|
{ "linuxdvb", NULL },
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_SATIP_CLIENT
|
||||||
|
{ "satip_client", NULL },
|
||||||
|
#endif
|
||||||
#if ENABLE_LIBAV
|
#if ENABLE_LIBAV
|
||||||
{ "transcoding", &transcoding_enabled },
|
{ "transcoding", &transcoding_enabled },
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue