Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
mpegts: add netceiver support
The NetCeiver is a device that streams DVB via multicast.

http://www.baycom.de/hardware/netceiver/

Signed-off-by: Sven Wegener <sven.wegener@stealer.net>
  • Loading branch information
swegener committed Nov 15, 2014
1 parent aa41df5 commit 0f736e5
Show file tree
Hide file tree
Showing 9 changed files with 686 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Makefile
Expand Up @@ -273,6 +273,12 @@ SRCS_HDHOMERUN = \
src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c
SRCS-${CONFIG_HDHOMERUN_CLIENT} += $(SRCS_HDHOMERUN)

# NetCeiver
SRCS-${CONFIG_NETCEIVER} += \
src/input/mpegts/netceiver/netceiver.c \
src/input/mpegts/netceiver/netceiver_monitor.c \
src/input/mpegts/netceiver/netceiver_tune.c

# IPTV
SRCS-${CONFIG_IPTV} += \
src/input/mpegts/iptv/iptv.c \
Expand Down
1 change: 1 addition & 0 deletions configure
Expand Up @@ -25,6 +25,7 @@ OPTIONS=(
"hdhomerun_client:auto"
"hdhomerun_static:no"
"iptv:yes"
"netceiver:yes"
"tsfile:yes"
"dvbscan:yes"
"timeshift:yes"
Expand Down
3 changes: 3 additions & 0 deletions src/input.h
Expand Up @@ -150,6 +150,9 @@ void tvh_input_stream_destroy ( tvh_input_stream_t *st );
#if ENABLE_HDHOMERUN_CLIENT
#include "input/mpegts/tvhdhomerun/tvhdhomerun.h"
#endif
#if ENABLE_NETCEIVER
#include "input/mpegts/netceiver/netceiver.h"
#endif
#endif

#endif /* __TVH_INPUT_H__ */
4 changes: 4 additions & 0 deletions src/input/mpegts.h
Expand Up @@ -29,6 +29,7 @@
#include "service.h"
#include "mpegts/dvb.h"
#include "subscriptions.h"
#include "udp.h"

#define MPEGTS_ONID_NONE 0xFFFF
#define MPEGTS_TSID_NONE 0xFFFF
Expand Down Expand Up @@ -134,6 +135,9 @@ typedef struct mpegts_pid
int8_t mp_cc;
RB_HEAD(,mpegts_pid_sub) mp_subs; // subscribers to pid
RB_ENTRY(mpegts_pid) mp_link;
#if ENABLE_NETCEIVER
udp_connection_t *nc_udp;
#endif
} mpegts_pid_t;

