diff -rupN tvheadend-3.4patch1/src/iptv_input.c tvheadend-3.4patch2/src/iptv_input.c
--- tvheadend-3.4patch1/src/iptv_input.c 2013-07-11 21:17:34.000000000 +0200
+++ tvheadend-3.4patch2/src/iptv_input.c 2014-04-04 16:00:04.000000000 +0200
@@ -40,6 +40,7 @@
#include "tsdemux.h"
#include "psi.h"
#include "settings.h"
+#include "tcp.h"
static int iptv_thread_running;
static int iptv_epollfd;
@@ -48,6 +49,57 @@ static pthread_mutex_t iptv_recvmutex;
struct service_list iptv_all_services; /* All IPTV services */
static struct service_list iptv_active_services; /* Currently enabled */
+
+/*
+ * URL processing - TODO: move to a library
+ */
+typedef struct
+url
+{
+ char buf[2048];
+ const char *scheme;
+ const char *host;
+ uint16_t port;
+ const char *path;
+} url_t;
+
+static int
+url_parse ( url_t *up, const char *urlstr )
+{
+ char *t1, *t2;
+ strcpy(up->buf, urlstr);
+
+ /* Scheme */
+ up->scheme = t1 = up->buf;
+ if (!(t2 = strstr(t1, "://"))) {
+ return 1;
+ }
+ *t2 = 0;
+
+ /* Host */
+ up->host = t1 = t2 + 3;
+ up->path = NULL;
+ if ((t2 = strstr(t1, "/"))) {
+ *t2 = 0;
+ up->path = t2 + 1;
+ }
+
+ /* Port */
+ up->port = 0;
+ if (!(t2 = strstr(up->host, ":"))) {
+ if (!strcmp(up->scheme, "https"))
+ up->port = 443;
+ else if (!strcmp(up->scheme, "http"))
+ up->port = 80;
+ } else {
+ *t2 = 0;
+ up->port = atoi(t2+1);
+ }
+
+ return 0;
+}
+
+
/**
* PAT parser. We only parse a single program. CRC has already been verified
*/
@@ -101,7 +153,6 @@ iptv_ts_input(service_t *t, const uint8_
uint16_t pid = ((tsb[1] & 0x1f) << 8) | tsb[2];
if(pid == 0) {
-
if(t->s_pat_section == NULL)
t->s_pat_section = calloc(1, sizeof(psi_section_t));
psi_section_reassemble(t->s_pat_section, tsb, 1, iptv_got_pat, t);
@@ -124,16 +175,15 @@ iptv_ts_input(service_t *t, const uint8_
static void *
iptv_thread(void *aux)
{
- int nfds, fd, r, j, hlen;
- uint8_t tsb[65536], *buf;
+ int nfds, fd, type, tlen = sizeof(int), r, j, hlen, err = 0;
+ uint8_t *tsb, *buf, real_buf[65536];
struct epoll_event ev;
service_t *t;
while(1) {
nfds = epoll_wait(iptv_epollfd, &ev, 1, -1);
if(nfds == -1) {
- tvhlog(LOG_ERR, "IPTV", "epoll() error -- %s, sleeping 1 second",
- strerror(errno));
+ tvhlog(LOG_ERR, "IPTV", "epoll() error -- %s, sleeping 1 second", strerror(errno));
sleep(1);
continue;
}
@@ -142,51 +192,77 @@ iptv_thread(void *aux)
continue;
fd = ev.data.fd;
- r = read(fd, tsb, sizeof(tsb));
+ tsb = real_buf + 188;
+ r = read(fd, tsb, sizeof(real_buf) - 188);
- if(r > 1 && tsb[0] == 0x47 && (r % 188) == 0) {
+ getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, (socklen_t *)&tlen);
+
+ if(type == SOCK_STREAM || (r > 1 && tsb[0] == 0x47 && (r % 188) == 0)) {
/* Looks like raw TS in UDP */
buf = tsb;
} else {
/* Check for valid RTP packets */
if(r < 12)
- continue;
+ continue;
if((tsb[0] & 0xc0) != 0x80)
- continue;
+ continue;
if((tsb[1] & 0x7f) != 33)
- continue;
-
+ continue;
+
hlen = (tsb[0] & 0xf) * 4 + 12;
if(tsb[0] & 0x10) {
- // Extension (X bit) == true
+ // Extension (X bit) == true
- if(r < hlen + 4)
- continue; // Packet size < hlen + extension header
+ if(r < hlen + 4)
+ continue; // Packet size < hlen + extension header
- // Skip over extension header (last 2 bytes of header is length)
- hlen += ((tsb[hlen + 2] << 8) | tsb[hlen + 3]) * 4;
- // Add the extension header itself (EHL does not inc header)
- hlen += 4;
+ // Skip over extension header (last 2 bytes of header is length)
+ hlen += ((tsb[hlen + 2] << 8) | tsb[hlen + 3]) * 4;
+ // Add the extension header itself (EHL does not inc header)
+ hlen += 4;
}
if(r < hlen || (r - hlen) % 188 != 0)
- continue;
+ continue;
buf = tsb + hlen;
r -= hlen;
}
pthread_mutex_lock(&iptv_recvmutex);
-
+
LIST_FOREACH(t, &iptv_active_services, s_active_link) {
if(t->s_iptv_fd != fd)
- continue;
-
- for(j = 0; j < r; j += 188)
- iptv_ts_input(t, buf + j);
+ continue;
+
+ if(t->s_iptv_url != NULL) {
+ buf = tsb - t->s_iptv_tsb_len;
+ r += t->s_iptv_tsb_len;
+ memcpy(buf, t->s_iptv_tsb, t->s_iptv_tsb_len);
+
+ // Attempt to re-sync a TS stream (3 valid sync's in a row)
+ if(buf[0] != 0x47) {
+ err = 1;
+ while (err && (r > 376)) {
+ buf++; r--;
+ err = (buf[0] != 0x47) || (buf[188] != 0x47) || (buf[376] != 0x47);
+ }
+ }
+
+ for(j = 0; j <= r - 188; j += 188) {
+ iptv_ts_input(t, buf + j);
+ }
+
+ t->s_iptv_tsb_len = r % 188;
+ memcpy(t->s_iptv_tsb, buf+((r/188)*188), t->s_iptv_tsb_len);
+ }
+ else{
+ for(j = 0; j <= r - 188; j += 188)
+ iptv_ts_input(t, buf + j);
+ }
}
pthread_mutex_unlock(&iptv_recvmutex);
}
@@ -201,8 +277,10 @@ static int
iptv_service_start(service_t *t, unsigned int weight, int force_start)
{
pthread_t tid;
- int fd;
+ int fd, c, i, timeout;
char straddr[INET6_ADDRSTRLEN];
+ char buf[1024];
+ url_t url;
struct ip_mreqn m;
struct ipv6_mreq m6;
struct sockaddr_in sin;
@@ -218,101 +296,129 @@ iptv_service_start(service_t *t, unsigne
pthread_create(&tid, NULL, iptv_thread, NULL);
}
- /* Now, open the real socket for UDP */
- if(t->s_iptv_group.s_addr!=0) {
- fd = tvh_socket(AF_INET, SOCK_DGRAM, 0);
-
- }
- else {
- fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0);
- }
- if(fd == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_identifier);
- return -1;
- }
-
- /* First, resolve interface name */
- memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
- ifr.ifr_name[IFNAMSIZ - 1] = 0;
- if(ioctl(fd, SIOCGIFINDEX, &ifr)) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
- t->s_identifier, t->s_iptv_iface);
- close(fd);
- return -1;
- }
+ if(t->s_iptv_url != NULL){
+ if(url_parse(&url, t->s_iptv_url))
+ return -1;
- /* Bind to IPv4 multicast group */
- if(t->s_iptv_group.s_addr!=0) {
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(t->s_iptv_port);
- sin.sin_addr.s_addr = t->s_iptv_group.s_addr;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m, sizeof(struct ip_mreqn));
- if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
- t->s_identifier, inet_ntoa(sin.sin_addr), t->s_iptv_port,
- strerror(errno));
- close(fd);
+ /* MAKE CONNECTION */
+ // TODO: move connection to thread
+ // TODO: this is really only for testing and to allow use of TVH webserver as input
+ tvhlog(LOG_DEBUG, "IPTV", "connecting to HTTP %s:%d", url.host, url.port);
+ fd = tcp_connect(url.host, url.port, buf, sizeof(buf), 10);
+ if (fd < 0) {
+ tvhlog(LOG_ERR, "IPTV", "tcp_connect() failed -- %s", buf);
return -1;
+ }
+
+ /* Send request (VERY basic) */
+ c = snprintf(buf, sizeof(buf), "GET /%s HTTP/1.1\r\n", url.path);
+ tvh_write(fd, buf, c);
+ c = snprintf(buf, sizeof(buf), "Hostname: %s\r\n", url.host);
+ tvh_write(fd, buf, c);
+ tvh_write(fd, "\r\n", 2);
+
+ /* Read back header */
+ // TODO: do this properly
+ i = 0;
+ timeout = 2000;
+ while (1) {
+ if (!(c = read(fd, buf+i, 1))) {
+ usleep(100000);
+ timeout-=100;
+ if (timeout <= 0) {
+ tvhlog(LOG_ERR, "IPTV", "Timeout waiting for HTTP header");
+ return -1;
+ }
+ continue;
+ }
+ i++;
+ if (i == 4 && !strncmp(buf, "\r\n\r\n", 4))
+ break;
+ memmove(buf, buf+1, 3); i = 3;
}
- /* Join IPv4 group */
- memset(&m, 0, sizeof(m));
- m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
- m.imr_address.s_addr = 0;
- m.imr_ifindex = ifr.ifr_ifindex;
-
- if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m,
- sizeof(struct ip_mreqn)) == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
- t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
- close(fd);
- return -1;
+ }
+ else {
+ /* Now, open the real socket for UDP */
+ if(t->s_iptv_group.s_addr!=0) {
+ fd = tvh_socket(AF_INET, SOCK_DGRAM, 0);
}
- } else {
- /* Bind to IPv6 multicast group */
- memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_port = htons(t->s_iptv_port);
- sin6.sin6_addr = t->s_iptv_group6;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m6, sizeof(struct ipv6_mreq));
- if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1) {
- inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s",
- t->s_identifier, straddr, t->s_iptv_port,
- strerror(errno));
- close(fd);
+ else {
+ fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0);
+ }
+ if(fd == -1) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_identifier);
return -1;
}
- /* Join IPv6 group */
- memset(&m6, 0, sizeof(m6));
- m6.ipv6mr_multiaddr = t->s_iptv_group6;
- m6.ipv6mr_interface = ifr.ifr_ifindex;
-
- if(setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m6,
- sizeof(struct ipv6_mreq)) == -1) {
- inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
- straddr, sizeof(straddr));
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s",
- t->s_identifier, straddr, strerror(errno));
+
+ /* First, resolve interface name */
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
+ ifr.ifr_name[IFNAMSIZ - 1] = 0;
+ if(ioctl(fd, SIOCGIFINDEX, &ifr)) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s", t->s_identifier, t->s_iptv_iface);
close(fd);
return -1;
}
- }
+ /* Bind to IPv4 multicast group */
+ if(t->s_iptv_group.s_addr!=0) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(t->s_iptv_port);
+ sin.sin_addr.s_addr = t->s_iptv_group.s_addr;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m, sizeof(struct ip_mreqn));
+ if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s", t->s_identifier, inet_ntoa(sin.sin_addr), t->s_iptv_port, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ /* Join IPv4 group */
+ memset(&m, 0, sizeof(m));
+ m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
+ m.imr_address.s_addr = 0;
+ m.imr_ifindex = ifr.ifr_ifindex;
+
+ if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s", t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
+ close(fd);
+ return -1;
+ }
+ } else {
+ /* Bind to IPv6 multicast group */
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_port = htons(t->s_iptv_port);
+ sin6.sin6_addr = t->s_iptv_group6;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m6, sizeof(struct ipv6_mreq));
+ if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1) {
+ inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr));
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s", t->s_identifier, straddr, t->s_iptv_port, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ /* Join IPv6 group */
+ memset(&m6, 0, sizeof(m6));
+ m6.ipv6mr_multiaddr = t->s_iptv_group6;
+ m6.ipv6mr_interface = ifr.ifr_ifindex;
+
+ if(setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m6, sizeof(struct ipv6_mreq)) == -1) {
+ inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr, straddr, sizeof(straddr));
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s", t->s_identifier, straddr, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
- int resize = 262142;
- if(setsockopt(fd,SOL_SOCKET,SO_RCVBUF, &resize, sizeof(resize)) == -1)
- tvhlog(LOG_WARNING, "IPTV",
- "Can not icrease UDP receive buffer size to %d -- %s",
- resize, strerror(errno));
+ int resize = 262142;
+ if(setsockopt(fd,SOL_SOCKET,SO_RCVBUF, &resize, sizeof(resize)) == -1)
+ tvhlog(LOG_WARNING, "IPTV", "Can not icrease UDP receive buffer size to %d -- %s", resize, strerror(errno));
+ }
memset(&ev, 0, sizeof(ev));
ev.events = EPOLLIN;
ev.data.fd = fd;
if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s",
- t->s_identifier, strerror(errno));
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s", t->s_identifier, strerror(errno));
close(fd);
return -1;
}
@@ -350,49 +456,41 @@ iptv_service_stop(service_t *t)
assert(t->s_iptv_fd >= 0);
- /* First, resolve interface name */
- memset(&ifr, 0, sizeof(ifr));
- snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
- ifr.ifr_name[IFNAMSIZ - 1] = 0;
- if(ioctl(t->s_iptv_fd, SIOCGIFINDEX, &ifr)) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s",
- t->s_identifier, t->s_iptv_iface);
- }
-
- if(t->s_iptv_group.s_addr != 0) {
-
- struct ip_mreqn m;
- memset(&m, 0, sizeof(m));
- /* Leave multicast group */
- m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
- m.imr_address.s_addr = 0;
- m.imr_ifindex = ifr.ifr_ifindex;
-
- if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m,
- sizeof(struct ip_mreqn)) == -1) {
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
- t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
- }
- } else {
- char straddr[INET6_ADDRSTRLEN];
+ if(t->s_iptv_url == NULL) {
+ /* First, resolve interface name */
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%s", t->s_iptv_iface);
+ ifr.ifr_name[IFNAMSIZ - 1] = 0;
+ if(ioctl(t->s_iptv_fd, SIOCGIFINDEX, &ifr)) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s", t->s_identifier, t->s_iptv_iface);
+ }
+
+ if(t->s_iptv_group.s_addr != 0) {
+ struct ip_mreqn m;
+ memset(&m, 0, sizeof(m));
+ /* Leave multicast group */
+ m.imr_multiaddr.s_addr = t->s_iptv_group.s_addr;
+ m.imr_address.s_addr = 0;
+ m.imr_ifindex = ifr.ifr_ifindex;
- struct ipv6_mreq m6;
- memset(&m6, 0, sizeof(m6));
-
- m6.ipv6mr_multiaddr = t->s_iptv_group6;
- m6.ipv6mr_interface = ifr.ifr_ifindex;
-
- if(setsockopt(t->s_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m6,
- sizeof(struct ipv6_mreq)) == -1) {
- inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr,
- straddr, sizeof(straddr));
+ if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) {
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", t->s_identifier, inet_ntoa(m.imr_multiaddr), strerror(errno));
+ }
+ } else {
+ char straddr[INET6_ADDRSTRLEN];
- tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s",
- t->s_identifier, straddr, strerror(errno));
- }
+ struct ipv6_mreq m6;
+ memset(&m6, 0, sizeof(m6));
+ m6.ipv6mr_multiaddr = t->s_iptv_group6;
+ m6.ipv6mr_interface = ifr.ifr_ifindex;
+ if(setsockopt(t->s_iptv_fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &m6, sizeof(struct ipv6_mreq)) == -1) {
+ inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr, straddr, sizeof(straddr));
+ tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", t->s_identifier, straddr, strerror(errno));
+ }
+ }
}
close(t->s_iptv_fd); // Automatically removes fd from epoll set
@@ -423,9 +521,14 @@ iptv_service_save(service_t *t)
if(t->s_iptv_iface)
htsmsg_add_str(m, "interface", t->s_iptv_iface);
- if(t->s_iptv_group.s_addr!= 0) {
- inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
- htsmsg_add_str(m, "group", abuf);
+ if(t->s_iptv_url != 0){
+ htsmsg_add_str(m, "url", t->s_iptv_url);
+ }
+ else{
+ if(t->s_iptv_group.s_addr!= 0) {
+ inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
+ htsmsg_add_str(m, "group", abuf);
+ }
}
if(IN6_IS_ADDR_MULTICAST(t->s_iptv_group6.s6_addr) ) {
inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6));
@@ -435,13 +538,13 @@ iptv_service_save(service_t *t)
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
htsmsg_add_u32(m, "mapped", 1);
}
-
+
pthread_mutex_lock(&t->s_stream_mutex);
+ service_make_nicename(t);
psi_save_service_settings(m, t);
pthread_mutex_unlock(&t->s_stream_mutex);
-
- hts_settings_save(m, "iptvservices/%s",
- t->s_identifier);
+
+ hts_settings_save(m, "iptvservices/%s", t->s_identifier);
htsmsg_destroy(m);
}
@@ -453,9 +556,7 @@ iptv_service_save(service_t *t)
static int
iptv_service_quality(service_t *t)
{
- if(t->s_iptv_iface == NULL ||
- (t->s_iptv_group.s_addr == 0 && t->s_iptv_group6.s6_addr == 0) ||
- t->s_iptv_port == 0)
+ if(t->s_iptv_url == NULL && (t->s_iptv_iface == NULL || (t->s_iptv_group.s_addr == 0 && t->s_iptv_group6.s6_addr == 0) || t->s_iptv_port == 0))
return 0;
return 100;
@@ -481,12 +582,17 @@ iptv_service_setsourceinfo(service_t *t,
si->si_type = S_MPEG_TS;
si->si_adapter = t->s_iptv_iface ? strdup(t->s_iptv_iface) : NULL;
- if(t->s_iptv_group.s_addr != 0) {
- si->si_mux = strdup(inet_ntoa(t->s_iptv_group));
+ if(t->s_iptv_url != 0){
+ si->si_mux = strdup(t->s_iptv_url);
}
- else {
- inet_ntop(AF_INET6, &t->s_iptv_group6, straddr, sizeof(straddr));
- si->si_mux = strdup(straddr);
+ else{
+ if(t->s_iptv_group.s_addr != 0) {
+ si->si_mux = strdup(inet_ntoa(t->s_iptv_group));
+ }
+ else {
+ inet_ntop(AF_INET6, &t->s_iptv_group6, straddr, sizeof(straddr));
+ si->si_mux = strdup(straddr);
+ }
}
}
@@ -528,7 +634,7 @@ iptv_service_find(const char *id, int cr
LIST_FOREACH(t, &iptv_all_services, s_group_link)
if(!strcmp(t->s_identifier, id))
- return t;
+ return t;
}
if(create == 0)
@@ -588,25 +694,30 @@ iptv_service_load(void)
else
old = 1;
}
-
+
HTSMSG_FOREACH(f, l) {
if((c = htsmsg_get_map_by_field(f)) == NULL)
continue;
if(htsmsg_get_u32(c, "pmt", &pmt))
continue;
-
+
t = iptv_service_find(f->hmf_name, 1);
t->s_pmt_pid = pmt;
tvh_str_update(&t->s_iptv_iface, htsmsg_get_str(c, "interface"));
- if((s = htsmsg_get_str(c, "group")) != NULL){
- if (!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)) {
- inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
+ if((s = htsmsg_get_str(c, "url")) != NULL){
+ tvh_str_update(&t->s_iptv_url, htsmsg_get_str(c, "url"));
+ }
+ else{
+ if((s = htsmsg_get_str(c, "group")) != NULL){
+ if (!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)) {
+ inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
+ }
}
}
-
+
if(!htsmsg_get_u32(c, "port", &u32))
t->s_iptv_port = u32;
@@ -622,11 +733,11 @@ iptv_service_load(void)
service_make_nicename(t);
psi_load_service_settings(c, t);
pthread_mutex_unlock(&t->s_stream_mutex);
-
+
s = htsmsg_get_str(c, "channelname");
if(htsmsg_get_u32(c, "mapped", &u32))
u32 = 0;
-
+
if(s && u32)
service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
diff -rupN tvheadend-3.4patch1/src/service.h tvheadend-3.4patch2/src/service.h
--- tvheadend-3.4patch1/src/service.h 2013-07-11 21:17:34.000000000 +0200
+++ tvheadend-3.4patch2/src/service.h 2013-10-04 08:00:04.000000000 +0200
@@ -377,10 +377,13 @@ typedef struct service {
* IPTV members
*/
char *s_iptv_iface;
+ char *s_iptv_url;
struct in_addr s_iptv_group;
struct in6_addr s_iptv_group6;
uint16_t s_iptv_port;
int s_iptv_fd;
+ uint8_t s_iptv_tsb[188];
+ int s_iptv_tsb_len;
/**
* For per-transport PAT/PMT parsers, allocated on demand
diff -rupN tvheadend-3.4patch1/src/version.c tvheadend-3.4patch2/src/version.c
--- tvheadend-3.4patch1/src/version.c 1970-01-01 01:00:00.000000000 +0100
+++ tvheadend-3.4patch2/src/version.c 2013-10-02 08:00:02.000000000 +0200
@@ -0,0 +1 @@
+const char *tvheadend_version = "";
diff -rupN tvheadend-3.4patch1/src/webui/extjs.c tvheadend-3.4patch2/src/webui/extjs.c
--- tvheadend-3.4patch1/src/webui/extjs.c 2013-07-11 21:17:34.000000000 +0200
+++ tvheadend-3.4patch2/src/webui/extjs.c 2014-04-04 16:00:04.000000000 +0200
@@ -1745,12 +1745,18 @@ service_update_iptv(htsmsg_t *in)
}
if((s = htsmsg_get_str(c, "group")) != NULL) {
- if(!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)){
- inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
+ if(!strncmp(s, "http", 4)){
+ tvh_str_update(&t->s_iptv_url, s);
+ }
+ else {
+ t->s_iptv_url = NULL;
+
+ if(!inet_pton(AF_INET, s, &t->s_iptv_group.s_addr)) {
+ inet_pton(AF_INET6, s, &t->s_iptv_group6.s6_addr);
+ }
}
save = 1;
}
-
save |= tvh_str_update(&t->s_iptv_iface, htsmsg_get_str(c, "interface"));
if(save)
@@ -1772,13 +1778,18 @@ build_record_iptv(service_t *t)
htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : "");
htsmsg_add_str(r, "interface", t->s_iptv_iface ?: "");
- if(t->s_iptv_group.s_addr != 0){
- inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
- htsmsg_add_str(r, "group", t->s_iptv_group.s_addr ? abuf : "");
+ if(t->s_iptv_url != 0) {
+ htsmsg_add_str(r, "group", t->s_iptv_url ?: "");
}
else {
- inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6));
- htsmsg_add_str(r, "group", t->s_iptv_group6.s6_addr ? abuf6 : "");
+ if(t->s_iptv_group.s_addr != 0) {
+ inet_ntop(AF_INET, &t->s_iptv_group, abuf, sizeof(abuf));
+ htsmsg_add_str(r, "group", t->s_iptv_group.s_addr ? abuf : "");
+ }
+ else {
+ inet_ntop(AF_INET6, &t->s_iptv_group6, abuf6, sizeof(abuf6));
+ htsmsg_add_str(r, "group", t->s_iptv_group6.s6_addr ? abuf6 : "");
+ }
}
htsmsg_add_u32(r, "port", t->s_iptv_port);
@@ -1796,7 +1807,10 @@ iptv_servicecmp(const void *A, const voi
service_t *a = *(service_t **)A;
service_t *b = *(service_t **)B;
- return memcmp(&a->s_iptv_group, &b->s_iptv_group, 4);
+ if(&a->s_iptv_url != 0)
+ return strcmp(a->s_iptv_url, b->s_iptv_url);
+ else
+ return memcmp(&a->s_iptv_group, &b->s_iptv_group, 4);
}
/**
diff -rupN tvheadend-3.4patch1/src/webui/static/app/iptv.js tvheadend-3.4patch2/src/webui/static/app/iptv.js
--- tvheadend-3.4patch1/src/webui/static/app/iptv.js 2013-07-11 21:17:34.000000000 +0200
+++ tvheadend-3.4patch2/src/webui/static/app/iptv.js 2013-10-04 08:00:04.000000000 +0200
@@ -48,7 +48,7 @@ tvheadend.iptv = function(adapterId) {
{
header : "Channel name",
dataIndex : 'channelname',
- width : 150,
+ width : 100,
renderer : function(value, metadata, record, row, col, store) {
return value ? value
: 'Unmapped';
@@ -67,7 +67,7 @@ tvheadend.iptv = function(adapterId) {
{
header : "Interface",
dataIndex : 'interface',
- width : 100,
+ width : 50,
renderer : function(value, metadata, record, row, col, store) {
return value ? value : 'Unset';
},
@@ -76,9 +76,9 @@ tvheadend.iptv = function(adapterId) {
})
},
{
- header : "Group",
+ header : "Address / Group",
dataIndex : 'group',
- width : 100,
+ width : 150,
renderer : function(value, metadata, record, row, col, store) {
return value ? value : 'Unset';
},
@@ -89,7 +89,7 @@ tvheadend.iptv = function(adapterId) {
{
header : "UDP Port",
dataIndex : 'port',
- width : 60,
+ width : 50,
editor : new fm.NumberField({
minValue : 1,
maxValue : 65535