root/trunk/tvheadend/src/dvb/dvb_multiplex.c @ 3084

Revision 3084, 12.6 KB (checked in by andoma, 15 months ago)

If we are unable to create a demultiplex filter in hardware for a table,
put the table on a pending queue and cycle through all tables.

Fixes problems with low-end adapters that does not support that many
filter in hardware.

Line 
1/*
2 *  TV Input - Linux DVB interface
3 *  Copyright (C) 2007 Andreas �an
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 as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <pthread.h>
20#include <assert.h>
21
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <sys/ioctl.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <ctype.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <string.h>
32#include <dirent.h>
33
34#include <linux/dvb/frontend.h>
35#include <linux/dvb/dmx.h>
36
37#include "settings.h"
38
39#include "tvhead.h"
40#include "dvb.h"
41#include "channels.h"
42#include "transports.h"
43#include "teletext.h"
44#include "psi.h"
45#include "dvb_support.h"
46#include "notify.h"
47
48struct th_dvb_mux_instance_tree dvb_muxes;
49
50static struct strtab muxfestatustab[] = {
51  { "Unknown",      TDMI_FE_UNKNOWN },
52  { "No signal",    TDMI_FE_NO_SIGNAL },
53  { "Faint signal", TDMI_FE_FAINT_SIGNAL },
54  { "Bad signal",   TDMI_FE_BAD_SIGNAL },
55  { "Constant FEC", TDMI_FE_CONSTANT_FEC },
56  { "Bursty FEC",   TDMI_FE_BURSTY_FEC },
57  { "OK",           TDMI_FE_OK },
58};
59
60
61/**
62 *  Return a readable status text for the given mux
63 */
64const char *
65dvb_mux_status(th_dvb_mux_instance_t *tdmi)
66{
67  return val2str(tdmi->tdmi_fe_status, muxfestatustab) ?: "Invalid";
68}
69
70
71
72
73/**
74 *
75 */
76static int
77tdmi_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b)
78{
79  if(a->tdmi_switchport != b->tdmi_switchport)
80    return a->tdmi_switchport - b->tdmi_switchport;
81
82  if(a->tdmi_fe_params.frequency != b->tdmi_fe_params.frequency)
83    return a->tdmi_fe_params.frequency - b->tdmi_fe_params.frequency;
84
85  return a->tdmi_polarisation - b->tdmi_polarisation;
86}
87
88/**
89 *
90 */
91static int
92tdmi_global_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b)
93{
94  return strcmp(a->tdmi_identifier, b->tdmi_identifier);
95}
96
97
98/**
99 * Create a new mux on the given adapter, return NULL if it already exists
100 */
101th_dvb_mux_instance_t *
102dvb_mux_create(th_dvb_adapter_t *tda, struct dvb_frontend_parameters *fe_param,
103               int polarisation, int switchport,
104               uint16_t tsid, const char *network, const char *source)
105{
106  th_dvb_mux_instance_t *tdmi;
107  static th_dvb_mux_instance_t *skel;
108  char buf[200];
109  char qpsktxt[20];
110  int entries_before = tda->tda_muxes.entries;
111
112  lock_assert(&global_lock);
113
114  if(skel == NULL)
115    skel = calloc(1, sizeof(th_dvb_mux_instance_t));
116
117  skel->tdmi_polarisation = polarisation;
118  skel->tdmi_switchport = switchport;
119  skel->tdmi_fe_params.frequency = fe_param->frequency;
120
121  tdmi = RB_INSERT_SORTED(&tda->tda_muxes, skel, tdmi_adapter_link, tdmi_cmp);
122  if(tdmi != NULL)
123    return NULL;
124
125  tdmi = skel;
126  skel = NULL;
127
128  tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL];
129  TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
130
131  TAILQ_INIT(&tdmi->tdmi_table_queue);
132
133  tdmi->tdmi_transport_stream_id = tsid;
134  tdmi->tdmi_adapter = tda;
135  tdmi->tdmi_network = network ? strdup(network) : NULL;
136  tdmi->tdmi_quality = 100;
137
138  if(entries_before == 0 && tda->tda_rootpath != NULL) {
139    /* First mux on adapter with backing hardware, start scanner */
140    gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
141  }
142
143  memcpy(&tdmi->tdmi_fe_params, fe_param,
144         sizeof(struct dvb_frontend_parameters));
145
146  if(tda->tda_type == FE_QPSK)
147    snprintf(qpsktxt, sizeof(qpsktxt), "_%s_%d",
148             dvb_polarisation_to_str(polarisation), switchport);
149  else
150    qpsktxt[0] = 0;
151
152  snprintf(buf, sizeof(buf), "%s%d%s",
153           tda->tda_identifier,fe_param->frequency, qpsktxt);
154
155  tdmi->tdmi_identifier = strdup(buf);
156
157  RB_INSERT_SORTED(&dvb_muxes, tdmi, tdmi_global_link, tdmi_global_cmp);
158
159  if(source != NULL) {
160    dvb_mux_nicename(buf, sizeof(buf), tdmi);
161    tvhlog(LOG_NOTICE, "dvb", "New mux \"%s\" created by %s", buf, source);
162
163    dvb_mux_save(tdmi);
164    dvb_adapter_notify_reload(tda);
165  }
166
167  dvb_transport_load(tdmi);
168
169  return tdmi;
170}
171
172/**
173 * Destroy a DVB mux (it might come back by itself very soon though :)
174 */
175void
176dvb_mux_destroy(th_dvb_mux_instance_t *tdmi)
177{
178  th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
179  th_transport_t *t;
180
181  lock_assert(&global_lock);
182 
183  hts_settings_remove("dvbmuxes/%s/%s",
184                      tda->tda_identifier, tdmi->tdmi_identifier); 
185
186  while((t = LIST_FIRST(&tdmi->tdmi_transports)) != NULL)
187    transport_destroy(t);
188
189  if(tda->tda_mux_current == tdmi)
190    dvb_fe_stop(tda->tda_mux_current);
191
192  RB_REMOVE(&dvb_muxes, tdmi, tdmi_global_link);
193  RB_REMOVE(&tda->tda_muxes, tdmi, tdmi_adapter_link);
194
195  if(tdmi->tdmi_scan_queue != NULL)
196    TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
197
198  hts_settings_remove("dvbmuxes/%s", tdmi->tdmi_identifier);
199
200  free(tdmi->tdmi_network);
201  free(tdmi->tdmi_identifier);
202  free(tdmi);
203}
204
205
206/**
207 *
208 */
209th_dvb_mux_instance_t *
210dvb_mux_find_by_identifier(const char *identifier)
211{
212  th_dvb_mux_instance_t skel;
213
214  lock_assert(&global_lock);
215
216  skel.tdmi_identifier = (char *)identifier;
217  return RB_FIND(&dvb_muxes, &skel, tdmi_global_link, tdmi_global_cmp);
218}
219
220
221
222
223
224
225static struct strtab fectab[] = {
226  { "NONE", FEC_NONE },
227  { "1/2",  FEC_1_2 },
228  { "2/3",  FEC_2_3 },
229  { "3/4",  FEC_3_4 },
230  { "4/5",  FEC_4_5 },
231  { "5/6",  FEC_5_6 },
232  { "6/7",  FEC_6_7 },
233  { "7/8",  FEC_7_8 },
234  { "8/9",  FEC_8_9 },
235  { "AUTO", FEC_AUTO }
236};
237
238static struct strtab qamtab[] = {
239  { "QPSK",   QPSK },
240  { "QAM16",  QAM_16 },
241  { "QAM32",  QAM_32 },
242  { "QAM64",  QAM_64 },
243  { "QAM128", QAM_128 },
244  { "QAM256", QAM_256 },
245  { "AUTO",   QAM_AUTO },
246  { "8VSB",   VSB_8 },
247  { "16VSB",  VSB_16 }
248};
249
250static struct strtab bwtab[] = {
251  { "8MHz", BANDWIDTH_8_MHZ },
252  { "7MHz", BANDWIDTH_7_MHZ },
253  { "6MHz", BANDWIDTH_6_MHZ },
254  { "AUTO", BANDWIDTH_AUTO }
255};
256
257static struct strtab modetab[] = {
258  { "2k",   TRANSMISSION_MODE_2K },
259  { "8k",   TRANSMISSION_MODE_8K },
260  { "AUTO", TRANSMISSION_MODE_AUTO }
261};
262
263static struct strtab guardtab[] = {
264  { "1/32", GUARD_INTERVAL_1_32 },
265  { "1/16", GUARD_INTERVAL_1_16 },
266  { "1/8",  GUARD_INTERVAL_1_8 },
267  { "1/4",  GUARD_INTERVAL_1_4 },
268  { "AUTO", GUARD_INTERVAL_AUTO },
269};
270
271static struct strtab hiertab[] = {
272  { "NONE", HIERARCHY_NONE },
273  { "1",    HIERARCHY_1 },
274  { "2",    HIERARCHY_2 },
275  { "4",    HIERARCHY_4 },
276  { "AUTO", HIERARCHY_AUTO }
277};
278
279static struct strtab poltab[] = {
280  { "Vertical",      POLARISATION_VERTICAL },
281  { "Horizontal",    POLARISATION_HORIZONTAL },
282};
283
284
285/**
286 *
287 */
288void
289dvb_mux_save(th_dvb_mux_instance_t *tdmi)
290{
291  struct dvb_frontend_parameters *f = &tdmi->tdmi_fe_params;
292
293  htsmsg_t *m = htsmsg_create_map();
294
295  htsmsg_add_u32(m, "quality", tdmi->tdmi_quality);
296  htsmsg_add_str(m, "status", dvb_mux_status(tdmi));
297
298  htsmsg_add_u32(m, "transportstreamid", tdmi->tdmi_transport_stream_id);
299  if(tdmi->tdmi_network != NULL)
300    htsmsg_add_str(m, "network", tdmi->tdmi_network);
301
302  htsmsg_add_u32(m, "frequency", f->frequency);
303
304  switch(tdmi->tdmi_adapter->tda_type) {
305  case FE_OFDM:
306    htsmsg_add_str(m, "bandwidth",
307                   val2str(f->u.ofdm.bandwidth, bwtab));
308
309    htsmsg_add_str(m, "constellation",
310            val2str(f->u.ofdm.constellation, qamtab));
311
312    htsmsg_add_str(m, "transmission_mode",
313            val2str(f->u.ofdm.transmission_mode, modetab));
314
315    htsmsg_add_str(m, "guard_interval",
316            val2str(f->u.ofdm.guard_interval, guardtab));
317
318    htsmsg_add_str(m, "hierarchy",
319            val2str(f->u.ofdm.hierarchy_information, hiertab));
320
321    htsmsg_add_str(m, "fec_hi",
322            val2str(f->u.ofdm.code_rate_HP, fectab));
323
324    htsmsg_add_str(m, "fec_lo",
325            val2str(f->u.ofdm.code_rate_LP, fectab));
326    break;
327
328  case FE_QPSK:
329    htsmsg_add_u32(m, "symbol_rate", f->u.qpsk.symbol_rate);
330
331    htsmsg_add_str(m, "fec",
332            val2str(f->u.qpsk.fec_inner, fectab));
333
334    htsmsg_add_str(m, "polarisation",
335            val2str(tdmi->tdmi_polarisation, poltab));
336 
337    htsmsg_add_u32(m, "switchport", tdmi->tdmi_switchport);
338    break;
339
340  case FE_QAM:
341    htsmsg_add_u32(m, "symbol_rate", f->u.qam.symbol_rate);
342
343    htsmsg_add_str(m, "fec",
344            val2str(f->u.qam.fec_inner, fectab));
345
346    htsmsg_add_str(m, "constellation",
347            val2str(f->u.qam.modulation, qamtab));
348    break;
349
350  case FE_ATSC:
351    break;
352  }
353
354  hts_settings_save(m, "dvbmuxes/%s/%s",
355                    tdmi->tdmi_adapter->tda_identifier, tdmi->tdmi_identifier);
356  htsmsg_destroy(m);
357}
358
359
360/**
361 *
362 */
363static const char *
364tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m)
365{
366  th_dvb_mux_instance_t *tdmi;
367  struct dvb_frontend_parameters f;
368  const char *s;
369  int r;
370  int polarisation = 0;
371  unsigned int switchport = 0;
372  unsigned int tsid, u32;
373
374  memset(&f, 0, sizeof(f));
375 
376  f.inversion = INVERSION_AUTO;
377  htsmsg_get_u32(m, "frequency", &f.frequency);
378
379
380  switch(tda->tda_type) {
381  case FE_OFDM:
382    s = htsmsg_get_str(m, "bandwidth");
383    if(s == NULL || (r = str2val(s, bwtab)) < 0)
384      return "Invalid bandwidth";
385    f.u.ofdm.bandwidth = r;
386
387    s = htsmsg_get_str(m, "constellation");
388    if(s == NULL || (r = str2val(s, qamtab)) < 0)
389      return "Invalid QAM constellation";
390    f.u.ofdm.constellation = r;
391
392    s = htsmsg_get_str(m, "transmission_mode");
393    if(s == NULL || (r = str2val(s, modetab)) < 0)
394      return "Invalid transmission mode";
395    f.u.ofdm.transmission_mode = r;
396
397    s = htsmsg_get_str(m, "guard_interval");
398    if(s == NULL || (r = str2val(s, guardtab)) < 0)
399      return "Invalid guard interval";
400    f.u.ofdm.guard_interval = r;
401
402    s = htsmsg_get_str(m, "hierarchy");
403    if(s == NULL || (r = str2val(s, hiertab)) < 0)
404      return "Invalid heirarchy information";
405    f.u.ofdm.hierarchy_information = r;
406
407    s = htsmsg_get_str(m, "fec_hi");
408    if(s == NULL || (r = str2val(s, fectab)) < 0)
409      return "Invalid hi-FEC";
410    f.u.ofdm.code_rate_HP = r;
411
412    s = htsmsg_get_str(m, "fec_lo");
413    if(s == NULL || (r = str2val(s, fectab)) < 0)
414      return "Invalid lo-FEC";
415    f.u.ofdm.code_rate_LP = r;
416    break;
417
418  case FE_QPSK:
419    htsmsg_get_u32(m, "symbol_rate", &f.u.qpsk.symbol_rate);
420    if(f.u.qpsk.symbol_rate == 0)
421      return "Invalid symbol rate";
422   
423    s = htsmsg_get_str(m, "fec");
424    if(s == NULL || (r = str2val(s, fectab)) < 0)
425      return "Invalid FEC";
426    f.u.qpsk.fec_inner = r;
427
428    s = htsmsg_get_str(m, "polarisation");
429    if(s == NULL || (r = str2val(s, poltab)) < 0)
430      return "Invalid polarisation";
431    polarisation = r;
432   
433    htsmsg_get_u32(m, "switchport", &switchport);
434    break;
435
436  case FE_QAM:
437    htsmsg_get_u32(m, "symbol_rate", &f.u.qam.symbol_rate);
438    if(f.u.qam.symbol_rate == 0)
439      return "Invalid symbol rate";
440   
441    s = htsmsg_get_str(m, "constellation");
442    if(s == NULL || (r = str2val(s, qamtab)) < 0)
443      return "Invalid QAM constellation";
444    f.u.qam.modulation = r;
445
446    s = htsmsg_get_str(m, "fec");
447    if(s == NULL || (r = str2val(s, fectab)) < 0)
448      return "Invalid FEC";
449    f.u.qam.fec_inner = r;
450    break;
451
452  case FE_ATSC:
453    break;
454  }
455
456  if(htsmsg_get_u32(m, "transportstreamid", &tsid))
457    tsid = 0xffff;
458
459  tdmi = dvb_mux_create(tda, &f, polarisation, switchport,
460                        tsid, htsmsg_get_str(m, "network"), NULL);
461  if(tdmi != NULL) {
462
463    if((s = htsmsg_get_str(m, "status")) != NULL)
464      tdmi->tdmi_fe_status = str2val(s, muxfestatustab);
465
466    if(!htsmsg_get_u32(m, "quality", &u32)) {
467      tdmi->tdmi_quality = u32;
468
469      if(tdmi->tdmi_scan_queue != NULL)
470        TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
471
472      if(tdmi->tdmi_quality == 100) {
473        tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_OK];
474      } else {
475        tdmi->tdmi_scan_queue = &tda->tda_scan_queues[DVB_MUX_SCAN_BAD];
476      }
477      TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
478    }
479
480  }
481  return NULL;
482}
483
484
485
486/**
487 *
488 */
489void
490dvb_mux_load(th_dvb_adapter_t *tda)
491{
492  htsmsg_t *l, *c;
493  htsmsg_field_t *f;
494
495  if((l = hts_settings_load("dvbmuxes/%s", tda->tda_identifier)) == NULL)
496    return;
497 
498  HTSMSG_FOREACH(f, l) {
499    if((c = htsmsg_get_map_by_field(f)) == NULL)
500      continue;
501   
502    tdmi_create_by_msg(tda, c);
503  }
504  htsmsg_destroy(l);
505}
506
507/**
508 *
509 */
510void
511dvb_mux_set_networkname(th_dvb_mux_instance_t *tdmi, const char *networkname)
512{
513  htsmsg_t *m = htsmsg_create_map();
514  char buf[100];
515
516  htsmsg_add_str(m, "id", tdmi->tdmi_identifier);
517
518  free((void *)tdmi->tdmi_network);
519  tdmi->tdmi_network = strdup(networkname);
520  dvb_mux_save(tdmi);
521
522  dvb_mux_nicename(buf, sizeof(buf), tdmi);
523  htsmsg_add_str(m, "name", buf);
524  notify_by_msg("dvbmux", m);
525}
Note: See TracBrowser for help on using the browser.