struct mpegts_table
Expand Down
247 changes: 247 additions & 0 deletions src/input/mpegts/netceiver/netceiver.c
@@ -0,0 +1,247 @@
/*
* Tvheadend - NetCeiver DVB "frontend"
*
* Copyright (C) 2013-2014 Sven Wegener
*
* 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 "notify.h"
#include "atomic.h"
#include "tvhpoll.h"
#include "settings.h"
#include "input.h"
#include "udp.h"

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <arpa/inet.h>


#define LOG_SUBSYS "netceiver"


static void netceiver_class_save(idnode_t *in)
{
htsmsg_t *c;

c = htsmsg_create_map();
idnode_save(in, c);
hts_settings_save(c, "input/dvb/netceiver/%s", idnode_uuid_as_str(in));
htsmsg_destroy(c);
}

static const idclass_t netceiver_class =
{
.ic_super = &mpegts_input_class,
.ic_class = "netceiver",
.ic_caption = "NetCeiver DVB Frontend",
.ic_save = netceiver_class_save,
.ic_properties = (const property_t[]) {
{
.type = PT_STR,
.id = "interface",
.name = "Interface",
.off = offsetof(netceiver_t, nc_interface),
},
{},
}
};

static void *netceiver_input_thread(void *aux)
{
netceiver_t *nc = aux;
mpegts_mux_instance_t *mmi;
tvhpoll_event_t ev;
sbuf_t tsbuf;
char name[256];

nc->mi_display_name((mpegts_input_t *) nc, name, sizeof(name));

sbuf_init_fixed(&tsbuf, NETCEIVER_TS_IP_BUFFER_SIZE);

while (tvheadend_running) {
if (tvhpoll_wait(nc->nc_poll, &ev, 1, -1) < 1)
continue;

if (sbuf_read(&tsbuf, ev.data.fd) < 0) {
if (errno != EAGAIN && errno != EINTR)
tvherror(LOG_SUBSYS, "%s - read() error %d (%s)", name, errno, strerror(errno));
continue;
}

mmi = LIST_FIRST(&nc->mi_mux_active);
if (!mmi)
continue;
mpegts_input_recv_packets((mpegts_input_t *) nc, mmi, &tsbuf, NULL, NULL);
}

sbuf_free(&tsbuf);

return NULL;
}

static int netceiver_is_enabled(mpegts_input_t *mi, mpegts_mux_t *mm, int flags)
{
netceiver_t *nc = (netceiver_t *) mi;

if (!nc->nc_interface || !nc->nc_interface[0])
return 0;

return mpegts_input_is_enabled(mi, mm, flags);
}

static int netceiver_start_mux(mpegts_input_t *mi, mpegts_mux_instance_t *mmi)
{
netceiver_t *nc = (netceiver_t *) mi;
dvb_mux_t *dm = (dvb_mux_t *) mmi->mmi_mux;

if (dm->mm_active)
return 0;

netceiver_start_monitor(nc, &dm->lm_tuning);

// required for tables subscribing to pids
dm->mm_active = mmi;

psi_tables_default(mmi->mmi_mux);
psi_tables_dvb(mmi->mmi_mux);

return 0;
}

static void netceiver_stop_mux(mpegts_input_t *mi, mpegts_mux_instance_t *mmi)
{
netceiver_t *nc = (netceiver_t *) mi;

netceiver_stop_monitor(nc);
}

static mpegts_pid_t *netceiver_open_pid(mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner)
{
netceiver_t *nc = (netceiver_t *) mi;
dvb_mux_t *dm = (dvb_mux_t *) mm;
mpegts_service_t *s = owner;
mpegts_pid_t *mp;
int sid = 0;

mp = mpegts_input_open_pid(mi, mm, pid, type, owner);
if (!mp)
return NULL;

if (mp->nc_udp)
return mp;

if (type == MPS_STREAM && service_is_encrypted((service_t *) s)) {
sid = s->s_dvb_service_id;
}

mp->nc_udp = netceiver_tune(nc, NETCEIVER_GROUP_STREAM, &dm->lm_tuning, pid, sid);
if (mp->nc_udp) {
tvhpoll_event_t ev = {
.fd = mp->nc_udp->fd,
.data.fd = ev.fd,
.events = TVHPOLL_IN,
};
tvhpoll_add(nc->nc_poll, &ev, 1);
}

return mp;
}

static void netceiver_close_pid(mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, void *owner)
{
mpegts_pid_t *mp;

mp = mpegts_mux_find_pid(mm, pid, 0);
if (!mp)
return;

if (mp->nc_udp) {
udp_close(mp->nc_udp);
mp->nc_udp = NULL;
}

mpegts_input_close_pid(mi, mm, pid, type, owner);
}

static idnode_set_t *
netceiver_network_list(mpegts_input_t *mi)
{
idnode_set_t *is = idnode_set_create(0);

idnode_find_all_add(is, &dvb_network_dvbt_class, NULL);
idnode_find_all_add(is, &dvb_network_dvbc_class, NULL);
idnode_find_all_add(is, &dvb_network_dvbs_class, NULL);
idnode_find_all_add(is, &dvb_network_atsc_class, NULL);

return is;
}

static netceiver_t *netceiver_create(const char *uuid, htsmsg_t *conf)
{
netceiver_t *nc = calloc(1, sizeof(*nc));
nc = (netceiver_t *) mpegts_input_create0((mpegts_input_t *) nc, &netceiver_class, uuid, conf);

nc->mi_is_enabled = netceiver_is_enabled;
nc->mi_start_mux = netceiver_start_mux;
nc->mi_stop_mux = netceiver_stop_mux;
nc->mi_network_list = netceiver_network_list;
nc->mi_open_pid = netceiver_open_pid;
nc->mi_close_pid = netceiver_close_pid;

if (!nc->mi_name)
nc->mi_name = strdup("NetCeiver");

nc->nc_poll = tvhpoll_create(256);
tvhthread_create(&nc->nc_input_thread, NULL, netceiver_input_thread, nc);

tvhdebug(LOG_SUBSYS, "created %s on interface %s", nc->mi_name, nc->nc_interface);

return nc;
}

static void netceiver_load_config(void)
{
htsmsg_t *s, *e;
htsmsg_field_t *f;

tvhdebug(LOG_SUBSYS, "loading NetCeiver configuration");
if ((s = hts_settings_load_r(1, "input/dvb/netceiver"))) {
HTSMSG_FOREACH(f, s) {
tvhdebug(LOG_SUBSYS, "loading NetCeiver configuration from %s", f->hmf_name);
if (!(e = htsmsg_get_map_by_field(f)))
continue;
netceiver_create(f->hmf_name, e);
}
htsmsg_destroy(s);
}
}

void netceiver_init(void)
{
netceiver_monitor_init();
netceiver_load_config();
}

/******************************************************************************
* Editor Configuration
*
* vim:sts=2:ts=2:sw=2:et
*****************************************************************************/
59 changes: 59 additions & 0 deletions src/input/mpegts/netceiver/netceiver.h
@@ -0,0 +1,59 @@
/*
* Tvheadend - NetCeiver DVB "frontend"
*
* Copyright (C) 2013-2014 Sven Wegener
*
* 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_NETCEIVER_H__
#define __TVH_NETCEIVER_H__

#include "tvhpoll.h"

#define NETCEIVER_TS_PACKET_SIZE 188
#define NETCEIVER_TS_PACKETS_PER_IP_PACKET 7
#define NETCEIVER_TS_IP_PACKET_SIZE (NETCEIVER_TS_PACKETS_PER_IP_PACKET * NETCEIVER_TS_PACKET_SIZE)
#define NETCEIVER_TS_IP_BUFFER_SIZE (256 * NETCEIVER_TS_IP_PACKET_SIZE)

#define NETCEIVER_GROUP_STREAM 3
#define NETCEIVER_GROUP_MONITOR 4

typedef struct netceiver netceiver_t;

/*
* NetCeiver
*/

struct netceiver
{
mpegts_input_t;

const char *nc_interface;

pthread_t nc_input_thread;

tvhpoll_t *nc_poll;

udp_connection_t *nc_monitor_udp;
};

void netceiver_init(void);
udp_connection_t *netceiver_tune(netceiver_t *nc, int group, dvb_mux_conf_t *dmc, int pid, int sid);

void netceiver_monitor_init(void);
void netceiver_start_monitor(netceiver_t *nc, dvb_mux_conf_t *dmc);
void netceiver_stop_monitor(netceiver_t *nc);

#endif /* __TVH_NETCEIVER_H__ */

0 comments on commit 0f736e5

Please sign in to comment.