1 /*
2  * mptsd output PSI handling
3  * Copyright (C) 2010-2011 Unix Solutions Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
17  */
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <signal.h>
21 
22 #include "libfuncs/log.h"
23 #include "libfuncs/list.h"
24 
25 #include "libtsfuncs/tsfuncs.h"
26 
27 #include "config.h"
28 #include "data.h"
29 
output_psi_init_pat(CONFIG * conf,OUTPUT * o)30 static void output_psi_init_pat(CONFIG *conf, OUTPUT *o) {
31 	LNODE *lc, *lctmp;
32 	o->pat = ts_pat_alloc_init(conf->transport_stream_id);
33 	list_lock(conf->channels);
34 	list_for_each(conf->channels, lc, lctmp) {
35 		CHANNEL *c = lc->data;
36 		ts_pat_add_program(o->pat, c->service_id, c->pmt_pid);
37 	}
38 	list_unlock(conf->channels);
39 	gettimeofday(&o->pat_ts, NULL);
40 }
41 
output_psi_init_nit(CONFIG * conf,OUTPUT * o)42 static void output_psi_init_nit(CONFIG *conf, OUTPUT *o) {
43 	struct ts_nit *nit = ts_nit_alloc_init(conf->network_id);
44 
45 	ts_nit_add_network_name_descriptor(nit, conf->network_name);
46 
47 	if (conf->nit->items < 64) {
48 		int num;
49 		LNODE *lc, *lctmp;
50 		uint32_t *freqs = malloc(conf->nit->items * sizeof(uint32_t));
51 		uint32_t *services = malloc(conf->channels->items * sizeof(uint32_t));
52 		num = 0;
53 		list_lock(conf->nit);
54 		list_for_each(conf->nit, lc, lctmp) {
55 			NIT *ndata = lc->data;
56 			freqs[num++] = ndata->_freq;
57 		}
58 		ts_nit_add_frequency_list_descriptor_cable(nit, conf->transport_stream_id, conf->network_id, freqs, num);
59 		list_for_each(conf->nit, lc, lctmp) {
60 			NIT *ndata = lc->data;
61 			ts_nit_add_cable_delivery_descriptor(nit, ndata->ts_id, conf->network_id, ndata->_freq, ndata->_modulation, ndata->_symbol_rate);
62 		}
63 		list_unlock(conf->nit);
64 		num = 0;
65 		list_lock(conf->channels);
66 		list_for_each(conf->channels, lc, lctmp) {
67 			CHANNEL *c = lc->data;
68 			uint32_t srv = 0;
69 			srv  = (c->service_id &~ 0x00ff) << 16;
70 			srv |= (c->service_id &~ 0xff00) << 8;
71 			srv |= c->radio ? 0x02 : 0x01;
72 			services[num++] = srv;
73 		}
74 		list_unlock(conf->channels);
75 		ts_nit_add_service_list_descriptor(nit, conf->transport_stream_id, conf->network_id, services, num);
76 		free(freqs);
77 		free(services);
78 	} else {
79 		LOG("CONF  : Too much items in the NIT, maximum is 64! NIT not generated.\n");
80 	}
81 	gettimeofday(&o->nit_ts, NULL);
82 	o->nit = nit;
83 }
84 
output_psi_init_sdt(CONFIG * conf,OUTPUT * o)85 static void output_psi_init_sdt(CONFIG *conf, OUTPUT *o) {
86 	LNODE *lc, *lctmp;
87 	struct ts_sdt *sdt = ts_sdt_alloc_init(conf->network_id, conf->transport_stream_id);
88 	list_lock(conf->channels);
89 	list_for_each(conf->channels, lc, lctmp) {
90 		CHANNEL *c = lc->data;
91 		ts_sdt_add_service_descriptor(sdt, c->service_id, c->radio == 0, conf->provider_name, c->name);
92 	}
93 	list_unlock(conf->channels);
94 	gettimeofday(&o->sdt_ts, NULL);
95 	o->sdt = sdt;
96 }
97 
output_psi_init_tdt_tot(CONFIG * conf,OUTPUT * o)98 static void output_psi_init_tdt_tot(CONFIG *conf, OUTPUT *o) {
99 	conf = conf; // Silence warning
100 	o->pid_tdt_cont = 15;
101 	o->tdt = ts_tdt_alloc_init(time(NULL));
102 	o->tot = ts_tot_alloc_init(time(NULL));
103 	gettimeofday(&o->tdt_ts, NULL);
104 	gettimeofday(&o->tot_ts, NULL);
105 }
106 
107 
output_add_pat(OUTPUT * o)108 static void output_add_pat(OUTPUT *o) {
109 	if (!o->pat->programs_num) {
110 		LOG("OUTPUT: Error no programs in PAT!\n");
111 		return;
112 	}
113 	int i;
114 	struct ts_pat *pat = o->pat;
115 //	LOGf("OUTPUT: Outputing PAT with %d programs\n", o->pat->programs_num);
116 	for (i=0;i<pat->section_header->num_packets;i++) {
117 		ts_packet_set_cont(pat->section_header->packet_data + (i * TS_PACKET_SIZE), i + o->pid_pat_cont);
118 	}
119 	pat->ts_header.continuity = o->pid_pat_cont;
120 	o->pid_pat_cont += pat->section_header->num_packets;
121 	cbuf_fill(o->psibuf, pat->section_header->packet_data, pat->section_header->num_packets * TS_PACKET_SIZE);
122 //	ts_pat_dump(o->pat);
123 }
124 
output_add_nit(OUTPUT * o)125 void output_add_nit(OUTPUT *o) {
126 	if (!o || !o->nit)
127 		return;
128 	int i;
129 	struct ts_nit *nit = o->nit;
130 //	LOGf("OUTPUT: Outputing NIT\n");
131 	for (i=0;i<nit->section_header->num_packets;i++) {
132 		ts_packet_set_cont(nit->section_header->packet_data + (i * TS_PACKET_SIZE), i + o->pid_nit_cont);
133 	}
134 	nit->ts_header.continuity = o->pid_nit_cont;
135 	o->pid_nit_cont += nit->section_header->num_packets;
136 	cbuf_fill(o->psibuf, nit->section_header->packet_data, nit->section_header->num_packets * TS_PACKET_SIZE);
137 //	ts_nit_dump(nit);
138 }
139 
output_add_sdt(OUTPUT * o)140 void output_add_sdt(OUTPUT *o) {
141 	if (!o || !o->sdt)
142 		return;
143 	int i;
144 	struct ts_sdt *sdt = o->sdt;
145 //	LOGf("OUTPUT: Outputing SDT\n");
146 	for (i=0;i<sdt->section_header->num_packets;i++) {
147 		ts_packet_set_cont(sdt->section_header->packet_data + (i * TS_PACKET_SIZE), i + o->pid_sdt_cont);
148 	}
149 	sdt->ts_header.continuity = o->pid_sdt_cont;
150 	o->pid_sdt_cont += sdt->section_header->num_packets;
151 	cbuf_fill(o->psibuf, sdt->section_header->packet_data, sdt->section_header->num_packets * TS_PACKET_SIZE);
152 //	ts_sdt_dump(o->sdt);
153 }
154 
output_add_pid0x14(OUTPUT * o,struct ts_tdt * tdt)155 static void output_add_pid0x14(OUTPUT *o, struct ts_tdt *tdt) {
156 	if (!o || !o->tdt)
157 		return;
158 	int i;
159 //	LOGf("OUTPUT: Outputing TDT\n");
160 	for (i=0;i<tdt->section_header->num_packets;i++) {
161 		ts_packet_set_cont(tdt->section_header->packet_data + (i * TS_PACKET_SIZE), i + o->pid_tdt_cont);
162 	}
163 	tdt->ts_header.continuity = o->pid_tdt_cont;
164 	o->pid_tdt_cont += tdt->section_header->num_packets;
165 	cbuf_fill(o->psibuf, tdt->section_header->packet_data, tdt->section_header->num_packets * TS_PACKET_SIZE);
166 }
167 
output_add_tdt(OUTPUT * o)168 static void output_add_tdt(OUTPUT *o) {
169 //	LOGf("OUTPUT: Outputing TDT\n");
170 	ts_tdt_set_time(o->tdt, time(NULL));
171 	output_add_pid0x14(o, o->tdt);
172 //	ts_tdt_dump(o->tdt);
173 }
174 
output_add_tot(OUTPUT * o)175 static void output_add_tot(OUTPUT *o) {
176 //	LOGf("OUTPUT: Outputing TOT\n");
177 	ts_tot_set_localtime_offset_sofia(o->tot, time(NULL));
178 	output_add_pid0x14(o, o->tot);
179 //	ts_tdt_dump(o->tot);
180 }
181 
__output_add_eit(OUTPUT * o,struct ts_eit * eit)182 static void __output_add_eit(OUTPUT *o, struct ts_eit *eit) {
183 	if (!eit)
184 		return;
185 //	LOGf("OUTPUT: Outputing EIT\n");
186 	int i, pcnt = o->pid_eit_cont;
187 	if (eit->section_header && eit->section_header->packet_data) {
188 		for (i=0;i<eit->section_header->num_packets;i++) {
189 			ts_packet_set_cont(eit->section_header->packet_data + (i * TS_PACKET_SIZE), i + pcnt);
190 		}
191 		eit->ts_header.continuity = pcnt;
192 		o->pid_eit_cont += eit->section_header->num_packets;
193 		cbuf_fill(o->psibuf, eit->section_header->packet_data, eit->section_header->num_packets * TS_PACKET_SIZE);
194 	}
195 //	ts_eit_dump(eit);
196 }
197 
output_add_eit(CONFIG * conf,OUTPUT * o)198 static void output_add_eit(CONFIG *conf, OUTPUT *o) {
199 	LNODE *lr, *lrtmp;
200 	config_load_epg(conf);
201 	list_for_each(conf->inputs, lr, lrtmp) {
202 		INPUT *r = lr->data;
203 		__output_add_eit(o, r->channel->eit_now);
204 		__output_add_eit(o, r->channel->eit_next);
205 	}
206 }
207 
output_psi_add(CONFIG * conf,OUTPUT * o,struct timeval * now)208 static void output_psi_add(CONFIG *conf, OUTPUT *o, struct timeval *now) {
209 	if (timeval_diff_msec(&o->pat_ts, now) >= conf->timeouts.pat) {
210 		o->pat_ts = *now;
211 		output_add_pat(o);
212 	}
213 	if (timeval_diff_msec(&o->nit_ts, now) >= conf->timeouts.nit) {
214 		o->nit_ts = *now;
215 		output_add_nit(o);
216 	}
217 	if (timeval_diff_msec(&o->sdt_ts, now) >= conf->timeouts.sdt) {
218 		o->sdt_ts = *now;
219 		output_add_sdt(o);
220 	}
221 	if (timeval_diff_msec(&o->tdt_ts, now) >= conf->timeouts.tdt) {
222 		o->tdt_ts = *now;
223 		output_add_tdt(o);
224 	}
225 	if (timeval_diff_msec(&o->tot_ts, now) >= conf->timeouts.tot) {
226 		o->tot_ts = *now;
227 		output_add_tot(o);
228 	}
229 	if (timeval_diff_msec(&o->eit_ts, now) >= conf->timeouts.eit) {
230 		o->eit_ts = *now;
231 		output_add_eit(conf, o);
232 	}
233 }
234 
235 
output_psi_init(CONFIG * conf,OUTPUT * output)236 void output_psi_init(CONFIG *conf, OUTPUT *output) {
237 	output_psi_init_pat(conf, output);
238 	output_psi_init_nit(conf, output);
239 	output_psi_init_sdt(conf, output);
240 	output_psi_init_tdt_tot(conf, output);
241 	gettimeofday(&output->eit_ts, NULL);
242 }
243 
output_psi_free(OUTPUT * o)244 void output_psi_free(OUTPUT *o) {
245 	ts_pat_free(&o->pat);
246 	ts_nit_free(&o->nit);
247 	ts_sdt_free(&o->sdt);
248 	ts_tdt_free(&o->tdt);
249 	ts_tdt_free(&o->tot);
250 }
251 
output_handle_psi(void * _config)252 void * output_handle_psi(void *_config) {
253 	CONFIG *conf = _config;
254 	OUTPUT *o = conf->output;
255 	struct timeval now;
256 
257 	signal(SIGPIPE, SIG_IGN);
258 	while (!o->dienow) {
259 		gettimeofday(&now, NULL);
260 		output_psi_add(conf, o, &now);
261 		usleep(10000); // 10 ms
262 	}
263 	LOG("OUTPUT: PSI thread stopped.\n");
264 	o->dienow++;
265 	return 0;
266 }
267