bouquet,fastscan: initial implementation
This commit is contained in:
parent
a9b1d171be
commit
7134315e0f
21 changed files with 899 additions and 24 deletions
7
Makefile
7
Makefile
|
@ -152,7 +152,8 @@ SRCS = src/version.c \
|
|||
src/cron.c \
|
||||
src/esfilter.c \
|
||||
src/intlconv.c \
|
||||
src/profile.c
|
||||
src/profile.c \
|
||||
src/bouquet.c
|
||||
|
||||
SRCS-${CONFIG_UPNP} += \
|
||||
src/upnp.c
|
||||
|
@ -173,7 +174,8 @@ SRCS += \
|
|||
src/api/api_access.c \
|
||||
src/api/api_dvr.c \
|
||||
src/api/api_caclient.c \
|
||||
src/api/api_profile.c
|
||||
src/api/api_profile.c \
|
||||
src/api/api_bouquet.c
|
||||
|
||||
SRCS += \
|
||||
src/parsers/parsers.c \
|
||||
|
@ -229,6 +231,7 @@ SRCS-$(CONFIG_MPEGTS) += \
|
|||
src/input/mpegts/dvb_support.c \
|
||||
src/input/mpegts/dvb_charset.c \
|
||||
src/input/mpegts/dvb_psi.c \
|
||||
src/input/mpegts/fastscan.c \
|
||||
src/input/mpegts/tsdemux.c \
|
||||
src/input/mpegts/mpegts_mux_sched.c \
|
||||
src/input/mpegts/mpegts_network_scan.c \
|
||||
|
|
50
data/conf/fastscan
Normal file
50
data/conf/fastscan
Normal file
|
@ -0,0 +1,50 @@
|
|||
[
|
||||
{
|
||||
"name": "Canal Digitaal",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 900
|
||||
},
|
||||
{
|
||||
"name": "TV Vlaanderen",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 901
|
||||
},
|
||||
{
|
||||
"name": "TéléSAT",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 920
|
||||
},
|
||||
{
|
||||
"name": "Mobistar NL",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 930
|
||||
},
|
||||
{
|
||||
"name": "Mobistar FR",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 940
|
||||
},
|
||||
{
|
||||
"name": "AustriaSat",
|
||||
"position": 192,
|
||||
"frequency": 12515000,
|
||||
"pid": 950
|
||||
},
|
||||
{
|
||||
"name": "Skylink: Czech Republic",
|
||||
"position": 235,
|
||||
"frequency": 12070000,
|
||||
"pid": 30
|
||||
},
|
||||
{
|
||||
"name": "Skylink: Slovak Republic",
|
||||
"position": 235,
|
||||
"frequency": 12070000,
|
||||
"pid": 31
|
||||
}
|
||||
]
|
|
@ -125,6 +125,7 @@ void api_init ( void )
|
|||
api_mpegts_init();
|
||||
api_service_init();
|
||||
api_channel_init();
|
||||
api_bouquet_init();
|
||||
api_epg_init();
|
||||
api_epggrab_init();
|
||||
api_status_init();
|
||||
|
|
|
@ -64,6 +64,7 @@ void api_idnode_init ( void );
|
|||
void api_input_init ( void );
|
||||
void api_service_init ( void );
|
||||
void api_channel_init ( void );
|
||||
void api_bouquet_init ( void );
|
||||
void api_mpegts_init ( void );
|
||||
void api_epg_init ( void );
|
||||
void api_epggrab_init ( void );
|
||||
|
|
70
src/api/api_bouquet.c
Normal file
70
src/api/api_bouquet.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* API - bouquet calls
|
||||
*
|
||||
* 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_API_BOUQUET_H__
|
||||
#define __TVH_API_BOUQUET_H__
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "bouquet.h"
|
||||
#include "access.h"
|
||||
#include "api.h"
|
||||
|
||||
static void
|
||||
api_bouquet_grid
|
||||
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
bouquet_t *bq;
|
||||
|
||||
RB_FOREACH(bq, &bouquets, bq_link)
|
||||
idnode_set_add(ins, (idnode_t*)bq, &conf->filter);
|
||||
}
|
||||
|
||||
static int
|
||||
api_bouquet_create
|
||||
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
htsmsg_t *conf;
|
||||
bouquet_t *bq;
|
||||
|
||||
if (!(conf = htsmsg_get_map(args, "conf")))
|
||||
return EINVAL;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
bq = bouquet_create(NULL, conf, NULL, NULL);
|
||||
if (bq)
|
||||
bouquet_save(bq, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void api_bouquet_init ( void )
|
||||
{
|
||||
static api_hook_t ah[] = {
|
||||
{ "bouquet/class", ACCESS_ADMIN, api_idnode_class, (void*)&bouquet_class },
|
||||
{ "bouquet/grid", ACCESS_ADMIN, api_idnode_grid, api_bouquet_grid },
|
||||
{ "bouquet/create", ACCESS_ADMIN, api_bouquet_create, NULL },
|
||||
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
api_register_all(ah);
|
||||
}
|
||||
|
||||
#endif /* __TVH_API_BOUQUET_H__ */
|
|
@ -17,8 +17,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_API_SERVICE_H__
|
||||
#define __TVH_API_SERVICE_H__
|
||||
#ifndef __TVH_API_CHANNEL_H__
|
||||
#define __TVH_API_CHANNEL_H__
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "channels.h"
|
||||
|
@ -145,4 +145,4 @@ void api_channel_init ( void )
|
|||
}
|
||||
|
||||
|
||||
#endif /* __TVH_API_IDNODE_H__ */
|
||||
#endif /* __TVH_API_CHANNEL_H__ */
|
||||
|
|
|
@ -199,4 +199,4 @@ void api_service_init ( void )
|
|||
}
|
||||
|
||||
|
||||
#endif /* __TVH_API_IDNODE_H__ */
|
||||
#endif /* __TVH_API_SERVICE_H__ */
|
||||
|
|
387
src/bouquet.c
Normal file
387
src/bouquet.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* tvheadend, bouquets
|
||||
* 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 "settings.h"
|
||||
#include "access.h"
|
||||
#include "bouquet.h"
|
||||
#include "service.h"
|
||||
|
||||
bouquet_tree_t bouquets;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
_bq_cmp(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(((bouquet_t *)a)->bq_src ?: "", ((bouquet_t *)b)->bq_src ?: "");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_create(const char *uuid, htsmsg_t *conf,
|
||||
const char *name, const char *src)
|
||||
{
|
||||
bouquet_t *bq, *bq2;
|
||||
int i;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
bq = calloc(1, sizeof(bouquet_t));
|
||||
bq->bq_services = idnode_set_create();
|
||||
|
||||
if (idnode_insert(&bq->bq_id, uuid, &bouquet_class, 0)) {
|
||||
if (uuid)
|
||||
tvherror("bouquet", "invalid uuid '%s'", uuid);
|
||||
free(bq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conf) {
|
||||
bq->bq_in_load = 1;
|
||||
idnode_load(&bq->bq_id, conf);
|
||||
bq->bq_in_load = 0;
|
||||
if (!htsmsg_get_bool(conf, "shield", &i) && i)
|
||||
bq->bq_shield = 1;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
free(bq->bq_name);
|
||||
bq->bq_name = strdup(name);
|
||||
}
|
||||
|
||||
if (src) {
|
||||
free(bq->bq_src);
|
||||
bq->bq_src = strdup(src);
|
||||
}
|
||||
|
||||
bq2 = RB_INSERT_SORTED(&bouquets, bq, bq_link, _bq_cmp);
|
||||
assert(bq2 == NULL);
|
||||
|
||||
bq->bq_saveflag = 1;
|
||||
|
||||
return bq;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
bouquet_destroy(bouquet_t *bq)
|
||||
{
|
||||
if (!bq)
|
||||
return;
|
||||
|
||||
RB_REMOVE(&bouquets, bq, bq_link);
|
||||
idnode_unlink(&bq->bq_id);
|
||||
|
||||
idnode_set_free(bq->bq_services);
|
||||
free(bq->bq_name);
|
||||
free(bq->bq_src);
|
||||
free(bq);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_destroy_by_service(service_t *t)
|
||||
{
|
||||
bouquet_t *bq;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
RB_FOREACH(bq, &bouquets, bq_link)
|
||||
if (idnode_set_exists(bq->bq_services, &t->s_id))
|
||||
idnode_set_remove(bq->bq_services, &t->s_id);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_find_by_source(const char *name, const char *src, int create)
|
||||
{
|
||||
bouquet_t *bq;
|
||||
bouquet_t bqs;
|
||||
|
||||
assert(src);
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
bqs.bq_src = (char *)src;
|
||||
bq = RB_FIND(&bouquets, &bqs, bq_link, _bq_cmp);
|
||||
if (bq)
|
||||
return bq;
|
||||
if (create && name)
|
||||
return bouquet_create(NULL, NULL, name, src);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_add_service(bouquet_t *bq, service_t *s)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (!idnode_set_exists(bq->bq_services, &s->s_id)) {
|
||||
idnode_set_add(bq->bq_services, &s->s_id, NULL);
|
||||
bq->bq_saveflag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_save(bouquet_t *bq, int notify)
|
||||
{
|
||||
htsmsg_t *c = htsmsg_create_map();
|
||||
idnode_save(&bq->bq_id, c);
|
||||
hts_settings_save(c, "bouquet/%s", idnode_uuid_as_str(&bq->bq_id));
|
||||
if (bq->bq_shield)
|
||||
htsmsg_add_bool(c, "shield", 1);
|
||||
htsmsg_destroy(c);
|
||||
bq->bq_saveflag = 0;
|
||||
if (notify)
|
||||
idnode_notify_simple(&bq->bq_id);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Class definition
|
||||
* **************************************************************************/
|
||||
|
||||
static void
|
||||
bouquet_class_save(idnode_t *self)
|
||||
{
|
||||
bouquet_save((bouquet_t *)self, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
bouquet_class_delete(idnode_t *self)
|
||||
{
|
||||
bouquet_t *bq = (bouquet_t *)self;
|
||||
|
||||
if (!bq->bq_shield) {
|
||||
hts_settings_remove("bouquet/%s", idnode_uuid_as_str(&bq->bq_id));
|
||||
bouquet_destroy(bq);
|
||||
} else {
|
||||
idnode_set_free(bq->bq_services);
|
||||
bq->bq_services = idnode_set_create();
|
||||
bouquet_save(bq, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
bouquet_class_get_title (idnode_t *self)
|
||||
{
|
||||
bouquet_t *bq = (bouquet_t *)self;
|
||||
|
||||
if (bq->bq_comment && bq->bq_comment[0] != '\0')
|
||||
return bq->bq_comment;
|
||||
return bq->bq_name ?: "";
|
||||
}
|
||||
|
||||
static void
|
||||
bouquet_class_enabled_notify ( void *obj )
|
||||
{
|
||||
bouquet_t *bq = obj;
|
||||
service_t *s;
|
||||
size_t z;
|
||||
|
||||
if (!bq->bq_enabled) {
|
||||
for (z = 0; z < bq->bq_services->is_count; z++) {
|
||||
s = (service_t *)bq->bq_services->is_array[z];
|
||||
if (s->s_master_bouquet == bq)
|
||||
s->s_master_bouquet = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const void *
|
||||
bouquet_class_services_get ( void *obj )
|
||||
{
|
||||
htsmsg_t *l = htsmsg_create_list();
|
||||
bouquet_t *bq = obj;
|
||||
size_t z;
|
||||
|
||||
/* Add all */
|
||||
for (z = 0; z < bq->bq_services->is_count; z++)
|
||||
htsmsg_add_str(l, NULL, idnode_uuid_as_str(bq->bq_services->is_array[z]));
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static char *
|
||||
bouquet_class_services_rend ( void *obj )
|
||||
{
|
||||
bouquet_t *bq = obj;
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "Services Count %zi", bq->bq_services->is_count);
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
bouquet_class_services_set ( void *obj, const void *p )
|
||||
{
|
||||
bouquet_t *bq = obj;
|
||||
|
||||
if (bq->bq_services_waiting)
|
||||
htsmsg_destroy(bq->bq_services_waiting);
|
||||
bq->bq_services_waiting = NULL;
|
||||
if (bq->bq_in_load)
|
||||
bq->bq_services_waiting = htsmsg_copy((htsmsg_t *)p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *
|
||||
bouquet_class_services_count_get ( void *obj )
|
||||
{
|
||||
static uint32_t u32;
|
||||
bouquet_t *bq = obj;
|
||||
|
||||
u32 = bq->bq_services->is_count;
|
||||
return &u32;
|
||||
}
|
||||
|
||||
const idclass_t bouquet_class = {
|
||||
.ic_class = "bouquet",
|
||||
.ic_caption = "Bouquet",
|
||||
.ic_event = "bouquet",
|
||||
.ic_perm_def = ACCESS_ADMIN,
|
||||
.ic_save = bouquet_class_save,
|
||||
.ic_get_title = bouquet_class_get_title,
|
||||
.ic_delete = bouquet_class_delete,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "enabled",
|
||||
.name = "Enabled",
|
||||
.off = offsetof(bouquet_t, bq_enabled),
|
||||
.notify = bouquet_class_enabled_notify,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "name",
|
||||
.name = "Name",
|
||||
.off = offsetof(bouquet_t, bq_name),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "source",
|
||||
.name = "Source",
|
||||
.off = offsetof(bouquet_t, bq_src),
|
||||
.opts = PO_RDONLY,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.islist = 1,
|
||||
.id = "services",
|
||||
.name = "Services",
|
||||
.get = bouquet_class_services_get,
|
||||
.set = bouquet_class_services_set,
|
||||
.rend = bouquet_class_services_rend,
|
||||
.opts = PO_RDONLY | PO_HIDDEN,
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "services_count",
|
||||
.name = "# Services",
|
||||
.get = bouquet_class_services_count_get,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "comment",
|
||||
.name = "Comment",
|
||||
.off = offsetof(bouquet_t, bq_comment),
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "lcn_off",
|
||||
.name = "Channel Number Offset",
|
||||
.off = offsetof(bouquet_t, bq_lcn_offset),
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_init(void)
|
||||
{
|
||||
htsmsg_t *c, *m;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
RB_INIT(&bouquets);
|
||||
|
||||
/* Load */
|
||||
if ((c = hts_settings_load("bouquet")) != NULL) {
|
||||
HTSMSG_FOREACH(f, c) {
|
||||
if (!(m = htsmsg_field_get_map(f))) continue;
|
||||
(void)bouquet_create(f->hmf_name, m, NULL, NULL);
|
||||
}
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bouquet_service_resolve(void)
|
||||
{
|
||||
bouquet_t *bq;
|
||||
htsmsg_field_t *f;
|
||||
service_t *s;
|
||||
const char *str;
|
||||
int saveflag;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
RB_FOREACH(bq, &bouquets, bq_link) {
|
||||
if (!bq->bq_services_waiting)
|
||||
continue;
|
||||
saveflag = bq->bq_saveflag;
|
||||
HTSMSG_FOREACH(f, bq->bq_services_waiting) {
|
||||
if ((str = htsmsg_field_get_str(f))) {
|
||||
s = service_find_by_identifier(str);
|
||||
if (s)
|
||||
bouquet_add_service(bq, s);
|
||||
}
|
||||
}
|
||||
htsmsg_destroy(bq->bq_services_waiting);
|
||||
bq->bq_services_waiting = NULL;
|
||||
bq->bq_saveflag = saveflag;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bouquet_done(void)
|
||||
{
|
||||
bouquet_t *bq;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((bq = RB_FIRST(&bouquets)) != NULL)
|
||||
bouquet_destroy(bq);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
88
src/bouquet.h
Normal file
88
src/bouquet.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* TV headend - Bouquets
|
||||
* 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 BOUQUET_H_
|
||||
#define BOUQUET_H_
|
||||
|
||||
#include "idnode.h"
|
||||
#include "htsmsg.h"
|
||||
#include "service.h"
|
||||
|
||||
typedef struct bouquet {
|
||||
idnode_t bq_id;
|
||||
RB_ENTRY(bouquet) bq_link;
|
||||
|
||||
int bq_saveflag;
|
||||
int bq_in_load;
|
||||
|
||||
int bq_shield;
|
||||
int bq_enabled;
|
||||
char *bq_name;
|
||||
char *bq_src;
|
||||
char *bq_comment;
|
||||
idnode_set_t *bq_services;
|
||||
htsmsg_t *bq_services_waiting;
|
||||
uint32_t bq_lcn_offset;
|
||||
|
||||
} bouquet_t;
|
||||
|
||||
typedef RB_HEAD(,bouquet) bouquet_tree_t;
|
||||
|
||||
extern bouquet_tree_t bouquets;
|
||||
|
||||
extern const idclass_t bouquet_class;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_create(const char *uuid, htsmsg_t *conf,
|
||||
const char *name, const char *src);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_destroy_by_service(service_t *t);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_find_by_source(const char *name, const char *src, int create);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_add_service(bouquet_t *bq, service_t *s);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_save(bouquet_t *bq, int notify);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void bouquet_init(void);
|
||||
void bouquet_service_resolve(void);
|
||||
void bouquet_done(void);
|
||||
|
||||
#endif /* BOUQUET_H_ */
|
19
src/idnode.c
19
src/idnode.c
|
@ -164,8 +164,8 @@ idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class, int flags)
|
|||
} while (c != NULL && --retries > 0);
|
||||
|
||||
if(c != NULL) {
|
||||
fprintf(stderr, "Id node collision%s\n",
|
||||
(flags & IDNODE_SHORT_UUID) ? " (short)" : "");
|
||||
fprintf(stderr, "Id node collision (%s) %s\n",
|
||||
uuid, (flags & IDNODE_SHORT_UUID) ? " (short)" : "");
|
||||
abort();
|
||||
}
|
||||
tvhtrace("idnode", "insert node %s", idnode_uuid_as_str(in));
|
||||
|
@ -958,6 +958,21 @@ idnode_set_add
|
|||
is->is_array[is->is_count++] = in;
|
||||
}
|
||||
|
||||
void
|
||||
idnode_set_remove
|
||||
( idnode_set_t *is, idnode_t *in )
|
||||
{
|
||||
size_t z;
|
||||
|
||||
for (z = 0; z < is->is_count; z++)
|
||||
if (is->is_array[z] == in) {
|
||||
memmove(&is->is_array[z], &is->is_array[z+1],
|
||||
(is->is_count - z - 1) * sizeof(idnode_t *));
|
||||
is->is_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
idnode_set_exists
|
||||
( idnode_set_t *is, idnode_t * in )
|
||||
|
|
|
@ -200,11 +200,12 @@ int idnode_filter
|
|||
#define idnode_set_create() calloc(1, sizeof(idnode_set_t))
|
||||
void idnode_set_add
|
||||
( idnode_set_t *is, idnode_t *in, idnode_filter_t *filt );
|
||||
void idnode_set_remove ( idnode_set_t *is, idnode_t *in );
|
||||
int idnode_set_exists ( idnode_set_t *is, idnode_t *in );
|
||||
void idnode_set_sort ( idnode_set_t *is, idnode_sort_t *s );
|
||||
void idnode_set_sort ( idnode_set_t *is, idnode_sort_t *s );
|
||||
void idnode_set_sort_by_title ( idnode_set_t *is );
|
||||
htsmsg_t *idnode_set_as_htsmsg ( idnode_set_t *is );
|
||||
void idnode_set_free ( idnode_set_t *is );
|
||||
void idnode_set_free ( idnode_set_t *is );
|
||||
|
||||
#endif /* __TVH_IDNODE_H__ */
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "mpegts/fastscan.h"
|
||||
|
||||
void
|
||||
mpegts_init ( int linuxdvb_mask, str_list_t *satip_client,
|
||||
|
@ -27,6 +28,9 @@ mpegts_init ( int linuxdvb_mask, str_list_t *satip_client,
|
|||
idclass_register(&mpegts_mux_class);
|
||||
idclass_register(&mpegts_service_class);
|
||||
|
||||
/* FastScan init */
|
||||
dvb_fastscan_init();
|
||||
|
||||
/* Network scanner */
|
||||
#if ENABLE_MPEGTS
|
||||
mpegts_network_scan_init();
|
||||
|
@ -97,6 +101,7 @@ mpegts_done ( void )
|
|||
#if ENABLE_TSFILE
|
||||
tvhftrace("main", tsfile_done);
|
||||
#endif
|
||||
dvb_fastscan_done();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -425,9 +425,9 @@ struct mpegts_service
|
|||
* Fields defined by DVB standard EN 300 468
|
||||
*/
|
||||
|
||||
uint16_t s_dvb_service_id;
|
||||
uint16_t s_dvb_channel_num;
|
||||
uint32_t s_dvb_channel_num;
|
||||
uint16_t s_dvb_channel_minor;
|
||||
uint16_t s_dvb_service_id;
|
||||
char *s_dvb_svcname;
|
||||
char *s_dvb_provider;
|
||||
char *s_dvb_cridauth;
|
||||
|
|
|
@ -59,6 +59,10 @@ struct mpegts_mux;
|
|||
#define DVB_BAT_BASE 0x48
|
||||
#define DVB_BAT_MASK 0xF8
|
||||
|
||||
#define DVB_FASTSCAN_NIT_BASE 0xBC
|
||||
#define DVB_FASTSCAN_SDT_BASE 0xBD
|
||||
#define DVB_FASTSCAN_MASK 0xFF
|
||||
|
||||
#define DVB_VCT_T_BASE 0xC8
|
||||
#define DVB_VCT_C_BASE 0xC9
|
||||
#define DVB_VCT_MASK 0xFF
|
||||
|
@ -210,6 +214,8 @@ int dvb_nit_callback
|
|||
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
|
||||
int dvb_bat_callback
|
||||
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
|
||||
int dvb_fs_sdt_callback
|
||||
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
|
||||
int dvb_sdt_callback
|
||||
(struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
|
||||
int dvb_tdt_callback
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "lang_codes.h"
|
||||
#include "service.h"
|
||||
#include "dvb_charset.h"
|
||||
#include "bouquet.h"
|
||||
#include "fastscan.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
@ -321,7 +323,7 @@ dvb_desc_service
|
|||
|
||||
static int
|
||||
dvb_desc_service_list
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm )
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm, bouquet_t *bq )
|
||||
{
|
||||
uint16_t stype, sid;
|
||||
int i;
|
||||
|
@ -333,6 +335,8 @@ dvb_desc_service_list
|
|||
if (mm) {
|
||||
int save = 0;
|
||||
s = mpegts_service_find(mm, sid, 0, 1, &save);
|
||||
if (bq)
|
||||
bouquet_add_service(bq, (service_t *)s);
|
||||
if (save)
|
||||
s->s_config_save((service_t*)s);
|
||||
}
|
||||
|
@ -342,7 +346,7 @@ dvb_desc_service_list
|
|||
|
||||
static int
|
||||
dvb_desc_local_channel
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm )
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm, bouquet_t *bq )
|
||||
{
|
||||
int save = 0;
|
||||
uint16_t sid, lcn;
|
||||
|
@ -354,6 +358,11 @@ dvb_desc_local_channel
|
|||
if (lcn && mm) {
|
||||
mpegts_service_t *s = mpegts_service_find(mm, sid, 0, 0, &save);
|
||||
if (s) {
|
||||
if (bq && bq->bq_lcn_offset &&
|
||||
(!s->s_master_bouquet || s->s_master_bouquet == bq)) {
|
||||
lcn += bq->bq_lcn_offset;
|
||||
s->s_master_bouquet = bq;
|
||||
}
|
||||
if (s->s_dvb_channel_num != lcn) {
|
||||
s->s_dvb_channel_num = lcn;
|
||||
s->s_config_save((service_t*)s);
|
||||
|
@ -721,18 +730,20 @@ dvb_nit_callback
|
|||
mpegts_network_t *mn = mm->mm_network;
|
||||
char name[256], dauth[256];
|
||||
mpegts_table_state_t *st = NULL;
|
||||
bouquet_t *bq = NULL;
|
||||
const char *charset;
|
||||
|
||||
/* Net/Bat ID */
|
||||
nbid = (ptr[0] << 8) | ptr[1];
|
||||
|
||||
/* Begin */
|
||||
if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A) return -1;
|
||||
if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A && tableid != 0xBC)
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, &st, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
|
||||
/* NIT */
|
||||
if (tableid != 0x4A) {
|
||||
if (tableid != 0x4A && tableid != 0xBC /* fastscan */) {
|
||||
|
||||
/* Specific NID */
|
||||
if (mn->mn_nid) {
|
||||
|
@ -764,8 +775,13 @@ dvb_nit_callback
|
|||
}
|
||||
}
|
||||
|
||||
/* Fastscan */
|
||||
if (tableid == 0xBC) {
|
||||
tvhdebug(mt->mt_name, "fastscan %04X (%d) [%s]", nbid, nbid, name);
|
||||
bq = mt->mt_opaque;
|
||||
|
||||
/* BAT */
|
||||
if (tableid == 0x4A) {
|
||||
} else if (tableid == 0x4A) {
|
||||
tvhdebug(mt->mt_name, "bouquet %04X (%d) [%s]", nbid, nbid, name);
|
||||
|
||||
/* NIT */
|
||||
|
@ -780,7 +796,6 @@ dvb_nit_callback
|
|||
DVB_LOOP_FOREACH(ptr, len, 0, lptr, llen, 6) {
|
||||
tsid = (lptr[0] << 8) | lptr[1];
|
||||
onid = (lptr[2] << 8) | lptr[3];
|
||||
tvhdebug(mt->mt_name, " onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
|
||||
|
||||
/* Find existing mux */
|
||||
LIST_FOREACH(mux, &mn->mn_muxes, mm_network_link)
|
||||
|
@ -788,6 +803,33 @@ dvb_nit_callback
|
|||
break;
|
||||
charset = dvb_charset_find(mn, mux, NULL);
|
||||
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
dauth[0] = 0;
|
||||
if (mux && *name && tableid == 0x4A /* BAT */) {
|
||||
if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbs_class)) {
|
||||
dvb_mux_conf_t *mc = &((dvb_mux_t *)mux)->lm_tuning;
|
||||
if (mc->u.dmc_fe_qpsk.orbital_dir) {
|
||||
int pos = mc->u.dmc_fe_qpsk.orbital_pos;
|
||||
if (mc->u.dmc_fe_qpsk.orbital_dir == 'W')
|
||||
pos = -pos;
|
||||
snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbs,%d/%s", pos, name);
|
||||
}
|
||||
} else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbt_class)) {
|
||||
snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbt/%s", name);
|
||||
} else if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbc_class)) {
|
||||
snprintf(dauth, sizeof(dauth), "dvb-bouquet://dvbc/%s", name);
|
||||
}
|
||||
}
|
||||
if (dauth[0]) {
|
||||
bouquet_t *bq2 = bouquet_find_by_source(name, dauth, 1);
|
||||
if (bq2 != bq && bq && bq->bq_saveflag)
|
||||
bouquet_save(bq, 1);
|
||||
bq = bq2;
|
||||
}
|
||||
#endif
|
||||
|
||||
tvhdebug(mt->mt_name, " onid %04X (%d) tsid %04X (%d) mux %p bq %p", onid, onid, tsid, tsid, mux, bq);
|
||||
|
||||
DVB_DESC_FOREACH(lptr, llen, 4, dlptr, dllen, dtag, dlen, dptr) {
|
||||
tvhtrace(mt->mt_name, " dtag %02X dlen %d", dtag, dlen);
|
||||
|
||||
|
@ -839,17 +881,20 @@ dvb_nit_callback
|
|||
mpegts_mux_set_crid_authority(mux, dauth);
|
||||
break;
|
||||
case DVB_DESC_LOCAL_CHAN:
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux))
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux, bq))
|
||||
return -1;
|
||||
break;
|
||||
case DVB_DESC_SERVICE_LIST:
|
||||
if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux))
|
||||
if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux, bq))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bq && bq->bq_saveflag)
|
||||
bouquet_save(bq, 1);
|
||||
|
||||
/* End */
|
||||
return dvb_table_end(mt, st, sect);
|
||||
}
|
||||
|
@ -940,7 +985,7 @@ dvb_sdt_callback
|
|||
int r;
|
||||
s->s_dvb_servicetype = stype;
|
||||
save = 1;
|
||||
tvhtrace("sdt", " type changed");
|
||||
tvhtrace("sdt", " type changed (old %i)", s->s_dvb_servicetype);
|
||||
|
||||
/* Set tvh service type */
|
||||
if ((r = dvb_servicetype_lookup(stype)) != -1)
|
||||
|
@ -1100,6 +1145,144 @@ dvb_bat_callback
|
|||
return dvb_nit_callback(mt, ptr, len, tableid);
|
||||
}
|
||||
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
/*
|
||||
* DVB fastscan table processing
|
||||
*/
|
||||
int
|
||||
dvb_fs_sdt_callback
|
||||
(mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
|
||||
{
|
||||
int r, sect, last, ver;
|
||||
uint8_t dtag;
|
||||
int llen, dlen;
|
||||
const uint8_t *lptr, *dptr;
|
||||
uint16_t nbid = 0, onid, tsid, service_id;
|
||||
mpegts_mux_t *mm = mt->mt_mux, *mux;
|
||||
mpegts_network_t *mn = mm->mm_network;
|
||||
mpegts_table_state_t *st = NULL;
|
||||
bouquet_t *bq = mt->mt_opaque;
|
||||
|
||||
/* Fastscan ID */
|
||||
nbid = (ptr[0] << 8) | ptr[1];
|
||||
|
||||
/* Begin */
|
||||
if (tableid != 0xBD)
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, &st, §, &last, &ver);
|
||||
if (r != 1) return r;
|
||||
if (len < 5) return -1;
|
||||
ptr += 5;
|
||||
len -= 5;
|
||||
|
||||
while (len > 0) {
|
||||
const char *charset;
|
||||
char sprov[256] = "", sname[256] = "";
|
||||
mpegts_service_t *s;
|
||||
int stype = 0, save = 0;
|
||||
|
||||
onid = (ptr[0] << 8) | ptr[1];
|
||||
tsid = (ptr[2] << 8) | ptr[3];
|
||||
service_id = (ptr[4] << 8) | ptr[5];
|
||||
/* (ptr[6] << 8) | ptr[7] - video pid */
|
||||
/* (ptr[7] << 8) | ptr[8] - audio pid */
|
||||
/* (ptr[9] << 8) | ptr[10] - video ecm pid */
|
||||
/* (ptr[10] << 8) | ptr[12] - audio ecm pid */
|
||||
/* (ptr[14] << 8) | ptr[15] - pcr pid */
|
||||
|
||||
tvhdebug(mt->mt_name, " service %04X (%d) onid %04X (%d) tsid %04X (%d)",
|
||||
service_id, service_id, onid, onid, tsid, tsid);
|
||||
|
||||
/* Initialise the loop */
|
||||
DVB_LOOP_INIT(ptr, len, 16, lptr, llen);
|
||||
|
||||
/* Find service */
|
||||
s = mpegts_service_find(mm, service_id, 0, 1, &save);
|
||||
charset = dvb_charset_find(mn, mm, s);
|
||||
if (bq && s)
|
||||
bouquet_add_service(bq, (service_t *)s);
|
||||
|
||||
/* Descriptor loop */
|
||||
DVB_DESC_EACH(lptr, llen, dtag, dlen, dptr) {
|
||||
tvhtrace(mt->mt_name, " dtag %02X dlen %d", dtag, dlen);
|
||||
switch (dtag) {
|
||||
case DVB_DESC_SERVICE:
|
||||
if (dvb_desc_service(dptr, dlen, &stype, sprov,
|
||||
sizeof(sprov), sname, sizeof(sname), charset))
|
||||
return -1;
|
||||
break;
|
||||
case DVB_DESC_LOCAL_CHAN:
|
||||
/* Find existing mux */
|
||||
LIST_FOREACH(mux, &mn->mn_muxes, mm_network_link)
|
||||
if (mux->mm_onid == onid && mux->mm_tsid == tsid)
|
||||
break;
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux, bq))
|
||||
return -1;
|
||||
break;
|
||||
case DVB_DESC_SAT_DEL:
|
||||
mux = dvb_desc_sat_del(mm, onid, tsid, dptr, dlen);
|
||||
if (mux) {
|
||||
mpegts_mux_set_onid(mux, onid);
|
||||
mpegts_mux_set_tsid(mux, tsid, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tvhtrace(mt->mt_name, " type %d name [%s] provider [%s]",
|
||||
stype, sname, sprov);
|
||||
|
||||
/* Update service type */
|
||||
if (stype && !s->s_dvb_servicetype) {
|
||||
int r;
|
||||
s->s_dvb_servicetype = stype;
|
||||
save = 1;
|
||||
tvhtrace(mt->mt_name, " type changed");
|
||||
|
||||
/* Set tvh service type */
|
||||
if ((r = dvb_servicetype_lookup(stype)) != -1)
|
||||
s->s_servicetype = r;
|
||||
}
|
||||
|
||||
/* Update name */
|
||||
if (*sname && strcmp(s->s_dvb_svcname ?: "", sname)) {
|
||||
if (!s->s_dvb_svcname) {
|
||||
tvh_str_update(&s->s_dvb_svcname, sname);
|
||||
save = 1;
|
||||
tvhtrace(mt->mt_name, " name changed");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update provider */
|
||||
if (*sprov && strcmp(s->s_dvb_provider ?: "", sprov)) {
|
||||
if (!s->s_dvb_provider) {
|
||||
tvh_str_update(&s->s_dvb_provider, sprov);
|
||||
save = 1;
|
||||
tvhtrace(mt->mt_name, " provider changed");
|
||||
}
|
||||
}
|
||||
|
||||
if (save) {
|
||||
/* Update nice name */
|
||||
pthread_mutex_lock(&s->s_stream_mutex);
|
||||
service_make_nicename((service_t*)s);
|
||||
pthread_mutex_unlock(&s->s_stream_mutex);
|
||||
tvhdebug(mt->mt_name, " nicename %s", s->s_nicename);
|
||||
/* Save changes */
|
||||
idnode_changed(&s->s_id);
|
||||
service_refresh_channel((service_t*)s);
|
||||
}
|
||||
}
|
||||
|
||||
if (bq && bq->bq_saveflag)
|
||||
bouquet_save(bq, 1);
|
||||
|
||||
/* End */
|
||||
return dvb_table_end(mt, st, sect);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* PMT update reason flags
|
||||
*/
|
||||
|
@ -1589,6 +1772,18 @@ psi_tables_default ( mpegts_mux_t *mm )
|
|||
NULL, "cat", MT_QUICKREQ | MT_CRC, DVB_CAT_PID);
|
||||
}
|
||||
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
static void
|
||||
psi_tables_dvb_fastscan( void *aux, bouquet_t *bq, const char *name, int pid )
|
||||
{
|
||||
tvhtrace("fastscan", "adding table %04X (%i) for '%s'", pid, pid, name);
|
||||
mpegts_table_add(aux, DVB_FASTSCAN_NIT_BASE, DVB_FASTSCAN_MASK,
|
||||
dvb_nit_callback, bq, "fs_nit", MT_CRC, pid);
|
||||
mpegts_table_add(aux, DVB_FASTSCAN_SDT_BASE, DVB_FASTSCAN_MASK,
|
||||
dvb_fs_sdt_callback, bq, "fs_sdt", MT_CRC, pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
psi_tables_dvb ( mpegts_mux_t *mm )
|
||||
{
|
||||
|
@ -1599,6 +1794,17 @@ psi_tables_dvb ( mpegts_mux_t *mm )
|
|||
DVB_SDT_PID);
|
||||
mpegts_table_add(mm, DVB_BAT_BASE, DVB_BAT_MASK, dvb_bat_callback,
|
||||
NULL, "bat", MT_CRC, DVB_BAT_PID);
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
if (idnode_is_instance(&mm->mm_id, &dvb_mux_dvbs_class)) {
|
||||
dvb_mux_conf_t *mc = &((dvb_mux_t *)mm)->lm_tuning;
|
||||
if (mc->dmc_fe_type == DVB_TYPE_S) {
|
||||
int pos = mc->u.dmc_fe_qpsk.orbital_pos;
|
||||
if (mc->u.dmc_fe_qpsk.orbital_dir == 'W')
|
||||
pos = -pos;
|
||||
dvb_fastscan_each(mm, pos, mc->dmc_fe_freq, psi_tables_dvb_fastscan);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -382,7 +382,7 @@ mpegts_network_set_network_name
|
|||
{
|
||||
char buf[256];
|
||||
if (mn->mn_network_name) return 0;
|
||||
if (!name || !strcmp(name, mn->mn_network_name ?: ""))
|
||||
if (!name || name[0] == '\0' || !strcmp(name, mn->mn_network_name ?: ""))
|
||||
return 0;
|
||||
tvh_str_update(&mn->mn_network_name, name);
|
||||
mn->mn_display_name(mn, buf, sizeof(buf));
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include "libav.h"
|
||||
#endif
|
||||
#include "profile.h"
|
||||
#include "bouquet.h"
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <sys/prctl.h>
|
||||
|
@ -813,6 +814,8 @@ main(int argc, char **argv)
|
|||
http_client_init(opt_user_agent);
|
||||
esfilter_init();
|
||||
|
||||
bouquet_init();
|
||||
|
||||
service_init();
|
||||
|
||||
#if ENABLE_MPEGTS
|
||||
|
@ -821,6 +824,8 @@ main(int argc, char **argv)
|
|||
|
||||
channel_init();
|
||||
|
||||
bouquet_service_resolve();
|
||||
|
||||
subscription_init();
|
||||
|
||||
dvr_config_init();
|
||||
|
@ -917,6 +922,7 @@ main(int argc, char **argv)
|
|||
tvhftrace("main", service_mapper_done);
|
||||
tvhftrace("main", service_done);
|
||||
tvhftrace("main", channel_done);
|
||||
tvhftrace("main", bouquet_done);
|
||||
tvhftrace("main", dvr_done);
|
||||
tvhftrace("main", subscription_done);
|
||||
tvhftrace("main", access_done);
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "input.h"
|
||||
#include "access.h"
|
||||
#include "esfilter.h"
|
||||
#include "bouquet.h"
|
||||
|
||||
static void service_data_timeout(void *aux);
|
||||
static void service_class_delete(struct idnode *self);
|
||||
|
@ -799,6 +800,8 @@ service_destroy(service_t *t, int delconf)
|
|||
|
||||
t->s_status = SERVICE_ZOMBIE;
|
||||
|
||||
bouquet_destroy_by_service(t);
|
||||
|
||||
TAILQ_INIT(&t->s_filt_components);
|
||||
while((st = TAILQ_FIRST(&t->s_components)) != NULL)
|
||||
service_stream_destroy(t, st);
|
||||
|
|
|
@ -443,6 +443,11 @@ typedef struct service {
|
|||
|
||||
int64_t s_current_pts;
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void *s_master_bouquet;
|
||||
|
||||
} service_t;
|
||||
|
||||
|
||||
|
|
|
@ -6,10 +6,9 @@ tvheadend.cteditor = function(panel, index)
|
|||
{
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url: 'api/channeltag',
|
||||
comet: 'channeltag',
|
||||
titleS: 'Channel Tag',
|
||||
titleP: 'Channel Tags',
|
||||
iconCls: 'channelTags',
|
||||
iconCls: 'channelTags',
|
||||
tabIndex: index,
|
||||
add: {
|
||||
url: 'api/channeltag',
|
||||
|
@ -27,3 +26,31 @@ tvheadend.cteditor = function(panel, index)
|
|||
|
||||
return panel;
|
||||
};
|
||||
|
||||
/*
|
||||
* Bouquet
|
||||
*/
|
||||
tvheadend.bouquet = function(panel, index)
|
||||
{
|
||||
var list = 'enabled,name,source,services_count,comment,lcn_off';
|
||||
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url: 'api/bouquet',
|
||||
titleS: 'Bouquet',
|
||||
titleP: 'Bouquets',
|
||||
iconCls: 'bouquets',
|
||||
tabIndex: index,
|
||||
list: list,
|
||||
del: true,
|
||||
edit: { params: { list: list } },
|
||||
sort: {
|
||||
field: 'name',
|
||||
direction: 'ASC'
|
||||
},
|
||||
help: function() {
|
||||
new tvheadend.help('Bouquets', 'config_bouquet.html');
|
||||
},
|
||||
});
|
||||
|
||||
return panel;
|
||||
};
|
||||
|
|
|
@ -366,6 +366,7 @@ function accessUpdate(o) {
|
|||
});
|
||||
tvheadend.channel_tab(chepg);
|
||||
tvheadend.cteditor(chepg);
|
||||
tvheadend.bouquet(chepg);
|
||||
tvheadend.epggrab(chepg);
|
||||
|
||||
cp.add(chepg);
|
||||
|
|
Loading…
Add table
Reference in a new issue