root/trunk/tvheadend/src/dvb/dvb_adapter.c @ 3083

Revision 3083, 10.2 KB (checked in by andoma, 15 months ago)

Figure out if we need to re-save a transport configuration instead of relying on if we've seen it once, it can not change

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
33#include <linux/dvb/frontend.h>
34#include <linux/dvb/dmx.h>
35
36#include "settings.h"
37
38#include "tvhead.h"
39#include "transports.h"
40#include "dvb.h"
41#include "dvb_support.h"
42#include "tsdemux.h"
43#include "notify.h"
44
45struct th_dvb_adapter_queue dvb_adapters;
46struct th_dvb_mux_instance_tree dvb_muxes;
47static void *dvb_adapter_input_dvr(void *aux);
48
49
50/**
51 *
52 */
53static th_dvb_adapter_t *
54tda_alloc(void)
55{
56  int i;
57  th_dvb_adapter_t *tda = calloc(1, sizeof(th_dvb_adapter_t));
58  pthread_mutex_init(&tda->tda_delivery_mutex, NULL);
59
60  for(i = 0; i < 3; i++)
61    TAILQ_INIT(&tda->tda_scan_queues[i]);
62  return tda;
63}
64
65
66/**
67 * Save config for the given adapter
68 */
69static void
70tda_save(th_dvb_adapter_t *tda)
71{
72  htsmsg_t *m = htsmsg_create_map();
73
74  lock_assert(&global_lock);
75
76  htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type));
77  htsmsg_add_str(m, "displayname", tda->tda_displayname);
78  htsmsg_add_u32(m, "autodiscovery", tda->tda_autodiscovery);
79  hts_settings_save(m, "dvbadapters/%s", tda->tda_identifier);
80  htsmsg_destroy(m);
81}
82
83
84/**
85 *
86 */
87void
88dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s)
89{
90  htsmsg_t *m;
91
92  lock_assert(&global_lock);
93
94  if(!strcmp(s, tda->tda_displayname))
95    return;
96
97  tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" renamed to \"%s\"",
98         tda->tda_displayname, s);
99
100  m = htsmsg_create_map();
101  htsmsg_add_str(m, "id", tda->tda_identifier);
102
103  free(tda->tda_displayname);
104  tda->tda_displayname = strdup(s);
105 
106  tda_save(tda);
107
108  htsmsg_add_str(m, "name", tda->tda_displayname);
109
110  notify_by_msg("dvbadapter", m);
111}
112
113
114/**
115 *
116 */
117void
118dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on)
119{
120  if(tda->tda_autodiscovery == on)
121    return;
122
123  lock_assert(&global_lock);
124
125  tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" mux autodiscovery set to %s",
126         tda->tda_displayname, on ? "On" : "Off");
127
128  tda->tda_autodiscovery = on;
129  tda_save(tda);
130}
131
132
133/**
134 *
135 */
136static void
137tda_add(const char *path)
138{
139  char fname[256];
140  int fe, i, r;
141  th_dvb_adapter_t *tda;
142  char buf[400];
143  pthread_t ptid;
144
145  snprintf(fname, sizeof(fname), "%s/frontend0", path);
146 
147  fe = open(fname, O_RDWR | O_NONBLOCK);
148  if(fe == -1) {
149    if(errno != ENOENT)
150      tvhlog(LOG_ALERT, "dvb",
151             "Unable to open %s -- %s\n", fname, strerror(errno));
152    return;
153  }
154
155  tda = tda_alloc();
156
157  tda->tda_rootpath = strdup(path);
158  tda->tda_demux_path = malloc(256);
159  snprintf(tda->tda_demux_path, 256, "%s/demux0", path);
160  tda->tda_dvr_path = malloc(256);
161  snprintf(tda->tda_dvr_path, 256, "%s/dvr0", path);
162
163
164  tda->tda_fe_fd = fe;
165
166  tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info));
167
168  if(ioctl(tda->tda_fe_fd, FE_GET_INFO, tda->tda_fe_info)) {
169    tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter\n", fname);
170    close(fe);
171    free(tda);
172    return;
173  }
174
175  tda->tda_type = tda->tda_fe_info->type;
176
177  snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath,
178           tda->tda_fe_info->name);
179
180  r = strlen(buf);
181  for(i = 0; i < r; i++)
182    if(!isalnum((int)buf[i]))
183      buf[i] = '_';
184
185  tda->tda_identifier = strdup(buf);
186 
187  tda->tda_autodiscovery = tda->tda_type != FE_QPSK;
188
189  /* Come up with an initial displayname, user can change it and it will
190     be overridden by any stored settings later on */
191
192  tda->tda_displayname = strdup(tda->tda_fe_info->name);
193
194  tvhlog(LOG_INFO, "dvb",
195         "Found adapter %s (%s)", path, tda->tda_fe_info->name);
196
197  TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
198
199  pthread_create(&ptid, NULL, dvb_adapter_input_dvr, tda);
200
201  dvb_table_init(tda);
202}
203
204
205/**
206 *
207 */
208void
209dvb_adapter_init(void)
210{
211  char path[200];
212  htsmsg_t *l, *c;
213  htsmsg_field_t *f;
214  const char *name, *s;
215  int i, type;
216  th_dvb_adapter_t *tda;
217
218  TAILQ_INIT(&dvb_adapters);
219
220  for(i = 0; i < 32; i++) {
221    snprintf(path, sizeof(path), "/dev/dvb/adapter%d", i);
222    tda_add(path);
223  }
224
225  l = hts_settings_load("dvbadapters");
226  if(l != NULL) {
227    HTSMSG_FOREACH(f, l) {
228      if((c = htsmsg_get_map_by_field(f)) == NULL)
229        continue;
230     
231      name = htsmsg_get_str(c, "displayname");
232
233      if((s = htsmsg_get_str(c, "type")) == NULL ||
234         (type = dvb_str_to_adaptertype(s)) < 0)
235        continue;
236
237      if((tda = dvb_adapter_find_by_identifier(f->hmf_name)) == NULL) {
238        /* Not discovered by hardware, create it */
239
240        tda = tda_alloc();
241        tda->tda_identifier = strdup(f->hmf_name);
242        tda->tda_type = type;
243        TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
244      } else {
245        if(type != tda->tda_type)
246          continue; /* Something is wrong, ignore */
247      }
248
249      free(tda->tda_displayname);
250      tda->tda_displayname = strdup(name);
251
252      htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery);
253    }
254    htsmsg_destroy(l);
255  }
256
257  TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link)
258    dvb_mux_load(tda);
259}
260
261
262/**
263 *
264 */
265void
266dvb_adapter_notify_reload(th_dvb_adapter_t *tda)
267{
268  htsmsg_t *m = htsmsg_create_map();
269  htsmsg_add_str(m, "id", tda->tda_identifier);
270
271  htsmsg_add_u32(m, "reload", 1);
272  notify_by_msg("dvbadapter", m);
273}
274
275
276/**
277 * If nobody is subscribing, cycle thru all muxes to get some stats
278 * and EIT updates
279 */
280void
281dvb_adapter_mux_scanner(void *aux)
282{
283  th_dvb_adapter_t *tda = aux;
284  th_dvb_mux_instance_t *tdmi;
285  int i;
286
287  gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 10);
288
289  if(transport_compute_weight(&tda->tda_transports) > 0)
290    return; /* someone is here */
291
292  /* Check if we have muxes pending for quickscan, if so, choose them */
293  tdmi = TAILQ_FIRST(&tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL]);
294
295  /* If not, alternate between the other two (bad and OK) */
296  if(tdmi == NULL) {
297    for(i = 0; i < 2; i++) {
298      tda->tda_scan_selector = !tda->tda_scan_selector;
299      tdmi = TAILQ_FIRST(&tda->tda_scan_queues[tda->tda_scan_selector]);
300      if(tdmi != NULL) {
301        assert(tdmi->tdmi_scan_queue ==
302               &tda->tda_scan_queues[tda->tda_scan_selector]);
303        break;
304      }
305    }
306  } else {
307    assert(tdmi->tdmi_scan_queue ==
308           &tda->tda_scan_queues[DVB_MUX_SCAN_INITIAL]);
309  }
310
311  if(tdmi != NULL) {
312    /* Push to tail of queue */
313    TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
314    TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
315    dvb_fe_tune(tdmi, "Autoscan");
316  }
317}
318
319/**
320 *
321 */
322void
323dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
324{
325  th_dvb_mux_instance_t *tdmi_src, *tdmi_dst;
326  th_transport_t *t_src, *t_dst;
327  th_stream_t *st_src, *st_dst;
328
329  lock_assert(&global_lock);
330
331  while((tdmi_dst = RB_FIRST(&dst->tda_muxes)) != NULL)
332    dvb_mux_destroy(tdmi_dst);
333
334  RB_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link) {
335
336    tdmi_dst = dvb_mux_create(dst,
337                              &tdmi_src->tdmi_fe_params,
338                              tdmi_src->tdmi_polarisation,
339                              tdmi_src->tdmi_switchport,
340                              tdmi_src->tdmi_transport_stream_id,
341                              tdmi_src->tdmi_network,
342                              "copy operation");
343
344
345    assert(tdmi_dst != NULL);
346
347    LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, tht_mux_link) {
348      t_dst = dvb_transport_find(tdmi_dst,
349                                 t_src->tht_dvb_service_id,
350                                 t_src->tht_pmt_pid,
351                                 NULL);
352
353      t_dst->tht_pcr_pid     = t_src->tht_pcr_pid;
354      t_dst->tht_disabled    = t_src->tht_disabled;
355      t_dst->tht_servicetype = t_src->tht_servicetype;
356      t_dst->tht_scrambled   = t_src->tht_scrambled;
357
358      if(t_src->tht_provider != NULL)
359        t_dst->tht_provider    = strdup(t_src->tht_provider);
360
361      if(t_src->tht_svcname != NULL)
362        t_dst->tht_svcname = strdup(t_src->tht_svcname);
363
364      if(t_src->tht_chname != NULL)
365        t_dst->tht_chname = strdup(t_src->tht_chname);
366     
367      if(t_src->tht_ch != NULL)
368        transport_map_channel(t_dst, t_src->tht_ch);
369
370      pthread_mutex_lock(&t_src->tht_stream_mutex);
371
372      LIST_FOREACH(st_src, &t_src->tht_components, st_link) {
373
374        st_dst = transport_stream_create(t_dst,
375                                         st_src->st_pid,
376                                         st_src->st_type);
377       
378        st_dst->st_tb = (AVRational){1, 90000};
379       
380        memcpy(st_dst->st_lang, st_src->st_lang, 4);
381        st_dst->st_frame_duration = st_src->st_frame_duration;
382        st_dst->st_caid           = st_src->st_caid;
383      }
384
385      pthread_mutex_unlock(&t_src->tht_stream_mutex);
386
387    }
388    dvb_mux_save(tdmi_dst);
389  }
390  tda_save(dst);
391}
392
393/**
394 *
395 */
396int
397dvb_adapter_destroy(th_dvb_adapter_t *tda)
398{
399  th_dvb_mux_instance_t *tdmi;
400
401  if(tda->tda_rootpath != NULL)
402    return -1;
403
404  lock_assert(&global_lock);
405
406  hts_settings_remove("dvbadapters/%s", tda->tda_identifier);
407
408  while((tdmi = RB_FIRST(&tda->tda_muxes)) != NULL)
409    dvb_mux_destroy(tdmi);
410 
411  TAILQ_REMOVE(&dvb_adapters, tda, tda_global_link);
412
413  free(tda->tda_identifier);
414  free(tda->tda_displayname);
415
416  free(tda);
417
418  return 0;
419}
420
421
422/**
423 *
424 */
425void
426dvb_adapter_clean(th_dvb_adapter_t *tda)
427{
428  th_transport_t *t;
429 
430  lock_assert(&global_lock);
431
432  while((t = LIST_FIRST(&tda->tda_transports)) != NULL)
433    transport_remove_subscriber(t, NULL); /* Flushes all subscribers */
434}
435
436
437
438/**
439 *
440 */
441static void *
442dvb_adapter_input_dvr(void *aux)
443{
444  th_dvb_adapter_t *tda = aux;
445  int fd, i, r;
446  uint8_t tsb[188 * 10];
447  th_transport_t *t;
448
449  fd = open(tda->tda_dvr_path, O_RDONLY);
450  if(fd == -1) {
451    tvhlog(LOG_ALERT, "dvb", "%s: unable to open dvr", tda->tda_dvr_path);
452    return NULL;
453  }
454
455  while(1) {
456    r = read(fd, tsb, sizeof(tsb));
457
458    pthread_mutex_lock(&tda->tda_delivery_mutex);
459   
460    for(i = 0; i < r; i += 188)
461      LIST_FOREACH(t, &tda->tda_transports, tht_active_link)
462        if(t->tht_dvb_mux_instance == tda->tda_mux_current)
463          ts_recv_packet1(t, tsb + i);
464
465    pthread_mutex_unlock(&tda->tda_delivery_mutex);
466  }
467}
Note: See TracBrowser for help on using the browser.