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