Merge remote-tracking branch 'origin/pr/329'
Conflicts: src/tvheadend.h
This commit is contained in:
commit
ae2ba4b6cd
93 changed files with 1270 additions and 292 deletions
11
src/access.c
11
src/access.c
|
@ -520,6 +520,7 @@ access_entry_destroy(access_entry_t *ae)
|
|||
free(ae->ae_id);
|
||||
free(ae->ae_username);
|
||||
free(ae->ae_password);
|
||||
free(ae->ae_comment);
|
||||
TAILQ_REMOVE(&access_entries, ae, ae_link);
|
||||
free(ae);
|
||||
}
|
||||
|
@ -769,3 +770,13 @@ access_init(int createdefault, int noacl)
|
|||
htsmsg_destroy(m);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
access_done(void)
|
||||
{
|
||||
access_entry_t *ae;
|
||||
|
||||
dtable_delete("accesscontrol");
|
||||
while ((ae = TAILQ_FIRST(&access_entries)) != NULL)
|
||||
access_entry_destroy(ae);
|
||||
}
|
||||
|
|
|
@ -111,5 +111,6 @@ uint32_t access_get_by_addr(struct sockaddr *src);
|
|||
*
|
||||
*/
|
||||
void access_init(int createdefault, int noacl);
|
||||
void access_done(void);
|
||||
|
||||
#endif /* ACCESS_H_ */
|
||||
|
|
28
src/api.c
28
src/api.c
|
@ -29,6 +29,7 @@ typedef struct api_link {
|
|||
} api_link_t;
|
||||
|
||||
RB_HEAD(,api_link) api_hook_tree;
|
||||
SKEL_DECLARE(api_skel, api_link_t);
|
||||
|
||||
static int ah_cmp
|
||||
( api_link_t *a, api_link_t *b )
|
||||
|
@ -39,15 +40,15 @@ static int ah_cmp
|
|||
void
|
||||
api_register ( const api_hook_t *hook )
|
||||
{
|
||||
static api_link_t *t, *skel = NULL;
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(api_link_t));
|
||||
skel->hook = hook;
|
||||
t = RB_INSERT_SORTED(&api_hook_tree, skel, link, ah_cmp);
|
||||
if (t)
|
||||
api_link_t *t;
|
||||
SKEL_ALLOC(api_skel);
|
||||
api_skel->hook = hook;
|
||||
t = RB_INSERT_SORTED(&api_hook_tree, api_skel, link, ah_cmp);
|
||||
if (t) {
|
||||
tvherror("api", "trying to re-register subsystem");
|
||||
else
|
||||
skel = NULL;
|
||||
} else {
|
||||
SKEL_USED(api_skel);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -125,3 +126,14 @@ void api_init ( void )
|
|||
api_status_init();
|
||||
api_imagecache_init();
|
||||
}
|
||||
|
||||
void api_done ( void )
|
||||
{
|
||||
api_link_t *t;
|
||||
|
||||
while ((t = RB_FIRST(&api_hook_tree)) != NULL) {
|
||||
RB_REMOVE(&api_hook_tree, t, link);
|
||||
free(t);
|
||||
}
|
||||
SKEL_FREE(api_skel);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ int api_exec ( const char *subsystem, htsmsg_t *args, htsmsg_t **resp );
|
|||
* Initialise
|
||||
*/
|
||||
void api_init ( void );
|
||||
void api_done ( void );
|
||||
void api_idnode_init ( void );
|
||||
void api_input_init ( void );
|
||||
void api_service_init ( void );
|
||||
|
|
|
@ -170,6 +170,8 @@ api_idnode_load_by_class
|
|||
if (e)
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
free(is->is_array);
|
||||
free(is);
|
||||
}
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
|
|
22
src/avahi.c
22
src/avahi.c
|
@ -39,6 +39,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
|
@ -54,6 +55,7 @@
|
|||
|
||||
static AvahiEntryGroup *group = NULL;
|
||||
static char *name = NULL;
|
||||
static AvahiSimplePoll *avahi_asp = NULL;
|
||||
|
||||
static void create_services(AvahiClient *c);
|
||||
|
||||
|
@ -247,14 +249,13 @@ client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
|
|||
static void *
|
||||
avahi_thread(void *aux)
|
||||
{
|
||||
AvahiSimplePoll *asp = avahi_simple_poll_new();
|
||||
const AvahiPoll *ap = avahi_simple_poll_get(asp);
|
||||
const AvahiPoll *ap = avahi_simple_poll_get(avahi_asp);
|
||||
|
||||
name = avahi_strdup("Tvheadend");
|
||||
|
||||
avahi_client_new(ap, AVAHI_CLIENT_NO_FAIL, client_callback, NULL, NULL);
|
||||
|
||||
while((avahi_simple_poll_iterate(asp, -1)) != -1) {}
|
||||
while(avahi_simple_poll_iterate(avahi_asp, -1) == 0);
|
||||
|
||||
return NULL;
|
||||
|
||||
|
@ -264,10 +265,19 @@ avahi_thread(void *aux)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
pthread_t avahi_tid;
|
||||
|
||||
void
|
||||
avahi_init(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
tvhthread_create(&tid, NULL, avahi_thread, NULL, 1);
|
||||
avahi_asp = avahi_simple_poll_new();
|
||||
tvhthread_create(&avahi_tid, NULL, avahi_thread, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
avahi_done(void)
|
||||
{
|
||||
avahi_simple_poll_quit(avahi_asp);
|
||||
pthread_kill(avahi_tid, SIGTERM);
|
||||
pthread_join(avahi_tid, NULL);
|
||||
}
|
||||
|
|
|
@ -1 +1,7 @@
|
|||
#ifdef CONFIG_AVAHI
|
||||
void avahi_init(void);
|
||||
void avahi_done(void);
|
||||
#else
|
||||
static inline void avahi_init(void) { }
|
||||
static inline void avahi_done(void) { }
|
||||
#endif
|
||||
|
|
|
@ -48,9 +48,12 @@ struct channel_tag_queue channel_tags;
|
|||
static dtable_t *channeltags_dtable;
|
||||
|
||||
static void channel_tag_init ( void );
|
||||
static void channel_tag_done ( void );
|
||||
static channel_tag_t *channel_tag_find(const char *id, int create);
|
||||
static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm,
|
||||
int flags);
|
||||
static void channel_tag_destroy(channel_tag_t *ct, int delconf);
|
||||
|
||||
|
||||
#define CTM_DESTROY_UPDATE_TAG 0x1
|
||||
#define CTM_DESTROY_UPDATE_CHANNEL 0x2
|
||||
|
@ -74,7 +77,7 @@ channel_class_save ( idnode_t *self )
|
|||
static void
|
||||
channel_class_delete ( idnode_t *self )
|
||||
{
|
||||
channel_delete((channel_t*)self);
|
||||
channel_delete((channel_t*)self, 1);
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
@ -543,7 +546,7 @@ channel_create0
|
|||
}
|
||||
|
||||
void
|
||||
channel_delete ( channel_t *ch )
|
||||
channel_delete ( channel_t *ch, int delconf )
|
||||
{
|
||||
th_subscription_t *s;
|
||||
channel_tag_mapping_t *ctm;
|
||||
|
@ -551,14 +554,15 @@ channel_delete ( channel_t *ch )
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhinfo("channel", "%s - deleting", channel_get_name(ch));
|
||||
if (delconf)
|
||||
tvhinfo("channel", "%s - deleting", channel_get_name(ch));
|
||||
|
||||
/* Tags */
|
||||
while((ctm = LIST_FIRST(&ch->ch_ctms)) != NULL)
|
||||
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_TAG);
|
||||
|
||||
/* DVR */
|
||||
autorec_destroy_by_channel(ch);
|
||||
autorec_destroy_by_channel(ch, delconf);
|
||||
dvr_destroy_by_channel(ch);
|
||||
|
||||
/* Services */
|
||||
|
@ -579,7 +583,8 @@ channel_delete ( channel_t *ch )
|
|||
htsp_channel_delete(ch);
|
||||
|
||||
/* Settings */
|
||||
hts_settings_remove("channel/%s", idnode_uuid_as_str(&ch->ch_id));
|
||||
if (delconf)
|
||||
hts_settings_remove("channel/%s", idnode_uuid_as_str(&ch->ch_id));
|
||||
|
||||
/* Free memory */
|
||||
RB_REMOVE(&channels, ch, ch_link);
|
||||
|
@ -625,6 +630,21 @@ channel_init ( void )
|
|||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
channel_done ( void )
|
||||
{
|
||||
channel_t *ch;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((ch = RB_FIRST(&channels)) != NULL)
|
||||
channel_delete(ch, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
channel_tag_done();
|
||||
}
|
||||
|
||||
/* ***
|
||||
* Channel tags TODO
|
||||
*/
|
||||
|
@ -738,15 +758,17 @@ channel_tag_find(const char *id, int create)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
channel_tag_destroy(channel_tag_t *ct)
|
||||
channel_tag_destroy(channel_tag_t *ct, int delconf)
|
||||
{
|
||||
channel_tag_mapping_t *ctm;
|
||||
channel_t *ch;
|
||||
|
||||
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
|
||||
ch = ctm->ctm_channel;
|
||||
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_CHANNEL);
|
||||
channel_save(ch);
|
||||
if (delconf) {
|
||||
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
|
||||
ch = ctm->ctm_channel;
|
||||
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_CHANNEL);
|
||||
channel_save(ch);
|
||||
}
|
||||
}
|
||||
|
||||
if(ct->ct_enabled && !ct->ct_internal)
|
||||
|
@ -884,7 +906,7 @@ channel_tag_record_delete(void *opaque, const char *id)
|
|||
|
||||
if((ct = channel_tag_find(id, 0)) == NULL)
|
||||
return -1;
|
||||
channel_tag_destroy(ct);
|
||||
channel_tag_destroy(ct, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -955,3 +977,15 @@ channel_tag_init ( void )
|
|||
channeltags_dtable = dtable_create(&channel_tags_dtc, "channeltags", NULL);
|
||||
dtable_load(channeltags_dtable);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_tag_done ( void )
|
||||
{
|
||||
channel_tag_t *ct;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((ct = TAILQ_FIRST(&channel_tags)) != NULL)
|
||||
channel_tag_destroy(ct, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
dtable_delete("channeltags");
|
||||
}
|
||||
|
|
|
@ -120,6 +120,7 @@ typedef struct channel_service_mapping {
|
|||
extern const idclass_t channel_class;
|
||||
|
||||
void channel_init(void);
|
||||
void channel_done(void);
|
||||
|
||||
channel_t *channel_create0
|
||||
(channel_t *ch, const idclass_t *idc, const char *uuid, htsmsg_t *conf,
|
||||
|
@ -127,7 +128,7 @@ channel_t *channel_create0
|
|||
#define channel_create(u, c, n)\
|
||||
channel_create0(calloc(1, sizeof(channel_t)), &channel_class, u, c, n)
|
||||
|
||||
void channel_delete(channel_t *ch);
|
||||
void channel_delete(channel_t *ch, int delconf);
|
||||
|
||||
channel_t *channel_find_by_name(const char *name);
|
||||
#define channel_find_by_uuid(u)\
|
||||
|
|
|
@ -33,6 +33,11 @@ void config_init ( void )
|
|||
}
|
||||
}
|
||||
|
||||
void config_done ( void )
|
||||
{
|
||||
htsmsg_destroy(config);
|
||||
}
|
||||
|
||||
void config_save ( void )
|
||||
{
|
||||
hts_settings_save(config, "config");
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "htsmsg.h"
|
||||
|
||||
void config_init ( void );
|
||||
void config_done ( void );
|
||||
void config_save ( void );
|
||||
|
||||
htsmsg_t *config_get_all ( void );
|
||||
|
|
|
@ -77,6 +77,7 @@ typedef enum {
|
|||
LIST_HEAD(caid_list, caid);
|
||||
|
||||
void descrambler_init ( void );
|
||||
void descrambler_done ( void );
|
||||
void descrambler_service_start ( struct service *t );
|
||||
const char *descrambler_caid2name(uint16_t caid);
|
||||
uint16_t descrambler_name2caid(const char *str);
|
||||
|
|
|
@ -184,6 +184,8 @@ typedef struct capmt {
|
|||
|
||||
struct capmt_service_list capmt_services;
|
||||
|
||||
pthread_t capmt_tid;
|
||||
|
||||
/* from capmt configuration */
|
||||
char *capmt_sockfile;
|
||||
char *capmt_hostname;
|
||||
|
@ -1113,7 +1115,6 @@ capmt_destroy(capmt_t *capmt)
|
|||
static capmt_t *
|
||||
capmt_entry_find(const char *id, int create)
|
||||
{
|
||||
pthread_t ptid;
|
||||
char buf[20];
|
||||
capmt_t *capmt;
|
||||
static int tally;
|
||||
|
@ -1142,7 +1143,7 @@ capmt_entry_find(const char *id, int create)
|
|||
|
||||
TAILQ_INSERT_TAIL(&capmts, capmt, capmt_link);
|
||||
|
||||
tvhthread_create(&ptid, NULL, capmt_thread, capmt, 1);
|
||||
tvhthread_create(&capmt->capmt_tid, NULL, capmt_thread, capmt, 1);
|
||||
|
||||
return capmt;
|
||||
}
|
||||
|
@ -1280,3 +1281,19 @@ capmt_init(void)
|
|||
dtable_load(dt);
|
||||
}
|
||||
|
||||
void
|
||||
capmt_done(void)
|
||||
{
|
||||
capmt_t *capmt, *n;
|
||||
pthread_t tid;
|
||||
|
||||
for (capmt = TAILQ_FIRST(&capmts); capmt != NULL; capmt = n) {
|
||||
n = TAILQ_NEXT(capmt, capmt_link);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
tid = capmt->capmt_tid;
|
||||
capmt_destroy(capmt);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
pthread_join(tid, NULL);
|
||||
}
|
||||
dtable_delete("capmt");
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
void capmt_init(void);
|
||||
|
||||
void capmt_done(void);
|
||||
|
||||
void capmt_service_start(struct service *t);
|
||||
|
||||
#endif /* CAPMT_H_ */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <openssl/des.h>
|
||||
|
@ -184,9 +185,9 @@ typedef struct cwc_provider {
|
|||
typedef struct cs_card_data {
|
||||
|
||||
LIST_ENTRY(cs_card_data) cs_card;
|
||||
|
||||
|
||||
/* Card caid */
|
||||
uint16_t cwc_caid;
|
||||
uint16_t cwc_caid;
|
||||
|
||||
/* Card type */
|
||||
card_type_t cwc_card_type;
|
||||
|
@ -210,6 +211,8 @@ typedef struct cwc {
|
|||
|
||||
int cwc_retry_delay;
|
||||
|
||||
pthread_t cwc_tid;
|
||||
|
||||
pthread_cond_t cwc_cond;
|
||||
|
||||
pthread_mutex_t cwc_writer_mutex;
|
||||
|
@ -465,8 +468,7 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid, int enq, uint1
|
|||
|
||||
int seq = atomic_add(&cwc->cwc_seq, 1);
|
||||
|
||||
memset(buf, 0, 12);
|
||||
|
||||
buf[0] = buf[1] = 0;
|
||||
buf[2] = (seq >> 8) & 0xff;
|
||||
buf[3] = seq & 0xff;
|
||||
buf[4] = (sid >> 8) & 0xff;
|
||||
|
@ -488,7 +490,7 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid, int enq, uint1
|
|||
}
|
||||
|
||||
tvhtrace("cwc", "sending message sid %d len %"PRIsize_t" enq %d", sid, len, enq);
|
||||
tvhlog_hexdump("cwc", msg, len);
|
||||
tvhlog_hexdump("cwc", buf, len);
|
||||
|
||||
buf[0] = (len - 2) >> 8;
|
||||
buf[1] = (len - 2) & 0xff;
|
||||
|
@ -1194,6 +1196,7 @@ cwc_thread(void *aux)
|
|||
cwc->cwc_hostname, cwc->cwc_port);
|
||||
}
|
||||
|
||||
if(cwc->cwc_running == 0) continue;
|
||||
if(attempts == 1) continue; // Retry immediately
|
||||
d = 3;
|
||||
|
||||
|
@ -1224,6 +1227,7 @@ cwc_thread(void *aux)
|
|||
free((void *)cwc->cwc_password);
|
||||
free((void *)cwc->cwc_password_salted);
|
||||
free((void *)cwc->cwc_username);
|
||||
free((void *)cwc->cwc_comment);
|
||||
free((void *)cwc->cwc_hostname);
|
||||
free((void *)cwc->cwc_id);
|
||||
free((void *)cwc->cwc_viaccess_emm.shared_emm);
|
||||
|
@ -2066,7 +2070,6 @@ cwc_destroy(cwc_t *cwc)
|
|||
static cwc_t *
|
||||
cwc_entry_find(const char *id, int create)
|
||||
{
|
||||
pthread_t ptid;
|
||||
char buf[20];
|
||||
cwc_t *cwc;
|
||||
static int tally;
|
||||
|
@ -2094,7 +2097,7 @@ cwc_entry_find(const char *id, int create)
|
|||
cwc->cwc_running = 1;
|
||||
TAILQ_INSERT_TAIL(&cwcs, cwc, cwc_link);
|
||||
|
||||
tvhthread_create(&ptid, NULL, cwc_thread, cwc, 1);
|
||||
tvhthread_create(&cwc->cwc_tid, NULL, cwc_thread, cwc, 0);
|
||||
|
||||
return cwc;
|
||||
}
|
||||
|
@ -2337,6 +2340,29 @@ cwc_init(void)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
cwc_done(void)
|
||||
{
|
||||
cwc_t *cwc;
|
||||
pthread_t tid;
|
||||
|
||||
dtable_delete("cwc");
|
||||
pthread_mutex_lock(&cwc_mutex);
|
||||
while ((cwc = TAILQ_FIRST(&cwcs)) != NULL) {
|
||||
tid = cwc->cwc_tid;
|
||||
cwc_destroy(cwc);
|
||||
pthread_mutex_unlock(&cwc_mutex);
|
||||
pthread_kill(tid, SIGTERM);
|
||||
pthread_join(tid, NULL);
|
||||
pthread_mutex_lock(&cwc_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&cwc_mutex);
|
||||
}
|
||||
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
/*
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
void cwc_init(void);
|
||||
|
||||
void cwc_done(void);
|
||||
|
||||
void cwc_service_start(struct service *t);
|
||||
|
||||
void cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id);
|
||||
|
|
|
@ -115,6 +115,13 @@ descrambler_init ( void )
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
descrambler_done ( void )
|
||||
{
|
||||
capmt_done();
|
||||
cwc_done();
|
||||
}
|
||||
|
||||
void
|
||||
descrambler_service_start ( service_t *t )
|
||||
{
|
||||
|
|
17
src/dtable.c
17
src/dtable.c
|
@ -63,6 +63,23 @@ dtable_create(const dtable_class_t *dtc, const char *name, void *opaque)
|
|||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dtable_delete(const char *name)
|
||||
{
|
||||
dtable_t *dt = dtable_find(name);
|
||||
|
||||
if (dt) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_REMOVE(dt, dt_link);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
free(dt->dt_tablename);
|
||||
free(dt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -58,6 +58,8 @@ typedef struct dtable {
|
|||
dtable_t *dtable_create(const dtable_class_t *dtc, const char *name,
|
||||
void *opaque);
|
||||
|
||||
void dtable_delete(const char *name);
|
||||
|
||||
int dtable_load(dtable_t *dt);
|
||||
|
||||
dtable_t *dtable_find(const char *name);
|
||||
|
|
|
@ -296,8 +296,12 @@ dvr_entry_t *dvr_entry_update
|
|||
|
||||
void dvr_init(void);
|
||||
|
||||
void dvr_done(void);
|
||||
|
||||
void dvr_autorec_init(void);
|
||||
|
||||
void dvr_autorec_done(void);
|
||||
|
||||
void dvr_autorec_update(void);
|
||||
|
||||
void dvr_destroy_by_channel(channel_t *ch);
|
||||
|
@ -384,7 +388,7 @@ void dvr_autorec_check_season(epg_season_t *s);
|
|||
void dvr_autorec_check_serieslink(epg_serieslink_t *s);
|
||||
|
||||
|
||||
void autorec_destroy_by_channel(channel_t *ch);
|
||||
void autorec_destroy_by_channel(channel_t *ch, int delconf);
|
||||
|
||||
dvr_autorec_entry_t *autorec_entry_find(const char *id, int create);
|
||||
|
||||
|
@ -399,6 +403,7 @@ const char *dvr_val2pri(dvr_prio_t v);
|
|||
* Inotify support
|
||||
*/
|
||||
void dvr_inotify_init ( void );
|
||||
void dvr_inotify_done ( void );
|
||||
void dvr_inotify_add ( dvr_entry_t *de );
|
||||
void dvr_inotify_del ( dvr_entry_t *de );
|
||||
|
||||
|
|
|
@ -480,6 +480,20 @@ dvr_autorec_init(void)
|
|||
dvr_autorec_in_init = 0;
|
||||
}
|
||||
|
||||
void
|
||||
dvr_autorec_done(void)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((dae = TAILQ_FIRST(&autorec_entries)) != NULL) {
|
||||
TAILQ_REMOVE(&autorec_entries, dae, dae_link);
|
||||
free(dae);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
dtable_delete("autorec");
|
||||
}
|
||||
|
||||
void
|
||||
dvr_autorec_update(void)
|
||||
{
|
||||
|
@ -638,13 +652,14 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
|
|||
*
|
||||
*/
|
||||
void
|
||||
autorec_destroy_by_channel(channel_t *ch)
|
||||
autorec_destroy_by_channel(channel_t *ch, int delconf)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
htsmsg_t *m;
|
||||
|
||||
while((dae = LIST_FIRST(&ch->ch_autorecs)) != NULL) {
|
||||
dtable_record_erase(autorec_dt, dae->dae_id);
|
||||
if (delconf)
|
||||
dtable_record_erase(autorec_dt, dae->dae_id);
|
||||
autorec_entry_destroy(dae);
|
||||
}
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ dvr_entry_dec_ref(dvr_entry_t *de)
|
|||
if(de->de_autorec != NULL)
|
||||
LIST_REMOVE(de, de_autorec_link);
|
||||
|
||||
free(de->de_filename);
|
||||
free(de->de_config_name);
|
||||
free(de->de_creator);
|
||||
if (de->de_title) lang_str_destroy(de->de_title);
|
||||
|
@ -506,9 +507,10 @@ dvr_entry_dec_ref(dvr_entry_t *de)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
dvr_entry_remove(dvr_entry_t *de)
|
||||
dvr_entry_remove(dvr_entry_t *de, int delconf)
|
||||
{
|
||||
hts_settings_remove("dvr/log/%d", de->de_id);
|
||||
if (delconf)
|
||||
hts_settings_remove("dvr/log/%d", de->de_id);
|
||||
|
||||
htsp_dvr_entry_delete(de);
|
||||
|
||||
|
@ -523,6 +525,7 @@ dvr_entry_remove(dvr_entry_t *de)
|
|||
LIST_REMOVE(de, de_global_link);
|
||||
de->de_channel = NULL;
|
||||
free(de->de_channel_name);
|
||||
de->de_channel_name = NULL;
|
||||
|
||||
dvrdb_changed();
|
||||
|
||||
|
@ -729,7 +732,7 @@ static void
|
|||
dvr_timer_expire(void *aux)
|
||||
{
|
||||
dvr_entry_t *de = aux;
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -857,7 +860,7 @@ dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e)
|
|||
|
||||
/* If this was craeted by autorec - just remove it, it'll get recreated */
|
||||
if (de->de_autorec) {
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
|
||||
/* Find match */
|
||||
} else {
|
||||
|
@ -1025,7 +1028,7 @@ dvr_entry_cancel(dvr_entry_t *de)
|
|||
{
|
||||
switch(de->de_sched_state) {
|
||||
case DVR_SCHEDULED:
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
return NULL;
|
||||
|
||||
case DVR_RECORDING:
|
||||
|
@ -1034,11 +1037,11 @@ dvr_entry_cancel(dvr_entry_t *de)
|
|||
return de;
|
||||
|
||||
case DVR_COMPLETED:
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
return NULL;
|
||||
|
||||
case DVR_MISSED_TIME:
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
return NULL;
|
||||
|
||||
default:
|
||||
|
@ -1208,6 +1211,31 @@ dvr_init(void)
|
|||
dvr_autorec_update();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
dvr_done(void)
|
||||
{
|
||||
dvr_config_t *cfg;
|
||||
dvr_entry_t *de;
|
||||
|
||||
#if ENABLE_INOTIFY
|
||||
dvr_inotify_done();
|
||||
#endif
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((cfg = LIST_FIRST(&dvrconfigs)) != NULL) {
|
||||
LIST_REMOVE(cfg, config_link);
|
||||
free(cfg->dvr_storage);
|
||||
free(cfg->dvr_config_name);
|
||||
free(cfg);
|
||||
}
|
||||
while ((de = LIST_FIRST(&dvrentries)) != NULL)
|
||||
dvr_entry_remove(de, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
dvr_autorec_done();
|
||||
}
|
||||
|
||||
/**
|
||||
* find a dvr config by name, return NULL if not found
|
||||
*/
|
||||
|
@ -1306,6 +1334,7 @@ dvr_config_delete(const char *name)
|
|||
cfg->dvr_config_name);
|
||||
hts_settings_remove("dvr/config%s", cfg->dvr_config_name);
|
||||
LIST_REMOVE(cfg, config_link);
|
||||
free(cfg->dvr_config_name);
|
||||
free(cfg);
|
||||
|
||||
dvrconfig_changed();
|
||||
|
@ -1647,7 +1676,7 @@ dvr_entry_delete(dvr_entry_t *de)
|
|||
}
|
||||
|
||||
}
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1658,7 +1687,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
|
|||
{
|
||||
switch(de->de_sched_state) {
|
||||
case DVR_SCHEDULED:
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
break;
|
||||
|
||||
case DVR_RECORDING:
|
||||
|
@ -1669,7 +1698,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
|
|||
break;
|
||||
|
||||
case DVR_MISSED_TIME:
|
||||
dvr_entry_remove(de);
|
||||
dvr_entry_remove(de, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
@ -45,6 +47,8 @@ typedef struct dvr_inotify_entry
|
|||
struct dvr_entry_list entries;
|
||||
} dvr_inotify_entry_t;
|
||||
|
||||
static SKEL_DECLARE(dvr_inotify_entry_skel, dvr_inotify_entry_t);
|
||||
|
||||
static void* _dvr_inotify_thread ( void *p );
|
||||
|
||||
static int _str_cmp ( void *a, void *b )
|
||||
|
@ -55,10 +59,10 @@ static int _str_cmp ( void *a, void *b )
|
|||
/**
|
||||
* Initialise threads
|
||||
*/
|
||||
pthread_t dvr_inotify_tid;
|
||||
|
||||
void dvr_inotify_init ( void )
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
_inot_fd = inotify_init();
|
||||
if (_inot_fd == -1) {
|
||||
tvhlog(LOG_ERR, "dvr", "failed to initialise inotify (err=%s)",
|
||||
|
@ -66,7 +70,20 @@ void dvr_inotify_init ( void )
|
|||
return;
|
||||
}
|
||||
|
||||
tvhthread_create(&tid, NULL, _dvr_inotify_thread, NULL, 1);
|
||||
tvhthread_create(&dvr_inotify_tid, NULL, _dvr_inotify_thread, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void dvr_inotify_done ( void )
|
||||
{
|
||||
int fd = _inot_fd;
|
||||
_inot_fd = -1;
|
||||
close(fd);
|
||||
pthread_kill(dvr_inotify_tid, SIGTERM);
|
||||
pthread_join(dvr_inotify_tid, NULL);
|
||||
SKEL_FREE(dvr_inotify_entry_skel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +91,6 @@ void dvr_inotify_init ( void )
|
|||
*/
|
||||
void dvr_inotify_add ( dvr_entry_t *de )
|
||||
{
|
||||
static dvr_inotify_entry_t *skel = NULL;
|
||||
dvr_inotify_entry_t *e;
|
||||
char *path;
|
||||
struct stat st;
|
||||
|
@ -87,17 +103,16 @@ void dvr_inotify_add ( dvr_entry_t *de )
|
|||
|
||||
path = strdup(de->de_filename);
|
||||
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(dvr_inotify_entry_t));
|
||||
skel->path = dirname(path);
|
||||
SKEL_ALLOC(dvr_inotify_entry_skel);
|
||||
dvr_inotify_entry_skel->path = dirname(path);
|
||||
|
||||
if (stat(skel->path, &st))
|
||||
if (stat(dvr_inotify_entry_skel->path, &st))
|
||||
return;
|
||||
|
||||
e = RB_INSERT_SORTED(&_inot_tree, skel, link, _str_cmp);
|
||||
e = RB_INSERT_SORTED(&_inot_tree, dvr_inotify_entry_skel, link, _str_cmp);
|
||||
if (!e) {
|
||||
e = skel;
|
||||
skel = NULL;
|
||||
e = dvr_inotify_entry_skel;
|
||||
SKEL_USED(dvr_inotify_entry_skel);
|
||||
e->path = strdup(e->path);
|
||||
e->fd = inotify_add_watch(_inot_fd, e->path, EVENT_MASK);
|
||||
if (e->fd == -1) {
|
||||
|
@ -258,6 +273,8 @@ void* _dvr_inotify_thread ( void *p )
|
|||
from = NULL;
|
||||
i = 0;
|
||||
len = read(_inot_fd, buf, EVENT_BUF_LEN);
|
||||
if (_inot_fd < 0)
|
||||
break;
|
||||
|
||||
/* Process */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
|
15
src/epg.c
15
src/epg.c
|
@ -2314,3 +2314,18 @@ char *epg_hash ( const char *t, const char *s, const char *d )
|
|||
if ( t ) return md5sum(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void epg_skel_done(void)
|
||||
{
|
||||
epg_object_t **skel;
|
||||
epg_broadcast_t **broad;
|
||||
|
||||
skel = _epg_brand_skel();
|
||||
free(*skel); *skel = NULL;
|
||||
skel = _epg_season_skel();
|
||||
free(*skel); *skel = NULL;
|
||||
skel = _epg_episode_skel();
|
||||
free(*skel); *skel = NULL;
|
||||
broad = _epg_broadcast_skel();
|
||||
free(*broad); *broad = NULL;
|
||||
}
|
||||
|
|
|
@ -556,7 +556,10 @@ void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
|
|||
* ***********************************************************************/
|
||||
|
||||
void epg_init (void);
|
||||
void epg_save (void*);
|
||||
void epg_done (void);
|
||||
void epg_skel_done (void);
|
||||
void epg_save (void);
|
||||
void epg_save_callback (void *p);
|
||||
void epg_updated (void);
|
||||
|
||||
/* ************************************************************************
|
||||
|
|
45
src/epgdb.c
45
src/epgdb.c
|
@ -100,40 +100,40 @@ static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
|
|||
/*
|
||||
* Process v2 data
|
||||
*/
|
||||
static void _epgdb_v2_process ( htsmsg_t *m, epggrab_stats_t *stats )
|
||||
static void
|
||||
_epgdb_v2_process( char **sect, htsmsg_t *m, epggrab_stats_t *stats )
|
||||
{
|
||||
int save = 0;
|
||||
const char *s;
|
||||
static char *sect;
|
||||
|
||||
/* New section */
|
||||
if ( (s = htsmsg_get_str(m, "__section__")) ) {
|
||||
if (sect) free(sect);
|
||||
sect = strdup(s);
|
||||
if (*sect) free(*sect);
|
||||
*sect = strdup(s);
|
||||
|
||||
/* Brand */
|
||||
} else if ( !strcmp(sect, "brands") ) {
|
||||
} else if ( !strcmp(*sect, "brands") ) {
|
||||
if (epg_brand_deserialize(m, 1, &save)) stats->brands.total++;
|
||||
|
||||
/* Season */
|
||||
} else if ( !strcmp(sect, "seasons") ) {
|
||||
} else if ( !strcmp(*sect, "seasons") ) {
|
||||
if (epg_season_deserialize(m, 1, &save)) stats->seasons.total++;
|
||||
|
||||
/* Episode */
|
||||
} else if ( !strcmp(sect, "episodes") ) {
|
||||
} else if ( !strcmp(*sect, "episodes") ) {
|
||||
if (epg_episode_deserialize(m, 1, &save)) stats->episodes.total++;
|
||||
|
||||
/* Series link */
|
||||
} else if ( !strcmp(sect, "serieslinks") ) {
|
||||
} else if ( !strcmp(*sect, "serieslinks") ) {
|
||||
if (epg_serieslink_deserialize(m, 1, &save)) stats->seasons.total++;
|
||||
|
||||
/* Broadcasts */
|
||||
} else if ( !strcmp(sect, "broadcasts") ) {
|
||||
} else if ( !strcmp(*sect, "broadcasts") ) {
|
||||
if (epg_broadcast_deserialize(m, 1, &save)) stats->broadcasts.total++;
|
||||
|
||||
/* Unknown */
|
||||
} else {
|
||||
tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", sect);
|
||||
tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", *sect);
|
||||
//htsmsg_print(m);
|
||||
}
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ void epg_init ( void )
|
|||
uint8_t *mem, *rp;
|
||||
epggrab_stats_t stats;
|
||||
int ver = EPG_DB_VERSION;
|
||||
char *sect = NULL;
|
||||
|
||||
/* Find the right file (and version) */
|
||||
while (fd < 0 && ver > 0) {
|
||||
|
@ -207,7 +208,7 @@ void epg_init ( void )
|
|||
/* Process */
|
||||
switch (ver) {
|
||||
case 2:
|
||||
_epgdb_v2_process(m, &stats);
|
||||
_epgdb_v2_process(§, m, &stats);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -217,6 +218,8 @@ void epg_init ( void )
|
|||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
free(sect);
|
||||
|
||||
/* Stats */
|
||||
tvhlog(LOG_INFO, "epgdb", "loaded v%d", ver);
|
||||
tvhlog(LOG_INFO, "epgdb", " channels %d", stats.channels.total);
|
||||
|
@ -230,6 +233,17 @@ void epg_init ( void )
|
|||
close(fd);
|
||||
}
|
||||
|
||||
void epg_done ( void )
|
||||
{
|
||||
channel_t *ch;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
CHANNEL_FOREACH(ch)
|
||||
epg_channel_unlink(ch);
|
||||
epg_skel_done();
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Save
|
||||
* *************************************************************************/
|
||||
|
@ -264,7 +278,12 @@ static int _epg_write_sect ( int fd, const char *sect )
|
|||
return _epg_write(fd, m);
|
||||
}
|
||||
|
||||
void epg_save ( void *p )
|
||||
void epg_save_callback ( void *p )
|
||||
{
|
||||
epg_save();
|
||||
}
|
||||
|
||||
void epg_save ( void )
|
||||
{
|
||||
int fd;
|
||||
epg_object_t *eo;
|
||||
|
@ -274,7 +293,7 @@ void epg_save ( void *p )
|
|||
extern gtimer_t epggrab_save_timer;
|
||||
|
||||
if (epggrab_epgdb_periodicsave)
|
||||
gtimer_arm(&epggrab_save_timer, epg_save, NULL, epggrab_epgdb_periodicsave);
|
||||
gtimer_arm(&epggrab_save_timer, epg_save_callback, NULL, epggrab_epgdb_periodicsave);
|
||||
|
||||
fd = hts_settings_open_file(1, "epgdb.v%d", EPG_DB_VERSION);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
static int epggrab_confver;
|
||||
pthread_mutex_t epggrab_mutex;
|
||||
static pthread_cond_t epggrab_cond;
|
||||
int epggrab_running;
|
||||
|
||||
/* Config */
|
||||
uint32_t epggrab_interval;
|
||||
|
@ -96,7 +97,7 @@ static void* _epggrab_internal_thread ( void* p )
|
|||
|
||||
/* Check for config change */
|
||||
pthread_mutex_lock(&epggrab_mutex);
|
||||
while ( confver == epggrab_confver ) {
|
||||
while ( epggrab_running && confver == epggrab_confver ) {
|
||||
if (epggrab_module) {
|
||||
err = pthread_cond_timedwait(&epggrab_cond, &epggrab_mutex, &ts);
|
||||
} else {
|
||||
|
@ -109,6 +110,9 @@ static void* _epggrab_internal_thread ( void* p )
|
|||
ts.tv_sec += epggrab_interval;
|
||||
pthread_mutex_unlock(&epggrab_mutex);
|
||||
|
||||
if ( !epggrab_running)
|
||||
break;
|
||||
|
||||
/* Run grabber */
|
||||
if (mod) _epggrab_module_grab(mod);
|
||||
}
|
||||
|
@ -143,7 +147,7 @@ static void _epggrab_load ( void )
|
|||
htsmsg_get_u32(m, "channel_reicon", &epggrab_channel_reicon);
|
||||
htsmsg_get_u32(m, "epgdb_periodicsave", &epggrab_epgdb_periodicsave);
|
||||
if (epggrab_epgdb_periodicsave)
|
||||
gtimer_arm(&epggrab_save_timer, epg_save, NULL,
|
||||
gtimer_arm(&epggrab_save_timer, epg_save_callback, NULL,
|
||||
epggrab_epgdb_periodicsave);
|
||||
if (!htsmsg_get_u32(m, old ? "grab-interval" : "interval",
|
||||
&epggrab_interval)) {
|
||||
|
@ -319,7 +323,7 @@ int epggrab_set_periodicsave ( uint32_t e )
|
|||
if (!e)
|
||||
gtimer_disarm(&epggrab_save_timer);
|
||||
else
|
||||
epg_save(NULL); // will arm the timer
|
||||
epg_save(); // will arm the timer
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
save = 1;
|
||||
}
|
||||
|
@ -368,6 +372,8 @@ void epggrab_resched ( void )
|
|||
/*
|
||||
* Initialise
|
||||
*/
|
||||
pthread_t epggrab_tid;
|
||||
|
||||
void epggrab_init ( void )
|
||||
{
|
||||
/* Defaults */
|
||||
|
@ -396,11 +402,33 @@ void epggrab_init ( void )
|
|||
_epggrab_load();
|
||||
|
||||
/* Start internal grab thread */
|
||||
pthread_t tid;
|
||||
pthread_attr_t tattr;
|
||||
pthread_attr_init(&tattr);
|
||||
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
|
||||
tvhthread_create(&tid, &tattr, _epggrab_internal_thread, NULL, 1);
|
||||
pthread_attr_destroy(&tattr);
|
||||
epggrab_running = 1;
|
||||
tvhthread_create(&epggrab_tid, NULL, _epggrab_internal_thread, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
*/
|
||||
void epggrab_done ( void )
|
||||
{
|
||||
epggrab_module_t *mod;
|
||||
|
||||
epggrab_running = 0;
|
||||
pthread_cond_signal(&epggrab_cond);
|
||||
pthread_join(epggrab_tid, NULL);
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((mod = LIST_FIRST(&epggrab_modules)) != NULL) {
|
||||
LIST_REMOVE(mod, link);
|
||||
if (mod->type == EPGGRAB_OTA && ((epggrab_module_ota_t *)mod)->done)
|
||||
((epggrab_module_ota_t *)mod)->done((epggrab_module_ota_t *)mod);
|
||||
if (mod->type == EPGGRAB_INT || mod->type == EPGGRAB_EXT)
|
||||
free((void *)((epggrab_module_int_t *)mod)->path);
|
||||
free((void *)mod->id);
|
||||
free((void *)mod->name);
|
||||
free(mod);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
epggrab_ota_done_();
|
||||
opentv_done();
|
||||
}
|
||||
|
|
|
@ -221,6 +221,7 @@ struct epggrab_module_ota
|
|||
|
||||
/* Transponder tuning */
|
||||
void (*start) ( epggrab_module_ota_t *m, struct mpegts_mux *mm );
|
||||
void (*done) ( epggrab_module_ota_t *m );
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -238,6 +239,7 @@ htsmsg_t* epggrab_module_list ( void );
|
|||
*/
|
||||
extern epggrab_module_list_t epggrab_modules;
|
||||
extern pthread_mutex_t epggrab_mutex;
|
||||
extern int epggrab_running;
|
||||
extern uint32_t epggrab_interval;
|
||||
extern epggrab_module_int_t* epggrab_module;
|
||||
extern uint32_t epggrab_channel_rename;
|
||||
|
@ -262,8 +264,10 @@ int epggrab_enable_module_by_id ( const char *id, uint8_t e );
|
|||
* Load/Save
|
||||
*/
|
||||
void epggrab_init ( void );
|
||||
void epggrab_done ( void );
|
||||
void epggrab_save ( void );
|
||||
void epggrab_ota_init ( void );
|
||||
void epggrab_ota_done_ ( void );
|
||||
|
||||
/* **************************************************************************
|
||||
* Global Functions
|
||||
|
|
|
@ -345,7 +345,7 @@ static void *_epggrab_socket_thread ( void *p )
|
|||
epggrab_module_ext_t *mod = (epggrab_module_ext_t*)p;
|
||||
tvhlog(LOG_INFO, mod->id, "external socket enabled");
|
||||
|
||||
while ( mod->enabled && mod->sock ) {
|
||||
while ( epggrab_running && mod->enabled && mod->sock ) {
|
||||
tvhlog(LOG_DEBUG, mod->id, "waiting for connection");
|
||||
s = accept(mod->sock, NULL, NULL);
|
||||
if (s <= 0) continue;
|
||||
|
@ -452,6 +452,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
|
|||
void (*start) (epggrab_module_ota_t*m,
|
||||
struct mpegts_mux *dm),
|
||||
int (*enable) (void *m, uint8_t e ),
|
||||
void (*done) (epggrab_module_ota_t *m),
|
||||
epggrab_channel_tree_t *channels )
|
||||
{
|
||||
if (!skel) skel = calloc(1, sizeof(epggrab_module_ota_t));
|
||||
|
@ -463,6 +464,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
|
|||
skel->type = EPGGRAB_OTA;
|
||||
skel->enable = enable;
|
||||
skel->start = start;
|
||||
skel->done = done;
|
||||
//TAILQ_INIT(&skel->muxes);
|
||||
|
||||
return skel;
|
||||
|
|
|
@ -555,7 +555,7 @@ _eit_callback
|
|||
uint16_t onid, tsid, sid;
|
||||
uint32_t extraid;
|
||||
mpegts_service_t *svc;
|
||||
mpegts_mux_t *mm = mt->mt_mux;;
|
||||
mpegts_mux_t *mm = mt->mt_mux;
|
||||
epggrab_module_t *mod = mt->mt_opaque;
|
||||
epggrab_ota_mux_t *ota = NULL;
|
||||
mpegts_table_state_t *st;
|
||||
|
@ -680,11 +680,11 @@ static void _eit_start
|
|||
void eit_init ( void )
|
||||
{
|
||||
epggrab_module_ota_create(NULL, "eit", "EIT: DVB Grabber", 1,
|
||||
_eit_start, NULL, NULL);
|
||||
_eit_start, NULL, NULL, NULL);
|
||||
epggrab_module_ota_create(NULL, "uk_freesat", "UK: Freesat", 5,
|
||||
_eit_start, NULL, NULL);
|
||||
_eit_start, NULL, NULL, NULL);
|
||||
epggrab_module_ota_create(NULL, "uk_freeview", "UK: Freeview", 5,
|
||||
_eit_start, NULL, NULL);
|
||||
_eit_start, NULL, NULL, NULL);
|
||||
epggrab_module_ota_create(NULL, "viasat_baltic", "VIASAT: Baltic", 5,
|
||||
_eit_start, NULL, NULL);
|
||||
_eit_start, NULL, NULL, NULL);
|
||||
}
|
||||
|
|
|
@ -686,6 +686,14 @@ static void _opentv_dict_load ( htsmsg_t *m )
|
|||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
static void _opentv_done( epggrab_module_ota_t *m )
|
||||
{
|
||||
opentv_module_t *mod = (opentv_module_t *)m;
|
||||
free(mod->channel);
|
||||
free(mod->title);
|
||||
free(mod->summary);
|
||||
}
|
||||
|
||||
static int _opentv_prov_load_one ( const char *id, htsmsg_t *m )
|
||||
{
|
||||
char ibuf[100], nbuf[1000];
|
||||
|
@ -726,7 +734,7 @@ static int _opentv_prov_load_one ( const char *id, htsmsg_t *m )
|
|||
epggrab_module_ota_create(calloc(1, sizeof(opentv_module_t)),
|
||||
ibuf, nbuf, 2,
|
||||
_opentv_start, NULL,
|
||||
NULL);
|
||||
_opentv_done, NULL);
|
||||
|
||||
/* Add provider details */
|
||||
mod->dict = dict;
|
||||
|
@ -785,6 +793,24 @@ void opentv_init ( void )
|
|||
tvhlog(LOG_DEBUG, "opentv", "providers loaded");
|
||||
}
|
||||
|
||||
void opentv_done ( void )
|
||||
{
|
||||
opentv_dict_t *dict;
|
||||
opentv_genre_t *genre;
|
||||
|
||||
while ((dict = RB_FIRST(&_opentv_dicts)) != NULL) {
|
||||
RB_REMOVE(&_opentv_dicts, dict, h_link);
|
||||
huffman_tree_destroy(dict->codes);
|
||||
free(dict->id);
|
||||
free(dict);
|
||||
}
|
||||
while ((genre = RB_FIRST(&_opentv_genres)) != NULL) {
|
||||
RB_REMOVE(&_opentv_genres, genre, h_link);
|
||||
free(genre->id);
|
||||
free(genre);
|
||||
}
|
||||
}
|
||||
|
||||
void opentv_load ( void )
|
||||
{
|
||||
// TODO: do we want to keep a list of channels stored?
|
||||
|
|
|
@ -37,6 +37,8 @@ LIST_HEAD(,epggrab_ota_mux) epggrab_ota_active;
|
|||
gtimer_t epggrab_ota_pending_timer;
|
||||
gtimer_t epggrab_ota_active_timer;
|
||||
|
||||
SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t);
|
||||
|
||||
static void epggrab_ota_active_timer_cb ( void *p );
|
||||
static void epggrab_ota_pending_timer_cb ( void *p );
|
||||
|
||||
|
@ -191,23 +193,21 @@ epggrab_ota_register
|
|||
int interval, int timeout )
|
||||
{
|
||||
int save = 0;
|
||||
static epggrab_ota_mux_t *skel = NULL;
|
||||
epggrab_ota_map_t *map;
|
||||
epggrab_ota_mux_t *ota;
|
||||
|
||||
/* Find mux entry */
|
||||
const char *uuid = idnode_uuid_as_str(&mm->mm_id);
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(epggrab_ota_mux_t));
|
||||
skel->om_mux_uuid = (char*)uuid;
|
||||
SKEL_ALLOC(epggrab_ota_mux_skel);
|
||||
epggrab_ota_mux_skel->om_mux_uuid = (char*)uuid;
|
||||
|
||||
ota = RB_INSERT_SORTED(&epggrab_ota_all, skel, om_global_link, om_id_cmp);
|
||||
ota = RB_INSERT_SORTED(&epggrab_ota_all, epggrab_ota_mux_skel, om_global_link, om_id_cmp);
|
||||
if (!ota) {
|
||||
char buf[256];
|
||||
mm->mm_display_name(mm, buf, sizeof(buf));
|
||||
tvhinfo(mod->id, "registering mux %s", buf);
|
||||
ota = skel;
|
||||
skel = NULL;
|
||||
ota = epggrab_ota_mux_skel;
|
||||
SKEL_USED(epggrab_ota_mux_skel);
|
||||
ota->om_mux_uuid = strdup(uuid);
|
||||
ota->om_when = dispatch_clock + epggrab_ota_timeout(ota);
|
||||
ota->om_active = 1;
|
||||
|
@ -375,6 +375,7 @@ epggrab_ota_save ( epggrab_ota_mux_t *ota )
|
|||
}
|
||||
htsmsg_add_msg(c, "modules", l);
|
||||
hts_settings_save(c, "epggrab/otamux/%s", ota->om_mux_uuid);
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -457,6 +458,34 @@ epggrab_ota_init ( void )
|
|||
NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
epggrab_ota_free ( epggrab_ota_mux_t *ota )
|
||||
{
|
||||
epggrab_ota_map_t *map;
|
||||
|
||||
LIST_REMOVE(ota, om_q_link);
|
||||
while ((map = LIST_FIRST(&ota->om_modules)) != NULL) {
|
||||
LIST_REMOVE(map, om_link);
|
||||
free(map);
|
||||
}
|
||||
free(ota->om_mux_uuid);
|
||||
free(ota);
|
||||
}
|
||||
|
||||
void
|
||||
epggrab_ota_done_ ( void )
|
||||
{
|
||||
epggrab_ota_mux_t *ota;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((ota = LIST_FIRST(&epggrab_ota_active)) != NULL)
|
||||
epggrab_ota_free(ota);
|
||||
while ((ota = LIST_FIRST(&epggrab_ota_pending)) != NULL)
|
||||
epggrab_ota_free(ota);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
SKEL_FREE(epggrab_ota_mux_skel);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Editor Configuration
|
||||
*
|
||||
|
|
|
@ -91,6 +91,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
|
|||
void (*start) (epggrab_module_ota_t*m,
|
||||
struct mpegts_mux *mm),
|
||||
int (*enable) (void *m, uint8_t e ),
|
||||
void (*done) (epggrab_module_ota_t*m),
|
||||
epggrab_channel_tree_t *channels );
|
||||
|
||||
/* **************************************************************************
|
||||
|
@ -162,6 +163,7 @@ void eit_load ( void );
|
|||
|
||||
/* OpenTV module */
|
||||
void opentv_init ( void );
|
||||
void opentv_done ( void );
|
||||
void opentv_load ( void );
|
||||
|
||||
/* PyEPG module */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#if ENABLE_INOTIFY
|
||||
|
||||
#include <signal.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
@ -56,6 +57,8 @@ fsmonitor_thread ( void* p )
|
|||
|
||||
/* Wait for event */
|
||||
c = read(fsmonitor_fd, buf, sizeof(buf));
|
||||
if (fsmonitor_fd < 0)
|
||||
break;
|
||||
|
||||
/* Process */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
@ -94,14 +97,27 @@ fsmonitor_thread ( void* p )
|
|||
/*
|
||||
* Start the fsmonitor subsystem
|
||||
*/
|
||||
pthread_t fsmonitor_tid;
|
||||
|
||||
void
|
||||
fsmonitor_init ( void )
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/* Intialise inotify */
|
||||
fsmonitor_fd = inotify_init();
|
||||
tvhthread_create0(&tid, NULL, fsmonitor_thread, NULL, "fsmonitor", 1);
|
||||
tvhthread_create0(&fsmonitor_tid, NULL, fsmonitor_thread, NULL, "fsmonitor", 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop the fsmonitor subsystem
|
||||
*/
|
||||
void
|
||||
fsmonitor_done ( void )
|
||||
{
|
||||
int fd = fsmonitor_fd;
|
||||
fsmonitor_fd = -1;
|
||||
close(fd);
|
||||
pthread_kill(fsmonitor_tid, SIGTERM);
|
||||
pthread_join(fsmonitor_tid, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -111,13 +127,13 @@ int
|
|||
fsmonitor_add ( const char *path, fsmonitor_t *fsm )
|
||||
{
|
||||
int mask;
|
||||
static fsmonitor_path_t *skel = NULL;
|
||||
fsmonitor_path_t *skel;
|
||||
fsmonitor_path_t *fmp;
|
||||
fsmonitor_link_t *fml;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (!skel) skel = calloc(1, sizeof(fsmonitor_path_t));
|
||||
skel = calloc(1, sizeof(fsmonitor_path_t));
|
||||
skel->fmp_path = (char*)path;
|
||||
|
||||
/* Build mask */
|
||||
|
@ -127,21 +143,22 @@ fsmonitor_add ( const char *path, fsmonitor_t *fsm )
|
|||
fmp = RB_INSERT_SORTED(&fsmonitor_paths, skel, fmp_link, fmp_cmp);
|
||||
if (!fmp) {
|
||||
fmp = skel;
|
||||
fmp->fmp_fd
|
||||
= inotify_add_watch(fsmonitor_fd, path, mask);
|
||||
fmp->fmp_fd = inotify_add_watch(fsmonitor_fd, path, mask);
|
||||
|
||||
/* Failed */
|
||||
if (fmp->fmp_fd <= 0) {
|
||||
RB_REMOVE(&fsmonitor_paths, skel, fmp_link);
|
||||
RB_REMOVE(&fsmonitor_paths, fmp, fmp_link);
|
||||
free(fmp);
|
||||
tvhdebug("fsmonitor", "failed to add %s (exists?)", path);
|
||||
printf("ERROR: failed to add %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
skel = NULL;
|
||||
fmp->fmp_path = strdup(path);
|
||||
tvhdebug("fsmonitor", "watch %s", fmp->fmp_path);
|
||||
} else {
|
||||
free(skel);
|
||||
}
|
||||
|
||||
/* Check doesn't exist */
|
||||
|
@ -165,17 +182,16 @@ fsmonitor_add ( const char *path, fsmonitor_t *fsm )
|
|||
void
|
||||
fsmonitor_del ( const char *path, fsmonitor_t *fsm )
|
||||
{
|
||||
static fsmonitor_path_t *skel = NULL;
|
||||
static fsmonitor_path_t skel;
|
||||
fsmonitor_path_t *fmp;
|
||||
fsmonitor_link_t *fml;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (!skel) skel = calloc(1, sizeof(fsmonitor_path_t));
|
||||
skel->fmp_path = (char*)path;
|
||||
skel.fmp_path = (char*)path;
|
||||
|
||||
/* Find path */
|
||||
fmp = RB_FIND(&fsmonitor_paths, skel, fmp_link, fmp_cmp);
|
||||
fmp = RB_FIND(&fsmonitor_paths, &skel, fmp_link, fmp_cmp);
|
||||
if (fmp) {
|
||||
|
||||
/* Find link */
|
||||
|
@ -191,7 +207,7 @@ fsmonitor_del ( const char *path, fsmonitor_t *fsm )
|
|||
}
|
||||
|
||||
/* Remove path */
|
||||
if (!LIST_FIRST(&fmp->fmp_monitors)) {
|
||||
if (LIST_EMPTY(&fmp->fmp_monitors)) {
|
||||
tvhdebug("fsmonitor", "unwatch %s", fmp->fmp_path);
|
||||
RB_REMOVE(&fsmonitor_paths, fmp, fmp_link);
|
||||
inotify_rm_watch(fsmonitor_fd, fmp->fmp_fd);
|
||||
|
|
|
@ -47,6 +47,7 @@ struct fsmonitor {
|
|||
};
|
||||
|
||||
void fsmonitor_init ( void );
|
||||
void fsmonitor_done ( void );
|
||||
int fsmonitor_add ( const char *path, fsmonitor_t *fsm );
|
||||
void fsmonitor_del ( const char *path, fsmonitor_t *fsm );
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -1986,7 +1987,7 @@ htsp_read_loop(htsp_connection_t *htsp)
|
|||
|
||||
/* Session main loop */
|
||||
|
||||
while(1) {
|
||||
while(tvheadend_running) {
|
||||
readmsg:
|
||||
if((r = htsp_read_message(htsp, &m, 0)) != 0)
|
||||
return r;
|
||||
|
@ -2036,6 +2037,7 @@ readmsg:
|
|||
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2052,7 +2054,7 @@ htsp_write_scheduler(void *aux)
|
|||
|
||||
pthread_mutex_lock(&htsp->htsp_out_mutex);
|
||||
|
||||
while(1) {
|
||||
while(tvheadend_running) {
|
||||
|
||||
if((hmq = TAILQ_FIRST(&htsp->htsp_active_output_queues)) == NULL) {
|
||||
/* No active queues at all */
|
||||
|
@ -2213,6 +2215,14 @@ htsp_server_status ( void *opaque, htsmsg_t *m )
|
|||
htsmsg_add_str(m, "user", htsp->htsp_username);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel callback
|
||||
*/
|
||||
static void
|
||||
htsp_server_cancel ( void *opaque )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire up HTSP server
|
||||
*/
|
||||
|
@ -2224,12 +2234,25 @@ htsp_init(const char *bindaddr)
|
|||
.start = htsp_serve,
|
||||
.stop = NULL,
|
||||
.status = htsp_server_status,
|
||||
.cancel = htsp_server_cancel
|
||||
};
|
||||
htsp_server = tcp_server_create(bindaddr, tvheadend_htsp_port, &ops, NULL);
|
||||
if(tvheadend_htsp_port_extra)
|
||||
htsp_server_2 = tcp_server_create(bindaddr, tvheadend_htsp_port_extra, &ops, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire down HTSP server
|
||||
*/
|
||||
void
|
||||
htsp_done(void)
|
||||
{
|
||||
if (htsp_server_2)
|
||||
tcp_server_delete(htsp_server_2);
|
||||
if (htsp_server)
|
||||
tcp_server_delete(htsp_server);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Asynchronous updates
|
||||
* *************************************************************************/
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "dvr/dvr.h"
|
||||
|
||||
void htsp_init(const char *bindaddr);
|
||||
void htsp_done(void);
|
||||
|
||||
void htsp_channel_update_nownext(channel_t *ch);
|
||||
|
||||
|
|
18
src/http.c
18
src/http.c
|
@ -25,6 +25,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -789,7 +790,7 @@ http_serve(int fd, void **opaque, struct sockaddr_storage *peer,
|
|||
{
|
||||
htsbuf_queue_t spill;
|
||||
http_connection_t hc;
|
||||
|
||||
|
||||
// Note: global_lock held on entry */
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
memset(&hc, 0, sizeof(http_connection_t));
|
||||
|
@ -845,3 +846,18 @@ http_server_init(const char *bindaddr)
|
|||
};
|
||||
http_server = tcp_server_create(bindaddr, tvheadend_webui_port, &ops, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
http_server_done(void)
|
||||
{
|
||||
http_path_t *hp;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((hp = LIST_FIRST(&http_paths)) != NULL) {
|
||||
LIST_REMOVE(hp, hp_link);
|
||||
free((void *)hp->hp_path);
|
||||
free(hp);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
tcp_server_delete(http_server);
|
||||
}
|
||||
|
|
|
@ -136,6 +136,7 @@ http_path_t *http_path_add(const char *path, void *opaque,
|
|||
http_callback_t *callback, uint32_t accessmask);
|
||||
|
||||
void http_server_init(const char *bindaddr);
|
||||
void http_server_done(void);
|
||||
|
||||
int http_access_verify(http_connection_t *hc, int mask);
|
||||
|
||||
|
@ -148,6 +149,7 @@ typedef size_t (http_client_data_cb) (void *p, void *buf, size_t len);
|
|||
typedef void (http_client_fail_cb) (void *p);
|
||||
|
||||
void http_client_init ( void );
|
||||
void http_client_done ( void );
|
||||
http_client_t*
|
||||
http_connect ( const url_t *url,
|
||||
http_client_conn_cb conn_cb,
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
|
||||
/*
|
||||
|
@ -141,7 +142,7 @@ http_thread ( void *p )
|
|||
tvhpoll_event_t ev;
|
||||
http_client_t *hc;
|
||||
|
||||
while (1) {
|
||||
while (tvheadend_running) {
|
||||
n = tvhpoll_wait(http_poll, &ev, 1, -1);
|
||||
if (n < 0) {
|
||||
tvherror("http_client", "tvhpoll_wait() error");
|
||||
|
@ -217,11 +218,11 @@ http_close ( http_client_t *hc )
|
|||
/*
|
||||
* Initialise subsystem
|
||||
*/
|
||||
pthread_t http_client_tid;
|
||||
|
||||
void
|
||||
http_client_init ( void )
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/* Setup list */
|
||||
pthread_mutex_init(&http_lock, NULL);
|
||||
TAILQ_INIT(&http_clients);
|
||||
|
@ -235,7 +236,17 @@ http_client_init ( void )
|
|||
http_poll = tvhpoll_create(10);
|
||||
|
||||
/* Setup thread */
|
||||
tvhthread_create(&tid, NULL, http_thread, NULL, 1);
|
||||
tvhthread_create(&http_client_tid, NULL, http_thread, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
http_client_done ( void )
|
||||
{
|
||||
pthread_kill(http_client_tid, SIGTERM);
|
||||
pthread_join(http_client_tid, NULL);
|
||||
tvhpoll_destroy(http_poll);
|
||||
curl_multi_cleanup(http_curlm);
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
#else /* ENABLE_CURL */
|
||||
|
@ -245,4 +256,9 @@ http_client_init ( void )
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
http_client_done ( void )
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ENABLE_CURL */
|
||||
|
|
42
src/idnode.c
42
src/idnode.c
|
@ -43,6 +43,8 @@ static pthread_mutex_t idnode_mutex;
|
|||
static htsmsg_t *idnode_queue;
|
||||
static void* idnode_thread(void* p);
|
||||
|
||||
SKEL_DECLARE(idclasses_skel, idclass_link_t);
|
||||
|
||||
static void
|
||||
idclass_register(const idclass_t *idc);
|
||||
|
||||
|
@ -120,11 +122,11 @@ in_cmp(const idnode_t *a, const idnode_t *b)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
pthread_t idnode_tid;
|
||||
|
||||
void
|
||||
idnode_init(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
randfd = open("/dev/urandom", O_RDONLY);
|
||||
if(randfd == -1)
|
||||
exit(1);
|
||||
|
@ -132,7 +134,25 @@ idnode_init(void)
|
|||
idnode_queue = NULL;
|
||||
pthread_mutex_init(&idnode_mutex, NULL);
|
||||
pthread_cond_init(&idnode_cond, NULL);
|
||||
tvhthread_create(&tid, NULL, idnode_thread, NULL, 1);
|
||||
tvhthread_create(&idnode_tid, NULL, idnode_thread, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
idnode_done(void)
|
||||
{
|
||||
idclass_link_t *il;
|
||||
|
||||
pthread_cond_signal(&idnode_cond);
|
||||
pthread_join(idnode_tid, NULL);
|
||||
pthread_mutex_lock(&idnode_mutex);
|
||||
htsmsg_destroy(idnode_queue);
|
||||
idnode_queue = NULL;
|
||||
pthread_mutex_unlock(&idnode_mutex);
|
||||
while ((il = RB_FIRST(&idclasses)) != NULL) {
|
||||
RB_REMOVE(&idclasses, il, link);
|
||||
free(il);
|
||||
}
|
||||
SKEL_FREE(idclasses_skel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -810,15 +830,13 @@ ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
|
|||
static void
|
||||
idclass_register(const idclass_t *idc)
|
||||
{
|
||||
static idclass_link_t *skel = NULL;
|
||||
while (idc) {
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(idclass_link_t));
|
||||
skel->idc = idc;
|
||||
if (RB_INSERT_SORTED(&idclasses, skel, link, ic_cmp))
|
||||
SKEL_ALLOC(idclasses_skel);
|
||||
idclasses_skel->idc = idc;
|
||||
if (RB_INSERT_SORTED(&idclasses, idclasses_skel, link, ic_cmp))
|
||||
break;
|
||||
SKEL_USED(idclasses_skel);
|
||||
tvhtrace("idnode", "register class %s", idc->ic_class);
|
||||
skel = NULL;
|
||||
idc = idc->ic_super;
|
||||
}
|
||||
}
|
||||
|
@ -912,6 +930,9 @@ idnode_notify
|
|||
{
|
||||
const char *uuid = idnode_uuid_as_str(in);
|
||||
|
||||
if (!tvheadend_running)
|
||||
return;
|
||||
|
||||
/* Forced */
|
||||
if (chn || force) {
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
@ -961,7 +982,7 @@ idnode_thread ( void *p )
|
|||
|
||||
pthread_mutex_lock(&idnode_mutex);
|
||||
|
||||
while (1) {
|
||||
while (tvheadend_running) {
|
||||
|
||||
/* Get queue */
|
||||
if (!idnode_queue) {
|
||||
|
@ -995,6 +1016,7 @@ idnode_thread ( void *p )
|
|||
pthread_mutex_lock(&idnode_mutex);
|
||||
}
|
||||
if (q) htsmsg_destroy(q);
|
||||
pthread_mutex_unlock(&idnode_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ typedef struct idnode_filter_ele
|
|||
typedef LIST_HEAD(,idnode_filter_ele) idnode_filter_t;
|
||||
|
||||
void idnode_init(void);
|
||||
void idnode_done(void);
|
||||
|
||||
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc);
|
||||
void idnode_unlink(idnode_t *in);
|
||||
|
|
|
@ -199,7 +199,7 @@ imagecache_thread ( void *p )
|
|||
imagecache_image_t *img;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while (1) {
|
||||
while (tvheadend_running) {
|
||||
|
||||
/* Check we're enabled */
|
||||
if (!imagecache_conf.enabled) {
|
||||
|
@ -220,7 +220,9 @@ imagecache_thread ( void *p )
|
|||
/* Fetch */
|
||||
(void)imagecache_image_fetch(img);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
fprintf(stderr, "imagecache thread end\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -245,6 +247,10 @@ imagecache_timer_cb ( void *p )
|
|||
/*
|
||||
* Initialise
|
||||
*/
|
||||
#if ENABLE_IMAGECACHE
|
||||
pthread_t imagecache_tid;
|
||||
#endif
|
||||
|
||||
void
|
||||
imagecache_init ( void )
|
||||
{
|
||||
|
@ -307,10 +313,7 @@ imagecache_init ( void )
|
|||
|
||||
/* Start threads */
|
||||
#if ENABLE_IMAGECACHE
|
||||
{
|
||||
pthread_t tid;
|
||||
tvhthread_create(&tid, NULL, imagecache_thread, NULL, 1);
|
||||
}
|
||||
tvhthread_create(&imagecache_tid, NULL, imagecache_thread, NULL, 0);
|
||||
|
||||
/* Re-try timer */
|
||||
// TODO: this could be more efficient by being targetted, however
|
||||
|
@ -320,6 +323,27 @@ imagecache_init ( void )
|
|||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown
|
||||
*/
|
||||
void
|
||||
imagecache_done ( void )
|
||||
{
|
||||
imagecache_image_t *img;
|
||||
|
||||
#if ENABLE_IMAGECACHE
|
||||
pthread_cond_broadcast(&imagecache_cond);
|
||||
pthread_join(imagecache_tid, NULL);
|
||||
#endif
|
||||
while ((img = RB_FIRST(&imagecache_by_url)) != NULL) {
|
||||
RB_REMOVE(&imagecache_by_url, img, url_link);
|
||||
RB_REMOVE(&imagecache_by_id, img, id_link);
|
||||
free((void *)img->url);
|
||||
free(img);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if ENABLE_IMAGECACHE
|
||||
|
||||
/*
|
||||
|
|
|
@ -33,6 +33,7 @@ extern struct imagecache_config imagecache_conf;
|
|||
extern pthread_mutex_t imagecache_mutex;
|
||||
|
||||
void imagecache_init ( void );
|
||||
void imagecache_done ( void );
|
||||
|
||||
htsmsg_t *imagecache_get_config ( void );
|
||||
int imagecache_set_config ( htsmsg_t *c );
|
||||
|
|
|
@ -295,7 +295,7 @@ struct mpegts_mux
|
|||
* Functions
|
||||
*/
|
||||
|
||||
void (*mm_delete) (mpegts_mux_t *mm);
|
||||
void (*mm_delete) (mpegts_mux_t *mm, int delconf);
|
||||
void (*mm_config_save) (mpegts_mux_t *mm);
|
||||
void (*mm_display_name) (mpegts_mux_t*, char *buf, size_t len);
|
||||
int (*mm_is_enabled) (mpegts_mux_t *mm);
|
||||
|
@ -445,6 +445,9 @@ struct mpegts_input
|
|||
pthread_t mi_thread_id;
|
||||
th_pipe_t mi_thread_pipe;
|
||||
|
||||
int mi_delivery_running;
|
||||
pthread_t mi_thread_table_id;
|
||||
|
||||
/*
|
||||
* Functions
|
||||
*/
|
||||
|
@ -500,7 +503,7 @@ mpegts_input_t *mpegts_input_create0
|
|||
mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
|
||||
&mpegts_input_class, u, c)
|
||||
|
||||
void mpegts_input_delete ( mpegts_input_t *mi );
|
||||
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
|
||||
|
||||
#define mpegts_input_find(u) idnode_find(u, &mpegts_input_class);
|
||||
|
||||
|
@ -515,6 +518,9 @@ void mpegts_network_register_builder
|
|||
( const idclass_t *idc,
|
||||
mpegts_network_t *(*build)(const idclass_t *idc, htsmsg_t *conf) );
|
||||
|
||||
void mpegts_network_unregister_builder
|
||||
( const idclass_t *idc );
|
||||
|
||||
mpegts_network_t *mpegts_network_build
|
||||
( const char *clazz, htsmsg_t *conf );
|
||||
|
||||
|
@ -532,8 +538,10 @@ extern const idclass_t mpegts_network_class;
|
|||
|
||||
mpegts_mux_t *mpegts_network_find_mux
|
||||
(mpegts_network_t *mn, uint16_t onid, uint16_t tsid);
|
||||
|
||||
void mpegts_network_delete ( mpegts_network_t *mn );
|
||||
|
||||
void mpegts_network_class_delete ( const idclass_t *idc, int delconf );
|
||||
|
||||
void mpegts_network_delete ( mpegts_network_t *mn, int delconf );
|
||||
|
||||
void mpegts_network_schedule_initial_scan
|
||||
( mpegts_network_t *mm );
|
||||
|
@ -557,13 +565,13 @@ mpegts_mux_t *mpegts_mux_create0
|
|||
#define mpegts_mux_find(u)\
|
||||
idnode_find(u, &mpegts_mux_class)
|
||||
|
||||
#define mpegts_mux_delete_by_uuid(u)\
|
||||
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm); }
|
||||
#define mpegts_mux_delete_by_uuid(u, delconf)\
|
||||
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
|
||||
|
||||
void mpegts_mux_initial_scan_done ( mpegts_mux_t *mm, int log );
|
||||
void mpegts_mux_initial_scan_fail ( mpegts_mux_t *mm );
|
||||
|
||||
void mpegts_mux_delete ( mpegts_mux_t *mm );
|
||||
void mpegts_mux_delete ( mpegts_mux_t *mm, int delconf );
|
||||
|
||||
void mpegts_mux_save ( mpegts_mux_t *mm, htsmsg_t *c );
|
||||
|
||||
|
@ -599,7 +607,9 @@ size_t mpegts_input_recv_packets
|
|||
(mpegts_input_t *mi, mpegts_mux_instance_t *mmi, uint8_t *tsb, size_t len,
|
||||
int64_t *pcr, uint16_t *pcr_pid, const char *name);
|
||||
|
||||
void *mpegts_input_table_thread ( void *aux );
|
||||
void mpegts_input_table_thread_start( mpegts_input_t *mi );
|
||||
|
||||
void mpegts_input_table_thread_stop( mpegts_input_t *mi );
|
||||
|
||||
int mpegts_input_is_free ( mpegts_input_t *mi );
|
||||
|
||||
|
@ -646,7 +656,7 @@ mpegts_service_t *mpegts_service_find
|
|||
|
||||
void mpegts_service_save ( mpegts_service_t *s, htsmsg_t *c );
|
||||
|
||||
void mpegts_service_delete ( service_t *s );
|
||||
void mpegts_service_delete ( service_t *s, int delconf );
|
||||
|
||||
/*
|
||||
* MPEG-TS event handler
|
||||
|
|
|
@ -276,4 +276,6 @@ int dvb_delsys2type ( enum fe_delivery_system ds );
|
|||
|
||||
#endif /* ENABLE_DVBAPI */
|
||||
|
||||
void dvb_done ( void );
|
||||
|
||||
#endif /* DVB_SUPPORT_H */
|
||||
|
|
|
@ -78,6 +78,20 @@ void dvb_charset_init ( void )
|
|||
_charset_load_file();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void dvb_charset_done ( void )
|
||||
{
|
||||
dvb_charset_t *enc;
|
||||
|
||||
while ((enc = LIST_FIRST(&dvb_charset_list)) != NULL) {
|
||||
LIST_REMOVE(enc, link);
|
||||
free((void *)enc->charset);
|
||||
free(enc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find default charset
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ typedef struct dvb_charset {
|
|||
} dvb_charset_t;
|
||||
|
||||
void dvb_charset_init ( void );
|
||||
void dvb_charset_done ( void );
|
||||
|
||||
struct mpegts_network;
|
||||
struct mpegts_mux;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <linux/dvb/version.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
|
||||
|
||||
static int
|
||||
psi_parse_pmt(mpegts_service_t *t, const uint8_t *ptr, int len);
|
||||
|
||||
|
@ -445,17 +447,16 @@ static struct mpegts_table_state *
|
|||
mpegts_table_state_find
|
||||
( mpegts_table_t *mt, int tableid, uint64_t extraid, int last )
|
||||
{
|
||||
static struct mpegts_table_state *st, *skel = NULL;
|
||||
struct mpegts_table_state *st;
|
||||
|
||||
/* Find state */
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(*skel));
|
||||
skel->tableid = tableid;
|
||||
skel->extraid = extraid;
|
||||
st = RB_INSERT_SORTED(&mt->mt_state, skel, link, sect_cmp);
|
||||
SKEL_ALLOC(mpegts_table_state_skel);
|
||||
mpegts_table_state_skel->tableid = tableid;
|
||||
mpegts_table_state_skel->extraid = extraid;
|
||||
st = RB_INSERT_SORTED(&mt->mt_state, mpegts_table_state_skel, link, sect_cmp);
|
||||
if (!st) {
|
||||
st = skel;
|
||||
skel = NULL;
|
||||
st = mpegts_table_state_skel;
|
||||
SKEL_USED(mpegts_table_state_skel);
|
||||
mt->mt_incomplete++;
|
||||
mpegts_table_state_reset(mt, st, last);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_charset_tables.h"
|
||||
#include "../mpegts.h"
|
||||
|
||||
static int convert_iso_8859[16] = {
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, 13
|
||||
|
@ -813,3 +814,17 @@ dvb_bandwidth ( fe_bandwidth_t bw )
|
|||
}
|
||||
|
||||
#endif /* ENABLE_DVBAPI */
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void dvb_done( void )
|
||||
{
|
||||
extern SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
|
||||
extern SKEL_DECLARE(mpegts_pid_sub_skel, mpegts_pid_sub_t);
|
||||
extern SKEL_DECLARE(mpegts_pid_skel, mpegts_pid_t);
|
||||
|
||||
SKEL_FREE(mpegts_table_state_skel);
|
||||
SKEL_FREE(mpegts_pid_sub_skel);
|
||||
SKEL_FREE(mpegts_pid_skel);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __IPTV_H__
|
||||
|
||||
void iptv_init ( void );
|
||||
void iptv_done ( void );
|
||||
|
||||
#endif /* __IPTV_H__ */
|
||||
|
||||
|
|
|
@ -32,13 +32,15 @@
|
|||
#include <unistd.h>
|
||||
#include <regex.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* **************************************************************************
|
||||
* IPTV state
|
||||
* *************************************************************************/
|
||||
|
||||
iptv_input_t iptv_input;
|
||||
iptv_network_t iptv_network;
|
||||
iptv_input_t *iptv_input;
|
||||
iptv_network_t *iptv_network;
|
||||
tvhpoll_t *iptv_poll;
|
||||
pthread_t iptv_thread;
|
||||
pthread_mutex_t iptv_lock;
|
||||
|
@ -108,12 +110,12 @@ iptv_input_is_free ( mpegts_input_t *mi )
|
|||
c++;
|
||||
|
||||
/* Limit reached */
|
||||
if (iptv_network.in_max_streams && c >= iptv_network.in_max_streams) {
|
||||
if (iptv_network->in_max_streams && c >= iptv_network->in_max_streams) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bandwidth reached */
|
||||
if (iptv_network.in_bw_limited) {
|
||||
if (iptv_network->in_bw_limited) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -241,7 +243,7 @@ iptv_input_stop_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
|
|||
im->mm_iptv_tsb = NULL;
|
||||
|
||||
/* Clear bw limit */
|
||||
iptv_network.in_bw_limited = 0;
|
||||
iptv_network->in_bw_limited = 0;
|
||||
|
||||
pthread_mutex_unlock(&iptv_lock);
|
||||
}
|
||||
|
@ -261,7 +263,7 @@ iptv_input_thread ( void *aux )
|
|||
iptv_mux_t *im;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
while ( 1 ) {
|
||||
while ( tvheadend_running ) {
|
||||
nfds = tvhpoll_wait(iptv_poll, &ev, 1, -1);
|
||||
if ( nfds < 0 ) {
|
||||
tvhlog(LOG_ERR, "iptv", "poll() error %s, sleeping 1 second",
|
||||
|
@ -298,23 +300,23 @@ void
|
|||
iptv_input_recv_packets ( iptv_mux_t *im, size_t off, size_t len )
|
||||
{
|
||||
static time_t t1 = 0, t2;
|
||||
iptv_network.in_bps += len * 8;
|
||||
iptv_network->in_bps += len * 8;
|
||||
time(&t2);
|
||||
if (t2 != t1) {
|
||||
if (iptv_network.in_max_bandwidth &&
|
||||
iptv_network.in_bps > iptv_network.in_max_bandwidth * 1024) {
|
||||
if (!iptv_network.in_bw_limited) {
|
||||
if (iptv_network->in_max_bandwidth &&
|
||||
iptv_network->in_bps > iptv_network->in_max_bandwidth * 1024) {
|
||||
if (!iptv_network->in_bw_limited) {
|
||||
tvhinfo("iptv", "bandwidth limited exceeded");
|
||||
iptv_network.in_bw_limited = 1;
|
||||
iptv_network->in_bw_limited = 1;
|
||||
}
|
||||
}
|
||||
iptv_network.in_bps = 0;
|
||||
iptv_network->in_bps = 0;
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
/* Pass on */
|
||||
im->mm_iptv_pos
|
||||
= mpegts_input_recv_packets((mpegts_input_t*)&iptv_input,
|
||||
= mpegts_input_recv_packets((mpegts_input_t*)iptv_input,
|
||||
im->mm_active,
|
||||
im->mm_iptv_tsb + off,
|
||||
im->mm_iptv_pos + len - off,
|
||||
|
@ -423,7 +425,6 @@ iptv_network_config_save ( mpegts_network_t *mn )
|
|||
|
||||
void iptv_init ( void )
|
||||
{
|
||||
pthread_t tid;
|
||||
htsmsg_t *conf;
|
||||
const char *uuid = NULL;
|
||||
|
||||
|
@ -431,48 +432,64 @@ void iptv_init ( void )
|
|||
iptv_http_init();
|
||||
iptv_udp_init();
|
||||
|
||||
iptv_input = calloc(1, sizeof(iptv_input_t));
|
||||
|
||||
/* Init Input */
|
||||
mpegts_input_create0((mpegts_input_t*)&iptv_input,
|
||||
mpegts_input_create0((mpegts_input_t*)iptv_input,
|
||||
&iptv_input_class, NULL, NULL);
|
||||
iptv_input.mi_start_mux = iptv_input_start_mux;
|
||||
iptv_input.mi_stop_mux = iptv_input_stop_mux;
|
||||
iptv_input.mi_is_free = iptv_input_is_free;
|
||||
iptv_input.mi_get_weight = iptv_input_get_weight;
|
||||
iptv_input.mi_display_name = iptv_input_display_name;
|
||||
iptv_input.mi_enabled = 1;
|
||||
iptv_input->mi_start_mux = iptv_input_start_mux;
|
||||
iptv_input->mi_stop_mux = iptv_input_stop_mux;
|
||||
iptv_input->mi_is_free = iptv_input_is_free;
|
||||
iptv_input->mi_get_weight = iptv_input_get_weight;
|
||||
iptv_input->mi_display_name = iptv_input_display_name;
|
||||
iptv_input->mi_enabled = 1;
|
||||
|
||||
/* Load settings */
|
||||
if ((conf = hts_settings_load("input/iptv/config")))
|
||||
uuid = htsmsg_get_str(conf, "uuid");
|
||||
|
||||
iptv_network = calloc(1, sizeof(iptv_network_t));
|
||||
|
||||
/* Init Network */
|
||||
mpegts_network_create0((mpegts_network_t*)&iptv_network,
|
||||
mpegts_network_create0((mpegts_network_t*)iptv_network,
|
||||
&iptv_network_class, uuid, "IPTV Network", conf);
|
||||
iptv_network.mn_create_service = iptv_network_create_service;
|
||||
iptv_network.mn_mux_class = iptv_network_mux_class;
|
||||
iptv_network.mn_mux_create2 = iptv_network_create_mux2;
|
||||
iptv_network.mn_config_save = iptv_network_config_save;
|
||||
iptv_network->mn_create_service = iptv_network_create_service;
|
||||
iptv_network->mn_mux_class = iptv_network_mux_class;
|
||||
iptv_network->mn_mux_create2 = iptv_network_create_mux2;
|
||||
iptv_network->mn_config_save = iptv_network_config_save;
|
||||
|
||||
/* Defaults */
|
||||
if (!conf) {
|
||||
iptv_network.mn_skipinitscan = 1;
|
||||
iptv_network->mn_skipinitscan = 1;
|
||||
}
|
||||
|
||||
/* Link */
|
||||
mpegts_input_set_network((mpegts_input_t*)&iptv_input,
|
||||
(mpegts_network_t*)&iptv_network);
|
||||
mpegts_input_set_network((mpegts_input_t*)iptv_input,
|
||||
(mpegts_network_t*)iptv_network);
|
||||
/* Set table thread */
|
||||
tvhthread_create(&tid, NULL, mpegts_input_table_thread, &iptv_input, 1);
|
||||
mpegts_input_table_thread_start((mpegts_input_t *)iptv_input);
|
||||
|
||||
/* Setup TS thread */
|
||||
iptv_poll = tvhpoll_create(10);
|
||||
pthread_mutex_init(&iptv_lock, NULL);
|
||||
tvhthread_create(&iptv_thread, NULL, iptv_input_thread, NULL, 1);
|
||||
tvhthread_create(&iptv_thread, NULL, iptv_input_thread, NULL, 0);
|
||||
|
||||
/* Load config */
|
||||
iptv_mux_load_all();
|
||||
}
|
||||
|
||||
void iptv_done ( void )
|
||||
{
|
||||
mpegts_input_table_thread_stop((mpegts_input_t *)iptv_input);
|
||||
pthread_kill(iptv_thread, SIGTERM);
|
||||
pthread_join(iptv_thread, NULL);
|
||||
tvhpoll_destroy(iptv_poll);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mpegts_network_delete((mpegts_network_t *)iptv_network, 0);
|
||||
mpegts_input_delete((mpegts_input_t *)iptv_input, 0);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Editor Configuration
|
||||
*
|
||||
|
|
|
@ -65,12 +65,13 @@ iptv_mux_config_save ( mpegts_mux_t *mm )
|
|||
}
|
||||
|
||||
static void
|
||||
iptv_mux_delete ( mpegts_mux_t *mm )
|
||||
iptv_mux_delete ( mpegts_mux_t *mm, int delconf )
|
||||
{
|
||||
hts_settings_remove("input/iptv/muxes/%s/config",
|
||||
if (delconf)
|
||||
hts_settings_remove("input/iptv/muxes/%s/config",
|
||||
idnode_uuid_as_str(&mm->mm_id));
|
||||
|
||||
mpegts_mux_delete(mm);
|
||||
mpegts_mux_delete(mm, delconf);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -99,8 +99,8 @@ iptv_service_t *iptv_service_create0
|
|||
( iptv_mux_t *im, uint16_t sid, uint16_t pmt_pid,
|
||||
const char *uuid, htsmsg_t *conf );
|
||||
|
||||
extern iptv_input_t iptv_input;
|
||||
extern iptv_network_t iptv_network;
|
||||
extern iptv_input_t *iptv_input;
|
||||
extern iptv_network_t *iptv_network;
|
||||
|
||||
void iptv_mux_load_all ( void );
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
void linuxdvb_init ( int mask );
|
||||
|
||||
void linuxdvb_done ( void );
|
||||
|
||||
idnode_set_t *linuxdvb_root ( void );
|
||||
|
||||
#endif /* __TVH_LINUX_DVB_H__ */
|
||||
|
|
|
@ -45,3 +45,11 @@ void linuxdvb_init ( int adapter_mask )
|
|||
/* Initialsie devices */
|
||||
linuxdvb_adapter_init();
|
||||
}
|
||||
|
||||
void linuxdvb_done ( void )
|
||||
{
|
||||
linuxdvb_network_done();
|
||||
linuxdvb_adapter_done();
|
||||
dvb_charset_done();
|
||||
scanfile_done();
|
||||
}
|
||||
|
|
|
@ -144,6 +144,7 @@ linuxdvb_adapter_create
|
|||
|
||||
/* Setup */
|
||||
sprintf(buf, "%s [%s]", path, dfi->name);
|
||||
free(la->la_rootpath);
|
||||
la->la_rootpath = strdup(path);
|
||||
la->la_name = strdup(buf);
|
||||
la->la_dvb_number = number;
|
||||
|
@ -271,6 +272,7 @@ linuxdvb_adapter_add ( const char *path )
|
|||
/* Create */
|
||||
if (!(la = linuxdvb_adapter_create(uuid, conf, path, a, &dfi))) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "failed to create %s", path);
|
||||
htsmsg_destroy(conf);
|
||||
return; // Note: save to return here as global_lock is held
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +297,7 @@ linuxdvb_adapter_add ( const char *path )
|
|||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
htsmsg_destroy(conf);
|
||||
}
|
||||
|
||||
/* Relock before exit */
|
||||
|
@ -334,6 +337,8 @@ linuxdvb_adapter_del ( const char *path )
|
|||
|
||||
/* Delete */
|
||||
tvh_hardware_delete((tvh_hardware_t*)la);
|
||||
|
||||
free(la);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,3 +429,22 @@ linuxdvb_adapter_init ( void )
|
|||
linuxdvb_adapter_scan();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
linuxdvb_adapter_done ( void )
|
||||
{
|
||||
linuxdvb_adapter_t *la;
|
||||
tvh_hardware_t *th, *n;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
fsmonitor_del("/dev/dvb", &devdvbmon);
|
||||
fsmonitor_del("/dev", &devmon);
|
||||
for (th = LIST_FIRST(&tvh_hardware); th != NULL; th = n) {
|
||||
n = LIST_NEXT(th, th_link);
|
||||
if (idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) {
|
||||
la = (linuxdvb_adapter_t*)th;
|
||||
linuxdvb_adapter_del(la->la_rootpath);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
|
|
@ -704,7 +704,7 @@ linuxdvb_frontend_input_thread ( void *aux )
|
|||
tvhpoll_add(efd, ev, 2);
|
||||
|
||||
/* Read */
|
||||
while (1) {
|
||||
while (tvheadend_running) {
|
||||
nfds = tvhpoll_wait(efd, ev, 1, 10);
|
||||
if (nfds < 1) continue;
|
||||
if (ev[0].data.fd != dvr) break;
|
||||
|
@ -922,7 +922,6 @@ linuxdvb_frontend_create
|
|||
char id[12], name[256];
|
||||
linuxdvb_frontend_t *lfe;
|
||||
htsmsg_t *scconf = NULL;
|
||||
pthread_t tid;
|
||||
|
||||
/* Internal config ID */
|
||||
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(dfi->type), number);
|
||||
|
@ -986,7 +985,7 @@ linuxdvb_frontend_create
|
|||
pthread_cond_init(&lfe->lfe_dvr_cond, NULL);
|
||||
|
||||
/* Start table thread */
|
||||
tvhthread_create(&tid, NULL, mpegts_input_table_thread, lfe, 1);
|
||||
mpegts_input_table_thread_start((mpegts_input_t *)lfe);
|
||||
|
||||
/* Satconf */
|
||||
if (conf) {
|
||||
|
@ -1042,6 +1041,8 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
|
|||
if (lfe->lfe_fe_fd > 0)
|
||||
close(lfe->lfe_fe_fd);
|
||||
|
||||
mpegts_input_table_thread_stop((mpegts_input_t *)lfe);
|
||||
|
||||
/* Remove from adapter */
|
||||
LIST_REMOVE(lfe, lfe_link);
|
||||
|
||||
|
@ -1055,7 +1056,7 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
|
|||
linuxdvb_satconf_delete(lfe->lfe_satconf, 0);
|
||||
|
||||
/* Finish */
|
||||
mpegts_input_delete((mpegts_input_t*)lfe);
|
||||
mpegts_input_delete((mpegts_input_t*)lfe, 0);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* *************************************************************************/
|
||||
|
||||
static void
|
||||
linuxdvb_mux_delete ( mpegts_mux_t *mm );
|
||||
linuxdvb_mux_delete ( mpegts_mux_t *mm, int delconf );
|
||||
|
||||
extern const idclass_t mpegts_mux_class;
|
||||
|
||||
|
@ -611,15 +611,16 @@ linuxdvb_mux_create_instances ( mpegts_mux_t *mm )
|
|||
}
|
||||
|
||||
static void
|
||||
linuxdvb_mux_delete ( mpegts_mux_t *mm )
|
||||
linuxdvb_mux_delete ( mpegts_mux_t *mm, int delconf )
|
||||
{
|
||||
/* Remove config */
|
||||
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s",
|
||||
if (delconf)
|
||||
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s",
|
||||
idnode_uuid_as_str(&mm->mm_network->mn_id),
|
||||
idnode_uuid_as_str(&mm->mm_id));
|
||||
|
||||
/* Delete the mux */
|
||||
mpegts_mux_delete(mm);
|
||||
mpegts_mux_delete(mm, delconf);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
|
|
|
@ -51,7 +51,7 @@ linuxdvb_network_class_delete ( idnode_t *in )
|
|||
idnode_uuid_as_str(in));
|
||||
|
||||
/* Parent delete */
|
||||
mpegts_network_delete(mn);
|
||||
mpegts_network_delete(mn, 1);
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
@ -356,6 +356,13 @@ linuxdvb_network_builder
|
|||
return (mpegts_network_t*)linuxdvb_network_create0(NULL, idc, conf);
|
||||
}
|
||||
|
||||
static const idclass_t* linuxdvb_network_classes[] = {
|
||||
&linuxdvb_network_dvbt_class,
|
||||
&linuxdvb_network_dvbc_class,
|
||||
&linuxdvb_network_dvbs_class,
|
||||
&linuxdvb_network_atsc_class,
|
||||
};
|
||||
|
||||
void linuxdvb_network_init ( void )
|
||||
{
|
||||
htsmsg_t *c, *e;
|
||||
|
@ -363,16 +370,10 @@ void linuxdvb_network_init ( void )
|
|||
const char *s;
|
||||
int i;
|
||||
|
||||
const idclass_t* classes[] = {
|
||||
&linuxdvb_network_dvbt_class,
|
||||
&linuxdvb_network_dvbc_class,
|
||||
&linuxdvb_network_dvbs_class,
|
||||
&linuxdvb_network_atsc_class,
|
||||
};
|
||||
|
||||
/* Register class builders */
|
||||
for (i = 0; i < ARRAY_SIZE(classes); i++)
|
||||
mpegts_network_register_builder(classes[i], linuxdvb_network_builder);
|
||||
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++)
|
||||
mpegts_network_register_builder(linuxdvb_network_classes[i],
|
||||
linuxdvb_network_builder);
|
||||
|
||||
/* Load settings */
|
||||
if (!(c = hts_settings_load_r(1, "input/linuxdvb/networks")))
|
||||
|
@ -382,9 +383,9 @@ void linuxdvb_network_init ( void )
|
|||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
if (!(e = htsmsg_get_map(e, "config"))) continue;
|
||||
if (!(s = htsmsg_get_str(e, "class"))) continue;
|
||||
for (i = 0; i < ARRAY_SIZE(classes); i++) {
|
||||
if(!strcmp(classes[i]->ic_class, s)) {
|
||||
(void)linuxdvb_network_create0(f->hmf_name, classes[i], e);
|
||||
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++) {
|
||||
if(!strcmp(linuxdvb_network_classes[i]->ic_class, s)) {
|
||||
(void)linuxdvb_network_create0(f->hmf_name, linuxdvb_network_classes[i], e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -392,6 +393,19 @@ void linuxdvb_network_init ( void )
|
|||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
void linuxdvb_network_done ( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
/* Unregister class builders */
|
||||
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++) {
|
||||
mpegts_network_unregister_builder(linuxdvb_network_classes[i]);
|
||||
mpegts_network_class_delete(linuxdvb_network_classes[i], 0);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
/* ****************************************************************************
|
||||
* Search
|
||||
* ***************************************************************************/
|
||||
|
|
|
@ -207,6 +207,8 @@ struct linuxdvb_en50494
|
|||
|
||||
void linuxdvb_adapter_init ( void );
|
||||
|
||||
void linuxdvb_adapter_done ( void );
|
||||
|
||||
void linuxdvb_adapter_save ( linuxdvb_adapter_t *la );
|
||||
|
||||
int linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la );
|
||||
|
@ -245,6 +247,7 @@ struct linuxdvb_network
|
|||
};
|
||||
|
||||
void linuxdvb_network_init ( void );
|
||||
void linuxdvb_network_done ( void );
|
||||
linuxdvb_network_t *linuxdvb_network_find_by_uuid(const char *uuid);
|
||||
|
||||
linuxdvb_network_t *linuxdvb_network_create0
|
||||
|
|
|
@ -1096,7 +1096,7 @@ linuxdvb_satconf_ele_destroy ( linuxdvb_satconf_ele_t *ls )
|
|||
if (ls->ls_switch) linuxdvb_switch_destroy(ls->ls_switch);
|
||||
if (ls->ls_rotor) linuxdvb_rotor_destroy(ls->ls_rotor);
|
||||
if (ls->ls_en50494) linuxdvb_en50494_destroy(ls->ls_en50494);
|
||||
mpegts_input_delete((mpegts_input_t*)ls);
|
||||
mpegts_input_delete((mpegts_input_t*)ls, 1);
|
||||
}
|
||||
|
||||
linuxdvb_satconf_ele_t *
|
||||
|
@ -1171,8 +1171,10 @@ linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls, int delconf )
|
|||
linuxdvb_rotor_destroy(lse->ls_rotor);
|
||||
if (lse->ls_en50494)
|
||||
linuxdvb_en50494_destroy(lse->ls_en50494);
|
||||
mpegts_input_delete((mpegts_input_t*)lse);
|
||||
mpegts_input_delete((mpegts_input_t*)lse, delconf);
|
||||
}
|
||||
idnode_unlink(&ls->ls_id);
|
||||
free(ls);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -1228,6 +1230,7 @@ void
|
|||
linuxdvb_diseqc_destroy ( linuxdvb_diseqc_t *ld )
|
||||
{
|
||||
idnode_unlink(&ld->ld_id);
|
||||
free((void *)ld->ld_type);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -428,6 +428,43 @@ scanfile_init ( void )
|
|||
scanfile_load_dir(path, NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the mux list
|
||||
*/
|
||||
static void
|
||||
scanfile_done_region( scanfile_region_list_t *list )
|
||||
{
|
||||
scanfile_region_t *reg;
|
||||
scanfile_network_t *net;
|
||||
dvb_mux_conf_t *mux;
|
||||
|
||||
while ((reg = LIST_FIRST(list)) != NULL) {
|
||||
LIST_REMOVE(reg, sfr_link);
|
||||
while ((net = LIST_FIRST(®->sfr_networks)) != NULL) {
|
||||
LIST_REMOVE(net, sfn_link);
|
||||
while ((mux = LIST_FIRST(&net->sfn_muxes)) != NULL) {
|
||||
LIST_REMOVE(mux, dmc_link);
|
||||
free(mux);
|
||||
}
|
||||
free((void *)net->sfn_id);
|
||||
free((void *)net->sfn_name);
|
||||
free(net);
|
||||
}
|
||||
free((void *)reg->sfr_id);
|
||||
free((void *)reg->sfr_name);
|
||||
free(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scanfile_done ( void )
|
||||
{
|
||||
scanfile_done_region(&scanfile_regions_DVBS);
|
||||
scanfile_done_region(&scanfile_regions_DVBT);
|
||||
scanfile_done_region(&scanfile_regions_DVBC);
|
||||
scanfile_done_region(&scanfile_regions_ATSC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find scanfile
|
||||
*/
|
||||
|
|
|
@ -40,6 +40,7 @@ extern scanfile_region_list_t scanfile_regions_DVBS;
|
|||
extern scanfile_region_list_t scanfile_regions_ATSC;
|
||||
|
||||
void scanfile_init ( void );
|
||||
void scanfile_done ( void );
|
||||
|
||||
scanfile_network_t *scanfile_find ( const char *id );
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
|
||||
SKEL_DECLARE(mpegts_pid_sub_skel, mpegts_pid_sub_t);
|
||||
|
||||
|
||||
/* **************************************************************************
|
||||
* Class definition
|
||||
* *************************************************************************/
|
||||
|
@ -166,16 +169,14 @@ mpegts_input_open_pid
|
|||
mpegts_pid_t *mp;
|
||||
assert(owner != NULL);
|
||||
if ((mp = mpegts_mux_find_pid(mm, pid, 1))) {
|
||||
static mpegts_pid_sub_t *skel = NULL;
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(mpegts_pid_sub_t));
|
||||
skel->mps_type = type;
|
||||
skel->mps_owner = owner;
|
||||
if (!RB_INSERT_SORTED(&mp->mp_subs, skel, mps_link, mps_cmp)) {
|
||||
SKEL_ALLOC(mpegts_pid_sub_skel);
|
||||
mpegts_pid_sub_skel->mps_type = type;
|
||||
mpegts_pid_sub_skel->mps_owner = owner;
|
||||
if (!RB_INSERT_SORTED(&mp->mp_subs, mpegts_pid_sub_skel, mps_link, mps_cmp)) {
|
||||
mm->mm_display_name(mm, buf, sizeof(buf));
|
||||
tvhdebug("mpegts", "%s - open PID %04X (%d) [%d/%p]",
|
||||
buf, mp->mp_pid, mp->mp_pid, type, owner);
|
||||
skel = NULL;
|
||||
SKEL_USED(mpegts_pid_sub_skel);
|
||||
}
|
||||
}
|
||||
return mp;
|
||||
|
@ -486,30 +487,60 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, mpegts_table_feed_t *mtf )
|
|||
}
|
||||
}
|
||||
|
||||
void *
|
||||
static void *
|
||||
mpegts_input_table_thread ( void *aux )
|
||||
{
|
||||
mpegts_table_feed_t *mtf;
|
||||
mpegts_input_t *mi = aux;
|
||||
|
||||
while (1) {
|
||||
pthread_mutex_lock(&mi->mi_delivery_mutex);
|
||||
while (mi->mi_delivery_running) {
|
||||
|
||||
/* Wait for data */
|
||||
pthread_mutex_lock(&mi->mi_delivery_mutex);
|
||||
while(!(mtf = TAILQ_FIRST(&mi->mi_table_feed)))
|
||||
while(!(mtf = TAILQ_FIRST(&mi->mi_table_feed))) {
|
||||
if (!mi->mi_delivery_running)
|
||||
break;
|
||||
pthread_cond_wait(&mi->mi_table_feed_cond, &mi->mi_delivery_mutex);
|
||||
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
|
||||
pthread_mutex_unlock(&mi->mi_delivery_mutex);
|
||||
|
||||
}
|
||||
if (mtf)
|
||||
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
|
||||
|
||||
/* Process */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mpegts_input_table_dispatch(mtf->mtf_mux, mtf);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
if (mtf) {
|
||||
pthread_mutex_unlock(&mi->mi_delivery_mutex);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
mpegts_input_table_dispatch(mtf->mtf_mux, mtf);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
free(mtf);
|
||||
pthread_mutex_lock(&mi->mi_delivery_mutex);
|
||||
}
|
||||
}
|
||||
while ((mtf = TAILQ_FIRST(&mi->mi_table_feed)) != NULL) {
|
||||
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
|
||||
free(mtf);
|
||||
}
|
||||
pthread_mutex_unlock(&mi->mi_delivery_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_input_table_thread_start( mpegts_input_t *mi )
|
||||
{
|
||||
mi->mi_delivery_running = 1;
|
||||
tvhthread_create(&mi->mi_thread_table_id, NULL,
|
||||
mpegts_input_table_thread, mi, 0);
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_input_table_thread_stop( mpegts_input_t *mi )
|
||||
{
|
||||
pthread_mutex_lock(&mi->mi_delivery_mutex);
|
||||
mi->mi_delivery_running = 0;
|
||||
pthread_cond_signal(&mi->mi_table_feed_cond);
|
||||
pthread_mutex_unlock(&mi->mi_delivery_mutex);
|
||||
pthread_join(mi->mi_thread_table_id, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_input_flush_mux
|
||||
( mpegts_input_t *mi, mpegts_mux_t *mm )
|
||||
|
@ -667,14 +698,16 @@ mpegts_input_create0
|
|||
}
|
||||
|
||||
void
|
||||
mpegts_input_delete ( mpegts_input_t *mi )
|
||||
mpegts_input_delete ( mpegts_input_t *mi, int delconf )
|
||||
{
|
||||
mpegts_input_set_network(mi, NULL);
|
||||
idnode_unlink(&mi->ti_id);
|
||||
pthread_mutex_destroy(&mi->mi_delivery_mutex);
|
||||
pthread_cond_destroy(&mi->mi_table_feed_cond);
|
||||
tvh_pipe_close(&mi->mi_thread_pipe);
|
||||
LIST_REMOVE(mi, ti_link);
|
||||
LIST_REMOVE(mi, mi_global_link);
|
||||
free(mi->mi_name);
|
||||
free(mi);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
SKEL_DECLARE(mpegts_pid_skel, mpegts_pid_t);
|
||||
|
||||
static void
|
||||
mpegts_mux_initial_scan_timeout ( void *aux );
|
||||
static void
|
||||
|
@ -180,7 +182,7 @@ static void
|
|||
mpegts_mux_class_delete ( idnode_t *self )
|
||||
{
|
||||
mpegts_mux_t *mm = (mpegts_mux_t*)self;
|
||||
if (mm->mm_delete) mm->mm_delete(mm);
|
||||
if (mm->mm_delete) mm->mm_delete(mm, 1);
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
@ -330,7 +332,7 @@ mpegts_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len )
|
|||
}
|
||||
|
||||
void
|
||||
mpegts_mux_delete ( mpegts_mux_t *mm )
|
||||
mpegts_mux_delete ( mpegts_mux_t *mm, int delconf )
|
||||
{
|
||||
mpegts_mux_instance_t *mmi;
|
||||
mpegts_network_t *mn = mm->mm_network;
|
||||
|
@ -354,7 +356,7 @@ mpegts_mux_delete ( mpegts_mux_t *mm )
|
|||
|
||||
/* Delete services */
|
||||
while ((s = LIST_FIRST(&mm->mm_services))) {
|
||||
service_destroy((service_t*)s);
|
||||
service_destroy((service_t*)s, delconf);
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
|
@ -527,6 +529,7 @@ mpegts_mux_stop ( mpegts_mux_t *mm, int force )
|
|||
tvhtrace("mpegts", "%s - flush tables", buf);
|
||||
mpegts_table_flush_all(mm);
|
||||
|
||||
tvhtrace("mpegts", "%s - mi=%p", buf, (void *)mi);
|
||||
/* Flush table data queue */
|
||||
if (mi)
|
||||
mpegts_input_flush_mux(mi, mm);
|
||||
|
@ -905,14 +908,12 @@ mpegts_mux_find_pid ( mpegts_mux_t *mm, int pid, int create )
|
|||
skel.mp_pid = pid;
|
||||
mp = RB_FIND(&mm->mm_pids, &skel, mp_link, mp_cmp);
|
||||
} else {
|
||||
static mpegts_pid_t *skel = NULL;
|
||||
if (!skel)
|
||||
skel = calloc(1, sizeof(mpegts_pid_t));
|
||||
skel->mp_pid = pid;
|
||||
mp = RB_INSERT_SORTED(&mm->mm_pids, skel, mp_link, mp_cmp);
|
||||
SKEL_ALLOC(mpegts_pid_skel);
|
||||
mpegts_pid_skel->mp_pid = pid;
|
||||
mp = RB_INSERT_SORTED(&mm->mm_pids, mpegts_pid_skel, mp_link, mp_cmp);
|
||||
if (!mp) {
|
||||
mp = skel;
|
||||
skel = NULL;
|
||||
mp = mpegts_pid_skel;
|
||||
SKEL_USED(mpegts_pid_skel);
|
||||
mp->mp_fd = -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ mpegts_network_mux_create2
|
|||
|
||||
void
|
||||
mpegts_network_delete
|
||||
( mpegts_network_t *mn )
|
||||
( mpegts_network_t *mn, int delconf )
|
||||
{
|
||||
mpegts_input_t *mi;
|
||||
mpegts_mux_t *mm;
|
||||
|
@ -220,7 +220,7 @@ mpegts_network_delete
|
|||
|
||||
/* Delete all muxes */
|
||||
while ((mm = LIST_FIRST(&mn->mn_muxes))) {
|
||||
mm->mm_delete(mm);
|
||||
mm->mm_delete(mm, delconf);
|
||||
}
|
||||
|
||||
/* Check */
|
||||
|
@ -340,6 +340,18 @@ mpegts_network_create0
|
|||
return mn;
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_network_class_delete(const idclass_t *idc, int delconf)
|
||||
{
|
||||
mpegts_network_t *mn, *n;
|
||||
|
||||
for (mn = LIST_FIRST(&mpegts_network_all); mn != NULL; mn = n) {
|
||||
n = LIST_NEXT(mn, mn_global_link);
|
||||
if (mn->mn_id.in_class == idc)
|
||||
mpegts_network_delete(mn, delconf);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mpegts_network_set_nid
|
||||
( mpegts_network_t *mn, uint16_t nid )
|
||||
|
@ -384,6 +396,20 @@ mpegts_network_register_builder
|
|||
LIST_INSERT_HEAD(&mpegts_network_builders, mnb, link);
|
||||
}
|
||||
|
||||
void
|
||||
mpegts_network_unregister_builder
|
||||
( const idclass_t *idc )
|
||||
{
|
||||
mpegts_network_builder_t *mnb;
|
||||
LIST_FOREACH(mnb, &mpegts_network_builders, link) {
|
||||
if (mnb->idc == idc) {
|
||||
LIST_REMOVE(mnb, link);
|
||||
free(mnb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpegts_network_t *
|
||||
mpegts_network_build
|
||||
( const char *clazz, htsmsg_t *conf )
|
||||
|
|
|
@ -338,13 +338,14 @@ mpegts_service_provider_name ( service_t *s )
|
|||
}
|
||||
|
||||
void
|
||||
mpegts_service_delete ( service_t *t )
|
||||
mpegts_service_delete ( service_t *t, int delconf )
|
||||
{
|
||||
mpegts_service_t *ms = (mpegts_service_t*)t;
|
||||
mpegts_mux_t *mm = ms->s_dvb_mux;
|
||||
|
||||
/* Remove config */
|
||||
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s/services/%s",
|
||||
if (delconf)
|
||||
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s/services/%s",
|
||||
idnode_uuid_as_str(&mm->mm_network->mn_id),
|
||||
idnode_uuid_as_str(&mm->mm_id),
|
||||
idnode_uuid_as_str(&t->s_id));
|
||||
|
@ -354,6 +355,7 @@ mpegts_service_delete ( service_t *t )
|
|||
free(ms->s_dvb_provider);
|
||||
free(ms->s_dvb_charset);
|
||||
LIST_REMOVE(ms, s_dvb_mux_link);
|
||||
sbuf_free(&ms->s_tsbuf);
|
||||
|
||||
// Note: the ultimate deletion and removal from the idnode list
|
||||
// is done in service_destroy
|
||||
|
|
|
@ -240,7 +240,6 @@ tsfile_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *t )
|
|||
mpegts_input_t *
|
||||
tsfile_input_create ( int idx )
|
||||
{
|
||||
pthread_t tid;
|
||||
mpegts_input_t *mi;
|
||||
|
||||
/* Create object */
|
||||
|
@ -254,7 +253,7 @@ tsfile_input_create ( int idx )
|
|||
mi->mi_name = strdup("TSFile");
|
||||
|
||||
/* Start table thread */
|
||||
tvhthread_create(&tid, NULL, mpegts_input_table_thread, mi, 1);
|
||||
mpegts_input_table_thread_start(mi);
|
||||
return mi;
|
||||
}
|
||||
|
||||
|
|
|
@ -668,3 +668,22 @@ const lang_code_t **lang_code_split2 ( const char *codes )
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lang_code_free( lang_code_lookup_t *l )
|
||||
{
|
||||
lang_code_lookup_element_t *element;
|
||||
if (l == NULL)
|
||||
return;
|
||||
while ((element = RB_FIRST(l)) != NULL) {
|
||||
RB_REMOVE(l, element, link);
|
||||
free(element);
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
|
||||
void lang_code_done( void )
|
||||
{
|
||||
lang_code_free(lang_codes_code2b);
|
||||
lang_code_free(lang_codes_code1);
|
||||
lang_code_free(lang_codes_code2t);
|
||||
}
|
||||
|
|
|
@ -48,4 +48,6 @@ typedef struct lang_code_lookup_element {
|
|||
|
||||
typedef RB_HEAD(lang_code_lookup, lang_code_lookup_element) lang_code_lookup_t;
|
||||
|
||||
void lang_code_done( void );
|
||||
|
||||
#endif /* __TVH_LANG_CODES_H__ */
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "redblack.h"
|
||||
#include "lang_codes.h"
|
||||
#include "lang_str.h"
|
||||
#include "tvheadend.h"
|
||||
|
||||
SKEL_DECLARE(lang_str_ele_skel, lang_str_ele_t);
|
||||
|
||||
/* ************************************************************************
|
||||
* Support
|
||||
|
@ -107,7 +110,6 @@ static int _lang_str_add
|
|||
( lang_str_t *ls, const char *str, const char *lang, int update, int append )
|
||||
{
|
||||
int save = 0;
|
||||
static lang_str_ele_t *skel = NULL;
|
||||
lang_str_ele_t *e;
|
||||
|
||||
if (!str) return 0;
|
||||
|
@ -116,14 +118,14 @@ static int _lang_str_add
|
|||
if (!(lang = lang_code_get(lang))) return 0;
|
||||
|
||||
/* Create skel */
|
||||
if (!skel) skel = calloc(1, sizeof(lang_str_ele_t));
|
||||
skel->lang = lang;
|
||||
SKEL_ALLOC(lang_str_ele_skel);
|
||||
lang_str_ele_skel->lang = lang;
|
||||
|
||||
/* Create */
|
||||
e = RB_INSERT_SORTED(ls, skel, link, _lang_cmp);
|
||||
e = RB_INSERT_SORTED(ls, lang_str_ele_skel, link, _lang_cmp);
|
||||
if (!e) {
|
||||
skel->str = strdup(str);
|
||||
skel = NULL;
|
||||
lang_str_ele_skel->str = strdup(str);
|
||||
SKEL_USED(lang_str_ele_skel);
|
||||
save = 1;
|
||||
|
||||
/* Append */
|
||||
|
@ -189,3 +191,8 @@ lang_str_t *lang_str_deserialize ( htsmsg_t *m, const char *n )
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lang_str_done( void )
|
||||
{
|
||||
SKEL_FREE(lang_str_ele_skel);
|
||||
}
|
||||
|
|
|
@ -52,4 +52,7 @@ void lang_str_serialize
|
|||
lang_str_t *lang_str_deserialize
|
||||
( htsmsg_t *m, const char *f );
|
||||
|
||||
/* Init/Done */
|
||||
void lang_str_done( void );
|
||||
|
||||
#endif /* __TVH_LANG_STR_H__ */
|
||||
|
|
54
src/main.c
54
src/main.c
|
@ -59,6 +59,7 @@
|
|||
#include "imagecache.h"
|
||||
#include "timeshift.h"
|
||||
#include "fsmonitor.h"
|
||||
#include "lang_codes.h"
|
||||
#if ENABLE_LIBAV
|
||||
#include "libav.h"
|
||||
#include "plumbing/transcoding.h"
|
||||
|
@ -68,6 +69,8 @@
|
|||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
pthread_t main_tid;
|
||||
|
||||
/* Command line option struct */
|
||||
typedef struct str_list
|
||||
{
|
||||
|
@ -169,10 +172,14 @@ handle_sigpipe(int x)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
doexit(int x)
|
||||
{
|
||||
if (pthread_self() != main_tid)
|
||||
pthread_kill(main_tid, SIGTERM);
|
||||
pthread_cond_signal(>imer_cond);
|
||||
tvheadend_running = 0;
|
||||
signal(x, doexit);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -424,6 +431,8 @@ main(int argc, char **argv)
|
|||
const char *log_debug = NULL, *log_trace = NULL;
|
||||
char buf[512];
|
||||
|
||||
main_tid = pthread_self();
|
||||
|
||||
/* Setup global mutexes */
|
||||
pthread_mutex_init(&ffmpeg_lock, NULL);
|
||||
pthread_mutex_init(&fork_lock, NULL);
|
||||
|
@ -704,6 +713,8 @@ main(int argc, char **argv)
|
|||
umask(0);
|
||||
}
|
||||
|
||||
tvheadend_running = 1;
|
||||
|
||||
/* Start log thread (must be done post fork) */
|
||||
tvhlog_start();
|
||||
|
||||
|
@ -789,9 +800,7 @@ main(int argc, char **argv)
|
|||
if(opt_subscribe != NULL)
|
||||
subscription_dummy_join(opt_subscribe, 1);
|
||||
|
||||
#ifdef CONFIG_AVAHI
|
||||
avahi_init();
|
||||
#endif
|
||||
|
||||
epg_updated(); // cleanup now all prev ref's should have been created
|
||||
|
||||
|
@ -801,7 +810,6 @@ main(int argc, char **argv)
|
|||
* Wait for SIGTERM / SIGINT, but only in this thread
|
||||
*/
|
||||
|
||||
tvheadend_running = 1;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGTERM);
|
||||
sigaddset(&set, SIGINT);
|
||||
|
@ -822,21 +830,55 @@ main(int argc, char **argv)
|
|||
|
||||
mainloop();
|
||||
|
||||
tvhftrace("main", htsp_done);
|
||||
tvhftrace("main", http_server_done);
|
||||
tvhftrace("main", webui_done);
|
||||
tvhftrace("main", http_client_done);
|
||||
tvhftrace("main", fsmonitor_done);
|
||||
#if ENABLE_IPTV
|
||||
tvhftrace("main", iptv_done);
|
||||
#endif
|
||||
#if ENABLE_LINUXDVB
|
||||
tvhftrace("main", linuxdvb_done);
|
||||
#endif
|
||||
|
||||
// Note: the locking is obviously a bit redundant, but without
|
||||
// we need to disable the gtimer_arm call in epg_save()
|
||||
pthread_mutex_lock(&global_lock);
|
||||
epg_save(NULL);
|
||||
tvhftrace("main", epg_save);
|
||||
|
||||
#if ENABLE_TIMESHIFT
|
||||
timeshift_term();
|
||||
tvhftrace("main", timeshift_term);
|
||||
#endif
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
tvhftrace("main", epggrab_done);
|
||||
tvhftrace("main", tcp_server_done);
|
||||
tvhftrace("main", subscription_done);
|
||||
tvhftrace("main", descrambler_done);
|
||||
tvhftrace("main", service_mapper_done);
|
||||
tvhftrace("main", service_done);
|
||||
tvhftrace("main", channel_done);
|
||||
tvhftrace("main", dvr_done);
|
||||
tvhftrace("main", access_done);
|
||||
tvhftrace("main", epg_done);
|
||||
tvhftrace("main", avahi_done);
|
||||
tvhftrace("main", imagecache_done);
|
||||
tvhftrace("main", idnode_done);
|
||||
tvhftrace("main", lang_code_done);
|
||||
tvhftrace("main", api_done);
|
||||
tvhftrace("main", config_done);
|
||||
tvhftrace("main", hts_settings_done);
|
||||
tvhftrace("main", dvb_done);
|
||||
tvhftrace("main", lang_str_done);
|
||||
|
||||
tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
|
||||
tvhlog_end();
|
||||
|
||||
if(opt_fork)
|
||||
unlink(opt_pidpath);
|
||||
|
||||
free(opt_tsfile.str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -239,6 +239,8 @@ stream_clean(elementary_stream_t *st)
|
|||
void
|
||||
service_stream_destroy(service_t *t, elementary_stream_t *es)
|
||||
{
|
||||
caid_t *c;
|
||||
|
||||
if(t->s_status == SERVICE_RUNNING)
|
||||
stream_clean(es);
|
||||
|
||||
|
@ -246,6 +248,12 @@ service_stream_destroy(service_t *t, elementary_stream_t *es)
|
|||
avgstat_flush(&es->es_cc_errors);
|
||||
|
||||
TAILQ_REMOVE(&t->s_components, es, es_link);
|
||||
|
||||
while ((c = LIST_FIRST(&es->es_caids)) != NULL) {
|
||||
LIST_REMOVE(c, link);
|
||||
free(c);
|
||||
}
|
||||
|
||||
free(es->es_section);
|
||||
free(es->es_nicename);
|
||||
free(es);
|
||||
|
@ -441,8 +449,10 @@ service_find_instance
|
|||
void
|
||||
service_unref(service_t *t)
|
||||
{
|
||||
if((atomic_add(&t->s_refcount, -1)) == 1)
|
||||
if((atomic_add(&t->s_refcount, -1)) == 1) {
|
||||
free(t->s_nicename);
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -461,14 +471,14 @@ service_ref(service_t *t)
|
|||
* Destroy a service
|
||||
*/
|
||||
void
|
||||
service_destroy(service_t *t)
|
||||
service_destroy(service_t *t, int delconf)
|
||||
{
|
||||
elementary_stream_t *st;
|
||||
th_subscription_t *s;
|
||||
channel_service_mapping_t *csm;
|
||||
|
||||
if(t->s_delete != NULL)
|
||||
t->s_delete(t);
|
||||
t->s_delete(t, delconf);
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
|
@ -964,7 +974,7 @@ service_saver(void *aux)
|
|||
int restart;
|
||||
pthread_mutex_lock(&pending_save_mutex);
|
||||
|
||||
while(1) {
|
||||
while(tvheadend_running) {
|
||||
|
||||
if((t = TAILQ_FIRST(&pending_save_queue)) == NULL) {
|
||||
pthread_cond_wait(&pending_save_cond, &pending_save_mutex);
|
||||
|
@ -996,17 +1006,24 @@ service_saver(void *aux)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
pthread_t service_saver_tid;
|
||||
|
||||
void
|
||||
service_init(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
TAILQ_INIT(&pending_save_queue);
|
||||
TAILQ_INIT(&service_all);
|
||||
pthread_mutex_init(&pending_save_mutex, NULL);
|
||||
pthread_cond_init(&pending_save_cond, NULL);
|
||||
tvhthread_create(&tid, NULL, service_saver, NULL, 1);
|
||||
tvhthread_create(&service_saver_tid, NULL, service_saver, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
service_done(void)
|
||||
{
|
||||
pthread_cond_signal(&pending_save_cond);
|
||||
pthread_join(service_saver_tid, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -283,7 +283,7 @@ typedef struct service {
|
|||
|
||||
int (*s_grace_period)(struct service *t);
|
||||
|
||||
void (*s_delete)(struct service *t);
|
||||
void (*s_delete)(struct service *t, int delconf);
|
||||
|
||||
/**
|
||||
* Channel info
|
||||
|
@ -426,6 +426,7 @@ typedef struct service {
|
|||
|
||||
|
||||
void service_init(void);
|
||||
void service_done(void);
|
||||
|
||||
int service_start(service_t *t, int instance);
|
||||
|
||||
|
@ -466,7 +467,7 @@ int service_is_other(service_t *t);
|
|||
|
||||
int service_is_encrypted ( service_t *t );
|
||||
|
||||
void service_destroy(service_t *t);
|
||||
void service_destroy(service_t *t, int delconf);
|
||||
|
||||
void service_remove_subscriber(service_t *t, struct th_subscription *s,
|
||||
int reason);
|
||||
|
|
|
@ -44,13 +44,21 @@ static void *service_mapper_thread ( void *p );
|
|||
/**
|
||||
* Initialise
|
||||
*/
|
||||
pthread_t service_mapper_tid;
|
||||
|
||||
void
|
||||
service_mapper_init ( void )
|
||||
{
|
||||
pthread_t tid;
|
||||
TAILQ_INIT(&service_mapper_queue);
|
||||
pthread_cond_init(&service_mapper_cond, NULL);
|
||||
tvhthread_create(&tid, NULL, service_mapper_thread, NULL, 1);
|
||||
tvhthread_create(&service_mapper_tid, NULL, service_mapper_thread, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
service_mapper_done ( void )
|
||||
{
|
||||
pthread_cond_signal(&service_mapper_cond);
|
||||
pthread_join(service_mapper_tid, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -289,7 +297,7 @@ service_mapper_thread ( void *aux )
|
|||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
while (1) {
|
||||
while (tvheadend_running) {
|
||||
|
||||
/* Wait for work */
|
||||
while (!(s = TAILQ_FIRST(&service_mapper_queue))) {
|
||||
|
@ -298,7 +306,11 @@ service_mapper_thread ( void *aux )
|
|||
tvhinfo("service_mapper", "idle");
|
||||
}
|
||||
pthread_cond_wait(&service_mapper_cond, &global_lock);
|
||||
if (!tvheadend_running)
|
||||
break;
|
||||
}
|
||||
if (!tvheadend_running)
|
||||
break;
|
||||
service_mapper_remove(s);
|
||||
|
||||
if (!working) {
|
||||
|
@ -327,11 +339,17 @@ service_mapper_thread ( void *aux )
|
|||
/* Wait */
|
||||
run = 1;
|
||||
pthread_mutex_lock(&sq.sq_mutex);
|
||||
while(run) {
|
||||
while(tvheadend_running && run) {
|
||||
|
||||
/* Wait for message */
|
||||
while((sm = TAILQ_FIRST(&sq.sq_queue)) == NULL)
|
||||
while((sm = TAILQ_FIRST(&sq.sq_queue)) == NULL) {
|
||||
pthread_cond_wait(&sq.sq_cond, &sq.sq_mutex);
|
||||
if (!tvheadend_running)
|
||||
break;
|
||||
}
|
||||
if (!tvheadend_running)
|
||||
break;
|
||||
|
||||
TAILQ_REMOVE(&sq.sq_queue, sm, sm_link);
|
||||
pthread_mutex_unlock(&sq.sq_mutex);
|
||||
|
||||
|
@ -353,6 +371,8 @@ service_mapper_thread ( void *aux )
|
|||
streaming_msg_free(sm);
|
||||
pthread_mutex_lock(&sq.sq_mutex);
|
||||
}
|
||||
if (!tvheadend_running)
|
||||
break;
|
||||
|
||||
streaming_queue_clear(&sq.sq_queue);
|
||||
pthread_mutex_unlock(&sq.sq_mutex);
|
||||
|
@ -370,5 +390,7 @@ service_mapper_thread ( void *aux )
|
|||
service_mapper_stat.active = NULL;
|
||||
api_service_mapper_notify();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ typedef struct service_mapper_status
|
|||
} service_mapper_status_t;
|
||||
|
||||
void service_mapper_init ( void );
|
||||
void service_mapper_done ( void );
|
||||
|
||||
// Start new mapping
|
||||
void service_mapper_start
|
||||
|
|
|
@ -77,6 +77,15 @@ hts_settings_init(const char *confpath)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
hts_settings_done(void)
|
||||
{
|
||||
free(settingspath);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
void hts_settings_init(const char *confpath);
|
||||
|
||||
void hts_settings_done(void);
|
||||
|
||||
void hts_settings_save(htsmsg_t *record, const char *pathfmt, ...);
|
||||
|
||||
htsmsg_t *hts_settings_load(const char *pathfmt, ...);
|
||||
|
|
|
@ -403,6 +403,9 @@ subscription_unsubscribe(th_subscription_t *s)
|
|||
|
||||
if(s->ths_start_message != NULL)
|
||||
streaming_msg_free(s->ths_start_message);
|
||||
|
||||
if(s->ths_output->st_cb == subscription_input_null)
|
||||
free(s->ths_output);
|
||||
|
||||
free(s->ths_title);
|
||||
free(s->ths_hostname);
|
||||
|
@ -754,6 +757,20 @@ subscription_init(void)
|
|||
subscription_status_callback(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown subsystem
|
||||
*/
|
||||
void
|
||||
subscription_done(void)
|
||||
{
|
||||
th_subscription_t *s;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((s = LIST_FIRST(&subscriptions)) != NULL)
|
||||
subscription_unsubscribe(s);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Subscription control
|
||||
* *************************************************************************/
|
||||
|
|
|
@ -100,6 +100,8 @@ typedef struct th_subscription {
|
|||
*/
|
||||
void subscription_init(void);
|
||||
|
||||
void subscription_done(void);
|
||||
|
||||
void subscription_unsubscribe(th_subscription_t *s);
|
||||
|
||||
void subscription_set_weight(th_subscription_t *s, unsigned int weight);
|
||||
|
|
94
src/tcp.c
94
src/tcp.c
|
@ -29,6 +29,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -40,6 +41,8 @@
|
|||
#include "notify.h"
|
||||
|
||||
int tcp_preferred_address_family = AF_INET;
|
||||
int tcp_server_running;
|
||||
th_pipe_t tcp_server_pipe;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -330,6 +333,11 @@ tcp_read_timeout(int fd, void *buf, size_t len, int timeout)
|
|||
x = poll(&fds, 1, timeout);
|
||||
if(x == 0)
|
||||
return ETIMEDOUT;
|
||||
if(x == -1) {
|
||||
if (errno == EAGAIN)
|
||||
continue;
|
||||
return errno;
|
||||
}
|
||||
|
||||
x = recv(fd, buf + tot, len - tot, MSG_DONTWAIT);
|
||||
if(x == -1) {
|
||||
|
@ -385,6 +393,7 @@ typedef struct tcp_server {
|
|||
} tcp_server_t;
|
||||
|
||||
typedef struct tcp_server_launch {
|
||||
pthread_t tid;
|
||||
int fd;
|
||||
tcp_server_ops_t ops;
|
||||
void *opaque;
|
||||
|
@ -392,9 +401,11 @@ typedef struct tcp_server_launch {
|
|||
struct sockaddr_storage self;
|
||||
time_t started;
|
||||
LIST_ENTRY(tcp_server_launch) link;
|
||||
LIST_ENTRY(tcp_server_launch) alink;
|
||||
} tcp_server_launch_t;
|
||||
|
||||
static LIST_HEAD(, tcp_server_launch) tcp_server_launches = { 0 };
|
||||
static LIST_HEAD(, tcp_server_launch) tcp_server_active = { 0 };
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -448,6 +459,7 @@ tcp_server_start(void *aux)
|
|||
LIST_REMOVE(tsl, link);
|
||||
notify_reload("connections");
|
||||
}
|
||||
LIST_REMOVE(tsl, alink);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
free(tsl);
|
||||
|
@ -465,14 +477,9 @@ tcp_server_loop(void *aux)
|
|||
tvhpoll_event_t ev;
|
||||
tcp_server_t *ts;
|
||||
tcp_server_launch_t *tsl;
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
socklen_t slen;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
while(1) {
|
||||
while(tcp_server_running) {
|
||||
r = tvhpoll_wait(tcp_server_poll, &ev, 1, -1);
|
||||
if(r == -1) {
|
||||
perror("tcp_server: tvhpoll_wait");
|
||||
|
@ -482,6 +489,8 @@ tcp_server_loop(void *aux)
|
|||
if (r == 0) continue;
|
||||
|
||||
ts = ev.data.ptr;
|
||||
if (ts == (tcp_server_t *)&tcp_server_pipe)
|
||||
break;
|
||||
|
||||
if(ev.events & TVHPOLL_HUP) {
|
||||
close(ts->serverfd);
|
||||
|
@ -511,9 +520,13 @@ tcp_server_loop(void *aux)
|
|||
continue;
|
||||
}
|
||||
|
||||
tvhthread_create(&tid, &attr, tcp_server_start, tsl, 1);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_INSERT_HEAD(&tcp_server_active, tsl, alink);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
tvhthread_create(&tsl->tid, NULL, tcp_server_start, tsl, 0);
|
||||
}
|
||||
}
|
||||
tvhtrace("tcp", "server thread finished");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -600,6 +613,23 @@ tcp_server_create
|
|||
return ts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
tcp_server_delete(void *server)
|
||||
{
|
||||
tcp_server_t *ts = server;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.fd = ts->serverfd;
|
||||
ev.events = TVHPOLL_IN;
|
||||
ev.data.ptr = ts;
|
||||
tvhpoll_rem(tcp_server_poll, &ev, 1);
|
||||
free(ts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Connections status
|
||||
*/
|
||||
|
@ -635,14 +665,58 @@ tcp_server_connections ( void )
|
|||
/**
|
||||
*
|
||||
*/
|
||||
pthread_t tcp_server_tid;
|
||||
|
||||
void
|
||||
tcp_server_init(int opt_ipv6)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
tvhpoll_event_t ev;
|
||||
if(opt_ipv6)
|
||||
tcp_preferred_address_family = AF_INET6;
|
||||
|
||||
tvh_pipe(O_NONBLOCK, &tcp_server_pipe);
|
||||
tcp_server_poll = tvhpoll_create(10);
|
||||
tvhthread_create(&tid, NULL, tcp_server_loop, NULL, 1);
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.fd = tcp_server_pipe.rd;
|
||||
ev.events = TVHPOLL_IN;
|
||||
ev.data.ptr = &tcp_server_pipe;
|
||||
tvhpoll_add(tcp_server_poll, &ev, 1);
|
||||
|
||||
tcp_server_running = 1;
|
||||
tvhthread_create(&tcp_server_tid, NULL, tcp_server_loop, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_server_done(void)
|
||||
{
|
||||
pthread_t tid;
|
||||
tcp_server_launch_t *tsl;
|
||||
char c = 'E';
|
||||
|
||||
tcp_server_running = 0;
|
||||
tvh_write(tcp_server_pipe.wr, &c, 1);
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
LIST_FOREACH(tsl, &tcp_server_active, alink) {
|
||||
if (tsl->ops.cancel)
|
||||
tsl->ops.cancel(tsl->opaque);
|
||||
close(tsl->fd);
|
||||
tsl->fd = -1;
|
||||
pthread_kill(tsl->tid, SIGTERM);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
pthread_join(tcp_server_tid, NULL);
|
||||
tvh_pipe_close(&tcp_server_pipe);
|
||||
tvhpoll_destroy(tcp_server_poll);
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
while ((tsl = LIST_FIRST(&tcp_server_active)) != NULL) {
|
||||
tid = tsl->tid;
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
pthread_join(tid, NULL);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
|
|
@ -29,11 +29,13 @@ typedef struct tcp_server_ops
|
|||
struct sockaddr_storage *self);
|
||||
void (*stop) (void *opaque);
|
||||
void (*status) (void *opaque, htsmsg_t *m);
|
||||
void (*cancel) (void *opaque);
|
||||
} tcp_server_ops_t;
|
||||
|
||||
extern int tcp_preferred_address_family;
|
||||
|
||||
void tcp_server_init(int opt_ipv6);
|
||||
void tcp_server_done(void);
|
||||
|
||||
int tcp_connect(const char *hostname, int port, char *errbuf,
|
||||
size_t errbufsize, int timeout);
|
||||
|
@ -45,6 +47,8 @@ typedef void (tcp_server_callback_t)(int fd, void *opaque,
|
|||
void *tcp_server_create(const char *bindaddr, int port,
|
||||
tcp_server_ops_t *ops, void *opaque);
|
||||
|
||||
void tcp_server_delete(void *server);
|
||||
|
||||
int tcp_read(int fd, void *buf, size_t len);
|
||||
|
||||
char *tcp_read_line(int fd, htsbuf_queue_t *spill);
|
||||
|
|
|
@ -70,6 +70,8 @@ static inline htsmsg_t *tvheadend_capabilities_list(int check)
|
|||
|
||||
#define PTS_UNSET INT64_C(0x8000000000000000)
|
||||
|
||||
extern int tvheadend_running;
|
||||
|
||||
extern pthread_mutex_t global_lock;
|
||||
extern pthread_mutex_t ffmpeg_lock;
|
||||
extern pthread_mutex_t fork_lock;
|
||||
|
@ -540,6 +542,8 @@ static inline void mystrset(char **p, const char *s)
|
|||
*p = s ? strdup(s) : NULL;
|
||||
}
|
||||
|
||||
void doexit(int x);
|
||||
|
||||
int tvhthread_create0
|
||||
(pthread_t *thread, const pthread_attr_t *attr,
|
||||
void *(*start_routine) (void *), void *arg,
|
||||
|
@ -604,6 +608,11 @@ int rmtree ( const char *path );
|
|||
|
||||
char *regexp_escape ( const char *str );
|
||||
|
||||
#define SKEL_DECLARE(name, type) type *name;
|
||||
#define SKEL_ALLOC(name) do { if (!name) name = calloc(1, sizeof(*name)); } while (0)
|
||||
#define SKEL_USED(name) do { name = NULL; } while (0)
|
||||
#define SKEL_FREE(name) do { free(name); name = NULL; } while (0)
|
||||
|
||||
/* glibc wrapper */
|
||||
#if ! ENABLE_QSORT_R
|
||||
void
|
||||
|
|
14
src/tvhlog.c
14
src/tvhlog.c
|
@ -224,7 +224,7 @@ tvhlog_thread ( void *p )
|
|||
|
||||
/* Wait */
|
||||
if (!(msg = TAILQ_FIRST(&tvhlog_queue))) {
|
||||
if (tvhlog_run != 1) break;
|
||||
if (!tvhlog_run) break;
|
||||
if (fp) {
|
||||
fclose(fp); // only issue here is we close with mutex!
|
||||
// but overall performance will be higher
|
||||
|
@ -233,6 +233,7 @@ tvhlog_thread ( void *p )
|
|||
pthread_cond_wait(&tvhlog_cond, &tvhlog_mutex);
|
||||
continue;
|
||||
}
|
||||
if (!msg) break;
|
||||
TAILQ_REMOVE(&tvhlog_queue, msg, link);
|
||||
tvhlog_queue_size--;
|
||||
if (tvhlog_queue_size < (TVHLOG_QUEUE_MAXSIZE / 2))
|
||||
|
@ -252,7 +253,9 @@ tvhlog_thread ( void *p )
|
|||
tvhlog_process(msg, options, &fp, path);
|
||||
pthread_mutex_lock(&tvhlog_mutex);
|
||||
}
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
pthread_mutex_unlock(&tvhlog_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -420,15 +423,18 @@ void
|
|||
tvhlog_start ( void )
|
||||
{
|
||||
tvhlog_run = 1;
|
||||
tvhthread_create(&tvhlog_tid, NULL, tvhlog_thread, NULL, 1);
|
||||
tvhthread_create(&tvhlog_tid, NULL, tvhlog_thread, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tvhlog_end ( void )
|
||||
{
|
||||
pthread_mutex_lock(&tvhlog_mutex);
|
||||
tvhlog_run = 2;
|
||||
tvhlog_run = 0;
|
||||
pthread_cond_signal(&tvhlog_cond);
|
||||
pthread_mutex_unlock(&tvhlog_mutex);
|
||||
pthread_join(tvhlog_tid, NULL);
|
||||
free(tvhlog_path);
|
||||
htsmsg_destroy(tvhlog_debug);
|
||||
htsmsg_destroy(tvhlog_trace);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,12 @@ void _tvhlog_hexdump ( const char *file, int line,
|
|||
#define tvhlog_hexdump(...) (void)0
|
||||
#endif
|
||||
|
||||
#define tvhftrace(subsys, fcn) do { \
|
||||
tvhtrace(subsys, "%s() enter", #fcn); \
|
||||
fcn(); \
|
||||
tvhtrace(subsys, "%s() leave", #fcn); \
|
||||
} while (0)
|
||||
|
||||
#define tvhdebug(...) tvhlog(LOG_DEBUG, ##__VA_ARGS__)
|
||||
#define tvhinfo(...) tvhlog(LOG_INFO, ##__VA_ARGS__)
|
||||
#define tvhwarn(...) tvhlog(LOG_WARNING, ##__VA_ARGS__)
|
||||
|
|
|
@ -48,6 +48,7 @@ static pthread_cond_t comet_cond = PTHREAD_COND_INITIALIZER;
|
|||
static LIST_HEAD(, comet_mailbox) mailboxes;
|
||||
|
||||
int mailbox_tally;
|
||||
int comet_running;
|
||||
|
||||
typedef struct comet_mailbox {
|
||||
char *cmb_boxid; /* SHA-1 hash */
|
||||
|
@ -198,6 +199,10 @@ comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
|
|||
usleep(100000); /* Always sleep 0.1 sec to avoid comet storms */
|
||||
|
||||
pthread_mutex_lock(&comet_mutex);
|
||||
if (!comet_running) {
|
||||
pthread_mutex_unlock(&comet_mutex);
|
||||
return 400;
|
||||
}
|
||||
|
||||
if(cometid != NULL)
|
||||
LIST_FOREACH(cmb, &mailboxes, cmb_link)
|
||||
|
@ -216,8 +221,13 @@ comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
|
|||
|
||||
cmb->cmb_last_used = 0; /* Make sure we're not flushed out */
|
||||
|
||||
if(!im && cmb->cmb_messages == NULL)
|
||||
if(!im && cmb->cmb_messages == NULL) {
|
||||
pthread_cond_timedwait(&comet_cond, &comet_mutex, &ts);
|
||||
if (!comet_running) {
|
||||
pthread_mutex_unlock(&comet_mutex);
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "boxid", cmb->cmb_boxid);
|
||||
|
@ -279,10 +289,24 @@ comet_mailbox_dbg(http_connection_t *hc, const char *remain, void *opaque)
|
|||
void
|
||||
comet_init(void)
|
||||
{
|
||||
pthread_mutex_lock(&comet_mutex);
|
||||
comet_running = 1;
|
||||
pthread_mutex_unlock(&comet_mutex);
|
||||
http_path_add("/comet/poll", NULL, comet_mailbox_poll, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/comet/debug", NULL, comet_mailbox_dbg, ACCESS_WEB_INTERFACE);
|
||||
}
|
||||
|
||||
void
|
||||
comet_done(void)
|
||||
{
|
||||
comet_mailbox_t *cmb;
|
||||
|
||||
pthread_mutex_lock(&comet_mutex);
|
||||
comet_running = 0;
|
||||
while ((cmb = LIST_FIRST(&mailboxes)) != NULL)
|
||||
cmb_destroy(cmb);
|
||||
pthread_mutex_unlock(&comet_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -294,14 +318,16 @@ comet_mailbox_add_message(htsmsg_t *m, int isdebug)
|
|||
|
||||
pthread_mutex_lock(&comet_mutex);
|
||||
|
||||
LIST_FOREACH(cmb, &mailboxes, cmb_link) {
|
||||
if (comet_running) {
|
||||
LIST_FOREACH(cmb, &mailboxes, cmb_link) {
|
||||
|
||||
if(isdebug && !cmb->cmb_debug)
|
||||
continue;
|
||||
if(isdebug && !cmb->cmb_debug)
|
||||
continue;
|
||||
|
||||
if(cmb->cmb_messages == NULL)
|
||||
cmb->cmb_messages = htsmsg_create_list();
|
||||
htsmsg_add_msg(cmb->cmb_messages, NULL, htsmsg_copy(m));
|
||||
if(cmb->cmb_messages == NULL)
|
||||
cmb->cmb_messages = htsmsg_create_list();
|
||||
htsmsg_add_msg(cmb->cmb_messages, NULL, htsmsg_copy(m));
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cond_broadcast(&comet_cond);
|
||||
|
|
|
@ -1360,7 +1360,7 @@ extjs_service_delete(htsmsg_t *in)
|
|||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((id = htsmsg_field_get_string(f)) != NULL &&
|
||||
(t = service_find_by_identifier(id)) != NULL)
|
||||
service_destroy(t);
|
||||
service_destroy(t, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -484,7 +484,7 @@ page_epgsave(http_connection_t *hc,
|
|||
"<epgflush>1</epgflush>\n");
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
epg_save(NULL);
|
||||
epg_save();
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
http_output_content(hc, "text/xml");
|
||||
|
|
|
@ -241,7 +241,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
tp.tv_usec = 0;
|
||||
setsockopt(hc->hc_fd, SOL_SOCKET, SO_SNDTIMEO, &tp, sizeof(tp));
|
||||
|
||||
while(run) {
|
||||
while(run && tvheadend_running) {
|
||||
pthread_mutex_lock(&sq->sq_mutex);
|
||||
sm = TAILQ_FIRST(&sq->sq_queue);
|
||||
if(sm == NULL) {
|
||||
|
@ -1081,7 +1081,7 @@ page_imagecache(http_connection_t *hc, const char *remain, void *opaque)
|
|||
static void
|
||||
webui_static_content(const char *http_path, const char *source)
|
||||
{
|
||||
http_path_add(http_path, strdup(source), page_static_file,
|
||||
http_path_add(http_path, (void *)source, page_static_file,
|
||||
ACCESS_WEB_INTERFACE);
|
||||
}
|
||||
|
||||
|
@ -1130,3 +1130,9 @@ webui_init(void)
|
|||
webui_api_init();
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
webui_done(void)
|
||||
{
|
||||
comet_done();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "http.h"
|
||||
|
||||
void webui_init(void);
|
||||
void webui_done(void);
|
||||
|
||||
void simpleui_start(void);
|
||||
|
||||
|
@ -54,6 +55,8 @@ void webui_api_init ( void );
|
|||
*/
|
||||
void comet_init(void);
|
||||
|
||||
void comet_done(void);
|
||||
|
||||
void comet_mailbox_add_message(htsmsg_t *m, int isdebug);
|
||||
|
||||
void comet_flush(void);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <sys/types.h> /* See NOTES */
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
|
@ -100,6 +101,7 @@ static void *
|
|||
thread_wrapper ( void *p )
|
||||
{
|
||||
struct thread_state *ts = p;
|
||||
sigset_t set;
|
||||
|
||||
#if defined(PLATFORM_LINUX)
|
||||
/* Set name */
|
||||
|
@ -109,6 +111,12 @@ thread_wrapper ( void *p )
|
|||
pthread_set_name_np(pthread_self(), ts->name);
|
||||
#endif
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGTERM);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
|
||||
signal(SIGTERM, doexit);
|
||||
|
||||
/* Run */
|
||||
tvhdebug("thread", "created thread %ld [%s / %p(%p)]",
|
||||
(long)pthread_self(), ts->name, ts->run, ts->arg);
|
||||
|
|
Loading…
Add table
Reference in a new issue