Project

General

Profile

Bug #5486 » mpegts_network_dvb.c

2nd patched file - Daniel Tomaszewski, 2019-01-17 15:53

 
1
/*
2
 *  Tvheadend - Linux DVB Network
3
 *
4
 *  Copyright (C) 2013 Adam Sutton
5
 *
6
 *  This program is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
#include "tvheadend.h"
21
#include "input.h"
22
#include "queue.h"
23
#include "settings.h"
24
#include "mpegts_dvb.h"
25
#include "linuxdvb/linuxdvb_private.h"
26
#include "dvb_charset.h"
27
#include "config.h"
28
#include "scanfile.h"
29

30
#include <sys/types.h>
31
#include <sys/ioctl.h>
32
#include <unistd.h>
33
#include <stdlib.h>
34
#include <dirent.h>
35
#include <fcntl.h>
36

 
37
/* ****************************************************************************
38
 * Class definition
39
 * ***************************************************************************/
40

41
extern const idclass_t mpegts_network_class;
42

43
static void
44
dvb_network_class_delete ( idnode_t *in )
45
{
46
  mpegts_network_t *mn = (mpegts_network_t*)in;
47
  char ubuf[UUID_HEX_SIZE];
48

49
  /* remove config */
50
  hts_settings_remove("input/dvb/networks/%s",
51
                      idnode_uuid_as_str(in, ubuf));
52

53
  /* Parent delete */
54
  mpegts_network_delete(mn, 1);
55
}
56

57
static const void *
58
dvb_network_class_scanfile_get ( void *o )
59
{
60
  prop_ptr = NULL;
61
  return &prop_ptr;
62
}
63

64
void
65
dvb_network_scanfile_set ( dvb_network_t *ln, const char *id )
66
{
67
  dvb_mux_conf_t *dmc;
68
  scanfile_network_t *sfn;
69
  dvb_mux_t *mm;
70

71
  /* Find */
72
  if (!id)
73
    return;
74
  if (!(sfn = scanfile_find(id)))
75
    return;
76

77
  /* Set satellite position */
78
  if (sfn->sfn_satpos != INT_MAX && ln->mn_satpos == INT_MAX)
79
    ln->mn_satpos = sfn->sfn_satpos;
80

81
  /* Create */
82
  LIST_FOREACH(dmc, &sfn->sfn_muxes, dmc_link) {
83
    if (!(mm = dvb_network_find_mux(ln, dmc, MPEGTS_ONID_NONE, MPEGTS_TSID_NONE, 0, 0))) {
84
      mm = dvb_mux_create0(ln, MPEGTS_ONID_NONE, MPEGTS_TSID_NONE,
85
                           dmc, NULL, NULL);
86
      if (mm) {
87
        mpegts_mux_post_create((mpegts_mux_t *)mm);
88
        idnode_changed(&mm->mm_id);
89
      }
90
      if (tvhtrace_enabled()) {
91
        char buf[128];
92
        dvb_mux_conf_str(dmc, buf, sizeof(buf));
93
        tvhtrace(LS_SCANFILE, "mux %p %s added to network %s", mm, buf, ln->mn_network_name);
94
      }
95
    } else {
96
      if (tvhtrace_enabled()) {
97
        char buf[128];
98
        dvb_mux_conf_str(dmc, buf, sizeof(buf));
99
        tvhtrace(LS_SCANFILE, "mux %p skipped %s in network %s", mm, buf, ln->mn_network_name);
100
        dvb_mux_conf_str(&((dvb_mux_t *)mm)->lm_tuning, buf, sizeof(buf));
101
        tvhtrace(LS_SCANFILE, "mux %p exists %s in network %s", mm, buf, ln->mn_network_name);
102
      }
103
    }
104
  }
105
  scanfile_clean(sfn);
106
  return;
107
}
108

109
static int
110
dvb_network_class_scanfile_set ( void *o, const void *s )
111
{
112
  dvb_network_scanfile_set(o, s);
113
  return 0;
114
}
115

116
static htsmsg_t *
117
dvb_network_class_scanfile_list0
118
( const idclass_t *clazz, dvb_network_t *ln, const char *lang )
119
{
120
  const char *type;
121

122
  if (clazz == NULL)
123
    return NULL;
124
  htsmsg_t *e, *m = htsmsg_create_map();
125
  htsmsg_add_str(m, "type", "api");
126
  htsmsg_add_str(m, "uri", "dvb/scanfile/list");
127
  htsmsg_add_str(m, "stype", "none");
128
  e = htsmsg_create_map();
129
  if (clazz == &dvb_network_dvbt_class)
130
    type = "dvbt";
131
  else if (clazz == &dvb_network_dvbc_class)
132
    type = "dvbc";
133
  else if (clazz == &dvb_network_dvbs_class)
134
    type = "dvbs";
135
  else if (clazz == &dvb_network_atsc_t_class)
136
    type = "atsc-t";
137
  else if (clazz == &dvb_network_atsc_c_class)
138
    type = "atsc-c";
139
  else if (clazz == &dvb_network_isdb_t_class)
140
    type = "isdb-t";
141
  else if (clazz == &dvb_network_isdb_c_class)
142
    type = "isdb-c";
143
  else if (clazz == &dvb_network_isdb_s_class)
144
    type = "isdb-s";
145
  else if (clazz == &dvb_network_dtmb_class)
146
    type = "dtmb";
147
  else if (clazz == &dvb_network_dab_class)
148
    type = "dab";
149
  else
150
    type = "unk";
151
  htsmsg_add_str(e, "type", type);
152
  if (ln && ln->mn_satpos != INT_MAX)
153
    htsmsg_add_s32(e, "satpos", ln->mn_satpos);
154
  htsmsg_add_msg(m, "params", e);
155
  return m;
156
}
157

158
htsmsg_t *
159
dvb_network_class_scanfile_list ( void *o, const char *lang )
160
{
161
  if (o == NULL)
162
    return NULL;
163
  return dvb_network_class_scanfile_list0(((mpegts_network_t *)o)->mn_id.in_class, o, lang);
164
}
165

166
#define SCANFILE_LIST(name) \
167
static htsmsg_t * \
168
dvb_network_class_scanfile_list_##name ( void *o, const char *lang ) \
169
{ \
170
  return dvb_network_class_scanfile_list0(&dvb_network_##name##_class, o, lang); \
171
}
172

173
SCANFILE_LIST(dvbt);
174
SCANFILE_LIST(dvbc);
175
SCANFILE_LIST(dvbs);
176
SCANFILE_LIST(atsc_t);
177
SCANFILE_LIST(atsc_c);
178
SCANFILE_LIST(isdb_t);
179
SCANFILE_LIST(isdb_c);
180
SCANFILE_LIST(isdb_s);
181
SCANFILE_LIST(dtmb);
182
SCANFILE_LIST(dab);
183

184
static const void *
185
dvb_network_class_orbital_pos_get ( void *o )
186
{
187
  dvb_network_t *ln = o;
188
  prop_sbuf[0] = '\0';
189
  if (ln->mn_satpos != INT_MAX)
190
    dvb_sat_position_to_str(ln->mn_satpos, prop_sbuf, PROP_SBUF_LEN);
191
  return &prop_sbuf_ptr;
192
}
193

194
static int
195
dvb_network_class_orbital_pos_set ( void *o, const void *s )
196
{
197
  dvb_network_t *ln = o;
198
  int satpos;
199

200
  /* Find */
201
  if (!s)
202
    return 0;
203

204
  satpos = dvb_sat_position_from_str(s);
205
  if (satpos != ln->mn_satpos) {
206
    ln->mn_satpos = satpos;
207
    return 1;
208
  }
209

210
  return 0;
211
}
212

213
static htsmsg_t *
214
dvb_network_class_orbital_pos_list ( void *o, const char *lang )
215
{
216
  htsmsg_t *e, *m = htsmsg_create_map();
217
  htsmsg_add_str(m, "type", "api");
218
  htsmsg_add_str(m, "uri", "dvb/orbitalpos/list");
219
  htsmsg_add_str(m, "stype", "none");
220
  e = htsmsg_create_map();
221
  htsmsg_add_msg(m, "params", e);
222
  return m;
223
}
224

225
PROP_DOC(predefinedmuxlist)
226

227
const idclass_t dvb_network_class =
228
{
229
  .ic_super      = &mpegts_network_class,
230
  .ic_class      = "dvb_network",
231
  .ic_caption    = N_("LinuxDVB network"),
232
  .ic_delete     = dvb_network_class_delete,
233
  .ic_properties = (const property_t[]){
234
    {}
235
  }
236
};
237

238
const idclass_t dvb_network_dvbt_class =
239
{
240
  .ic_super      = &dvb_network_class,
241
  .ic_class      = "dvb_network_dvbt",
242
  .ic_caption    = N_("DVB-T Network"),
243
  .ic_properties = (const property_t[]) {
244
    {
245
      .type     = PT_STR,
246
      .id       = "scanfile",
247
      .name     = N_("Pre-defined muxes"),
248
      .desc     = N_("Use a pre-defined list of DVB-T muxes. "
249
                     "Note: these lists can sometimes be outdated and "
250
                     "may cause scanning to take longer than usual."),
251
      .doc      = prop_doc_predefinedmuxlist,
252
      .set      = dvb_network_class_scanfile_set,
253
      .get      = dvb_network_class_scanfile_get,
254
      .list     = dvb_network_class_scanfile_list_dvbt,
255
      .opts     = PO_NOSAVE,
256
    },
257
    {}
258
  }
259
};
260

261
const idclass_t dvb_network_dvbc_class =
262
{
263
  .ic_super      = &dvb_network_class,
264
  .ic_class      = "dvb_network_dvbc",
265
  .ic_caption    = N_("DVB-C Network"),
266
  .ic_properties = (const property_t[]) {
267
    {
268
      .type     = PT_STR,
269
      .id       = "scanfile",
270
      .name     = N_("Pre-defined muxes"),
271
      .desc     = N_("Use a pre-defined list of DVB-C muxes. "
272
                     "Note: these lists can sometimes be outdated and "
273
                     "may cause scanning to take longer than usual."),
274
      .doc      = prop_doc_predefinedmuxlist,
275
      .set      = dvb_network_class_scanfile_set,
276
      .get      = dvb_network_class_scanfile_get,
277
      .list     = dvb_network_class_scanfile_list_dvbc,
278
      .opts     = PO_NOSAVE,
279
    },
280
    {}
281
  }
282
};
283

284
const idclass_t dvb_network_dvbs_class =
285
{
286
  .ic_super      = &dvb_network_class,
287
  .ic_class      = "dvb_network_dvbs",
288
  .ic_caption    = N_("DVB-S Network"),
289
  .ic_properties = (const property_t[]) {
290
    {
291
      .type     = PT_STR,
292
      .id       = "scanfile",
293
      .name     = N_("Pre-defined muxes"),
294
      .desc     = N_("Use a pre-defined list of DVB-S/S2 muxes. "
295
                     "Note: these lists can sometimes be outdated and "
296
                     "may cause scanning to take longer than usual."),
297
      .doc      = prop_doc_predefinedmuxlist,
298
      .set      = dvb_network_class_scanfile_set,
299
      .get      = dvb_network_class_scanfile_get,
300
      .list     = dvb_network_class_scanfile_list_dvbs,
301
      .opts     = PO_NOSAVE,
302
    },
303
    {
304
      .type     = PT_STR,
305
      .id       = "orbital_pos",
306
      .name     = N_("Orbital position"),
307
      .desc     = N_("The orbital position of the satellite "
308
                     "your dish is pointing at."),
309
      .set      = dvb_network_class_orbital_pos_set,
310
      .get      = dvb_network_class_orbital_pos_get,
311
      .list     = dvb_network_class_orbital_pos_list,
312
    },
313
    {}
314
  }
315
};
316

317
const idclass_t dvb_network_atsc_t_class =
318
{
319
  .ic_super      = &dvb_network_class,
320
  .ic_class      = "dvb_network_atsc_t",
321
  .ic_caption    = N_("ATSC-T Network"),
322
  .ic_properties = (const property_t[]) {
323
    {
324
      .type     = PT_STR,
325
      .id       = "scanfile",
326
      .name     = N_("Pre-defined muxes"),
327
      .desc     = N_("Use a pre-defined list of ATSC-T muxes. "
328
                     "Note: these lists can sometimes be outdated and "
329
                     "may cause scanning to take longer than usual."),
330
      .doc      = prop_doc_predefinedmuxlist,
331
      .set      = dvb_network_class_scanfile_set,
332
      .get      = dvb_network_class_scanfile_get,
333
      .list     = dvb_network_class_scanfile_list_atsc_t,
334
      .opts     = PO_NOSAVE,
335
    },
336
    {}
337
  }
338
};
339

340
const idclass_t dvb_network_atsc_c_class =
341
{
342
  .ic_super      = &dvb_network_class,
343
  .ic_class      = "dvb_network_atsc_c",
344
  .ic_caption    = N_("ATSC-C Network"),
345
  .ic_properties = (const property_t[]) {
346
    {
347
      .type     = PT_STR,
348
      .id       = "scanfile",
349
      .name     = N_("Pre-defined muxes"),
350
      .desc     = N_("Use a pre-defined list of ATSC-C muxes. "
351
                     "Note: these lists can sometimes be outdated and "
352
                     "may cause scanning to take longer than usual."),
353
      .doc      = prop_doc_predefinedmuxlist,
354
      .set      = dvb_network_class_scanfile_set,
355
      .get      = dvb_network_class_scanfile_get,
356
      .list     = dvb_network_class_scanfile_list_atsc_c,
357
      .opts     = PO_NOSAVE,
358
    },
359
    {}
360
  }
361
};
362

363
const idclass_t dvb_network_cablecard_class =
364
{
365
  .ic_super      = &dvb_network_class,
366
  .ic_class      = "dvb_network_cablecard",
367
  .ic_caption    = N_("CableCARD Network"),
368
  .ic_properties = (const property_t[]){
369
    {}
370
  }
371
};
372

373
const idclass_t dvb_network_isdb_t_class =
374
{
375
  .ic_super      = &dvb_network_class,
376
  .ic_class      = "dvb_network_isdb_t",
377
  .ic_caption    = N_("ISDB-T Network"),
378
  .ic_properties = (const property_t[]) {
379
    {
380
      .type     = PT_STR,
381
      .id       = "scanfile",
382
      .name     = N_("Pre-defined muxes"),
383
      .desc     = N_("Use a pre-defined list of ISDB-T muxes. "
384
                     "Note: these lists can sometimes be outdated and "
385
                     "may cause scanning to take longer than usual."),
386
      .doc      = prop_doc_predefinedmuxlist,
387
      .set      = dvb_network_class_scanfile_set,
388
      .get      = dvb_network_class_scanfile_get,
389
      .list     = dvb_network_class_scanfile_list_isdb_t,
390
      .opts     = PO_NOSAVE,
391
    },
392
    {}
393
  }
394
};
395

396
const idclass_t dvb_network_isdb_c_class =
397
{
398
  .ic_super      = &dvb_network_class,
399
  .ic_class      = "dvb_network_isdb_c",
400
  .ic_caption    = N_("ISDB-C Network"),
401
  .ic_properties = (const property_t[]) {
402
    {
403
      .type     = PT_STR,
404
      .id       = "scanfile",
405
      .name     = N_("Pre-defined muxes"),
406
      .desc     = N_("Use a pre-defined list of ISDB-C muxes. "
407
                     "Note: these lists can sometimes be outdated and "
408
                     "may cause scanning to take longer than usual."),
409
      .doc      = prop_doc_predefinedmuxlist,
410
      .set      = dvb_network_class_scanfile_set,
411
      .get      = dvb_network_class_scanfile_get,
412
      .list     = dvb_network_class_scanfile_list_isdb_c,
413
      .opts     = PO_NOSAVE,
414
    },
415
    {}
416
  }
417
};
418

419
const idclass_t dvb_network_isdb_s_class =
420
{
421
  .ic_super      = &dvb_network_class,
422
  .ic_class      = "dvb_network_isdb_s",
423
  .ic_caption    = N_("ISDB-S Network"),
424
  .ic_properties = (const property_t[]) {
425
    {
426
      .type     = PT_STR,
427
      .id       = "scanfile",
428
      .name     = N_("Pre-defined muxes"),
429
      .desc     = N_("Use a pre-defined list of ISDB-S muxes. "
430
                     "Note: these lists can sometimes be outdated and "
431
                     "may cause scanning to take longer than usual."),
432
      .doc      = prop_doc_predefinedmuxlist,
433
      .set      = dvb_network_class_scanfile_set,
434
      .get      = dvb_network_class_scanfile_get,
435
      .list     = dvb_network_class_scanfile_list_isdb_s,
436
      .opts     = PO_NOSAVE,
437
    },
438
    {}
439
  }
440
};
441

442
const idclass_t dvb_network_dtmb_class =
443
{
444
  .ic_super      = &dvb_network_class,
445
  .ic_class      = "dvb_network_dtmb",
446
  .ic_caption    = N_("DTMB Network"),
447
  .ic_properties = (const property_t[]) {
448
    {
449
      .type     = PT_STR,
450
      .id       = "scanfile",
451
      .name     = N_("Pre-defined muxes"),
452
      .desc     = N_("Use a pre-defined list of DTMB muxes. "
453
                     "Note: these lists can sometimes be outdated and "
454
                     "may cause scanning to take longer than usual."),
455
      .doc      = prop_doc_predefinedmuxlist,
456
      .set      = dvb_network_class_scanfile_set,
457
      .get      = dvb_network_class_scanfile_get,
458
      .list     = dvb_network_class_scanfile_list_dtmb,
459
      .opts     = PO_NOSAVE,
460
    },
461
    {}
462
  }
463
};
464

465
const idclass_t dvb_network_dab_class =
466
{
467
  .ic_super      = &dvb_network_class,
468
  .ic_class      = "dvb_network_dab",
469
  .ic_caption    = N_("DAB Network"),
470
  .ic_properties = (const property_t[]) {
471
    {
472
      .type     = PT_STR,
473
      .id       = "scanfile",
474
      .name     = N_("Pre-defined muxes"),
475
      .desc     = N_("Use a pre-defined list of DAB muxes. "
476
                     "Note: these lists can sometimes be outdated and "
477
                     "may cause scanning to take longer than usual."),
478
      .doc      = prop_doc_predefinedmuxlist,
479
      .set      = dvb_network_class_scanfile_set,
480
      .get      = dvb_network_class_scanfile_get,
481
      .list     = dvb_network_class_scanfile_list_dab,
482
      .opts     = PO_NOSAVE,
483
    },
484
    {}
485
  }
486
};
487

488
/* ****************************************************************************
489
 * Class methods
490
 * ***************************************************************************/
491

492
static int
493
dvb_network_check_bandwidth( int bw1, int bw2 )
494
{
495
  if (bw1 == DVB_BANDWIDTH_NONE || bw1 == DVB_BANDWIDTH_AUTO ||
496
      bw2 == DVB_BANDWIDTH_NONE || bw2 == DVB_BANDWIDTH_AUTO)
497
    return 0;
498
  return bw1 != bw2;
499
}
500

501
static int
502
dvb_network_check_symbol_rate( dvb_mux_t *lm, dvb_mux_conf_t *dmc, int deltar )
503
{
504
  switch (dmc->dmc_fe_type) {
505
  case DVB_TYPE_T:
506
  case DVB_TYPE_DTMB:
507
    return dvb_network_check_bandwidth(lm->lm_tuning.u.dmc_fe_ofdm.bandwidth,
508
                                       dmc->u.dmc_fe_ofdm.bandwidth);
509
  case DVB_TYPE_C:
510
  case DVB_TYPE_ATSC_C:
511
    return deltaU32(lm->lm_tuning.u.dmc_fe_qam.symbol_rate,
512
               dmc->u.dmc_fe_qam.symbol_rate) > deltar;
513
  case DVB_TYPE_S:
514
    return deltaU32(lm->lm_tuning.u.dmc_fe_qpsk.symbol_rate,
515
               dmc->u.dmc_fe_qpsk.symbol_rate) > deltar;
516
  case DVB_TYPE_ATSC_T:
517
    return 0;
518
  default:
519
    return 0;
520
  }
521
}
522

523
static int
524
dvb_network_check_orbital_pos ( int satpos1, int satpos2 )
525
{
526
  if (satpos1 != INT_MAX && satpos2 != INT_MAX) {
527
    /* 1W and 0.8W */
528
    if (abs(satpos1 - satpos2) > 2)
529
      return 1;
530
  }
531
  return 0;
532
}
533

534
dvb_mux_t *
535
dvb_network_find_mux
536
  ( dvb_network_t *ln, dvb_mux_conf_t *dmc, uint16_t onid, uint16_t tsid, int check, int approx_match )
537
{
538
  int deltaf, deltar;
539
  mpegts_mux_t *mm, *mm_alt = NULL;
540

541
  LIST_FOREACH(mm, &ln->mn_muxes, mm_network_link) {
542

543
    if (check && mm->mm_enabled != MM_ENABLE) continue;
544

545
    deltaf = 2000; // 2K/MHz
546
    deltar = 1000;
547
    dvb_mux_t *lm = (dvb_mux_t*)mm;
548

549
    /* Same FE type - this REALLY should match! */
550
    if (lm->lm_tuning.dmc_fe_type != dmc->dmc_fe_type) continue;
551

552
    /* Also, the system type should match (DVB-S/DVB-S2) */
553
    if (!approx_match && (lm->lm_tuning.dmc_fe_delsys != dmc->dmc_fe_delsys)) continue;
554

555
    /* if ONID/TSID are a perfect match (and this is DVB-S, allow greater deltaf) */
556
    if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_S) {
557
      deltar = 7000;
558
      if (onid != MPEGTS_ONID_NONE && tsid != MPEGTS_TSID_NONE) {
559
        deltaf = 16000; // This is slightly crazy, but I have seen 10MHz changes in freq
560
                        // and remember the ONID and TSID must agree
561
      } else {
562
        /* the freq. changes for lower symbol rates might be smaller */
563
        deltaf = 4000;
564
        if (dmc->u.dmc_fe_qpsk.symbol_rate < 5000000)
565
          deltaf = 1900;
566
        if (dmc->u.dmc_fe_qpsk.symbol_rate < 10000000)
567
          deltaf = 2900;
568
      }
569
    }
570

571
    /* Reject if not same frequency (some tolerance due to changes and diff in NIT) */
572
    if (deltaU32(lm->lm_tuning.dmc_fe_freq, dmc->dmc_fe_freq) > deltaf) continue;
573

574
    /* Reject if not same symbol rate (some tolerance due to changes and diff in NIT) */
575
    if (dvb_network_check_symbol_rate(lm, dmc, deltar)) continue;
576

577
    /* Reject if not same polarisation */
578
    if (lm->lm_tuning.u.dmc_fe_qpsk.polarisation != dmc->u.dmc_fe_qpsk.polarisation) continue;
579

580
    /* DVB-S extra checks */
581
    if (!approx_match && (lm->lm_tuning.dmc_fe_type == DVB_TYPE_S)) {
582

583
      /* Same modulation */
584
      if (!dvb_modulation_is_none_or_auto(lm->lm_tuning.dmc_fe_modulation) &&
585
          !dvb_modulation_is_none_or_auto(dmc->dmc_fe_modulation) &&
586
          lm->lm_tuning.dmc_fe_modulation != dmc->dmc_fe_modulation) continue;
587

588
      /* Same FEC */
589
      if (lm->lm_tuning.u.dmc_fe_qpsk.fec_inner != dmc->u.dmc_fe_qpsk.fec_inner) continue;
590

591
      /* Same orbital position */
592
      if (dvb_network_check_orbital_pos(lm->lm_tuning.u.dmc_fe_qpsk.orbital_pos,
593
                                        dmc->u.dmc_fe_qpsk.orbital_pos)) continue;
594
    }
595

596
    /* Same PLP/ISI */
597
    if (lm->lm_tuning.dmc_fe_stream_id != dmc->dmc_fe_stream_id) continue;
598

599
    mm_alt = mm;
600

601
    /* Reject if not same ID */
602
    if (onid != MPEGTS_ONID_NONE && mm->mm_onid != MPEGTS_ONID_NONE && mm->mm_onid != onid) continue;
603
    if (tsid != MPEGTS_TSID_NONE && mm->mm_tsid != MPEGTS_TSID_NONE && mm->mm_tsid != tsid) continue;
604

605
    break;
606
  }
607
  if (!mm && onid != MPEGTS_ONID_NONE && tsid != MPEGTS_TSID_NONE) {
608
    /* use the mux with closest parameters */
609
    /* unfortunately, the onid and tsid might DIFFER */
610
    /* in the NIT table information and real mux feed */
611
    mm = mm_alt;
612
  }
613
  return (dvb_mux_t *)mm;
614
}
615

616
static htsmsg_t *
617
dvb_network_config_save ( mpegts_network_t *mn, char *filename, size_t fsize )
618
{
619
  htsmsg_t *c = htsmsg_create_map();
620
  char ubuf[UUID_HEX_SIZE];
621
  idnode_save(&mn->mn_id, c);
622
  htsmsg_add_str(c, "class", mn->mn_id.in_class->ic_class);
623
  if (filename)
624
    snprintf(filename, fsize, "input/dvb/networks/%s/config",
625
             idnode_uuid_as_str(&mn->mn_id, ubuf));
626
  return c;
627
}
628

629
const idclass_t *
630
dvb_network_mux_class
631
  ( mpegts_network_t *mn )
632
{
633
  if (idnode_is_instance(&mn->mn_id, &dvb_network_dvbt_class))
634
    return &dvb_mux_dvbt_class;
635
  if (idnode_is_instance(&mn->mn_id, &dvb_network_dvbc_class))
636
    return &dvb_mux_dvbc_class;
637
  if (idnode_is_instance(&mn->mn_id, &dvb_network_dvbs_class))
638
    return &dvb_mux_dvbs_class;
639
  if (idnode_is_instance(&mn->mn_id, &dvb_network_atsc_t_class))
640
    return &dvb_mux_atsc_t_class;
641
  if (idnode_is_instance(&mn->mn_id, &dvb_network_atsc_c_class))
642
    return &dvb_mux_atsc_c_class;
643
  if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_t_class))
644
    return &dvb_mux_isdb_t_class;
645
  if (idnode_is_instance(&mn->mn_id, &dvb_network_cablecard_class))
646
    return &dvb_mux_cablecard_class;
647
  if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_c_class))
648
    return &dvb_mux_isdb_c_class;
649
  if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_s_class))
650
    return &dvb_mux_isdb_s_class;
651
  if (idnode_is_instance(&mn->mn_id, &dvb_network_dtmb_class))
652
    return &dvb_mux_dtmb_class;
653
  if (idnode_is_instance(&mn->mn_id, &dvb_network_dab_class))
654
    return &dvb_mux_dab_class;
655
  return NULL;
656
}
657

658
#define CBIT_ORBITAL_POS        (1<<0)
659
#define CBIT_POLARISATION       (1<<1)
660
#define CBIT_FREQ               (1<<2)
661
#define CBIT_RATE               (1<<3)
662
#define CBIT_RATE_HP            (1<<4)
663
#define CBIT_RATE_LP            (1<<5)
664
#define CBIT_MODULATION         (1<<6)
665
#define CBIT_INVERSION          (1<<7)
666
#define CBIT_ROLLOFF            (1<<8)
667
#define CBIT_PILOT              (1<<9)
668
#define CBIT_STREAM_ID          (1<<10)
669
#define CBIT_BANDWIDTH          (1<<11)
670
#define CBIT_TRANS_MODE         (1<<12)
671
#define CBIT_GUARD              (1<<13)
672
#define CBIT_HIERARCHY          (1<<14)
673
#define CBIT_PLS_MODE           (1<<15)
674
#define CBIT_PLS_CODE           (1<<16)
675
#define CBIT_FEC_INNER          (1<<17)
676

677
static mpegts_mux_t *
678
dvb_network_create_mux
679
  ( mpegts_network_t *mn, void *origin, uint16_t onid, uint16_t tsid,
680
    void *p, int force )
681
{
682
  int save = 0, satpos;
683
  dvb_mux_t *mm;
684
  dvb_network_t *ln;
685
  dvb_mux_conf_t *dmc = p;
686
  const idclass_t *cls = dvb_network_mux_class(mn);
687

688
  tvhinfo(LS_MPEGTS, "dvb create mux: onid %d tsid %d force %d", onid, tsid, force);
689

690
  /* when forced - try to look also to another DVB-S networks */
691
  if (force && cls == &dvb_mux_dvbs_class && dmc->dmc_fe_type == DVB_TYPE_S &&
692
      dmc->u.dmc_fe_qpsk.orbital_pos != INT_MAX) {
693
    satpos = dvb_network_get_orbital_pos(mn);
694
    if (dvb_network_check_orbital_pos(satpos, dmc->u.dmc_fe_qpsk.orbital_pos)) {
695
      LIST_FOREACH(mn, &mpegts_network_all, mn_global_link) {
696
        if (!idnode_is_instance(&mn->mn_id, &dvb_network_dvbs_class)) continue;
697
        satpos = dvb_network_get_orbital_pos(mn);
698
        if (satpos == INT_MAX) continue;
699
        if (!dvb_network_check_orbital_pos(satpos, dmc->u.dmc_fe_qpsk.orbital_pos))
700
          break;
701
      }
702
      if (mn == NULL)
703
        return NULL;
704
    }
705
  }
706

707
  ln = (dvb_network_t*)mn;
708
  mm = dvb_network_find_mux(ln, dmc, onid, tsid, 0, 0);
709
  tvhdebug(LS_MPEGTS, "dvb create mux: mm %p discovery %d", mm, ln->mn_autodiscovery);
710
  if (!mm && (ln->mn_autodiscovery != MN_DISCOVERY_DISABLE || force)) {
711
    cls = dvb_network_mux_class((mpegts_network_t *)ln);
712
    tvhdebug(LS_MPEGTS, "dvb create mux: class = %p, dvbc class = %p", cls, &dvb_mux_dvbc_class);
713
    save |= dvb_fe_type_by_network_class(cls) == dmc->dmc_fe_type;
714
    tvhdebug(LS_MPEGTS, "dvb create mux: network fe type %d dmc fe type %d",  dvb_fe_type_by_network_class(cls), dmc->dmc_fe_type);
715
    if (save && dmc->dmc_fe_type == DVB_TYPE_S) {
716
      satpos = dvb_network_get_orbital_pos(mn);
717
      /* do not allow to mix satellite positions */
718
      if (dvb_network_check_orbital_pos(satpos, dmc->u.dmc_fe_qpsk.orbital_pos))
719
        save = 0;
720
    }
721
    if (save) {
722
      mm = dvb_mux_create0(ln, onid, tsid, dmc, NULL, NULL);
723
      mpegts_mux_post_create((mpegts_mux_t *)mm);
724
      if (tvhtrace_enabled()) {
725
        char buf[128];
726
        dvb_mux_conf_str(&((dvb_mux_t *)mm)->lm_tuning, buf, sizeof(buf));
727
        tvhtrace(LS_MPEGTS, "mux %p %s onid %i tsid %i added to network %s (autodiscovery)",
728
                 mm, buf, onid, tsid, mm->mm_network->mn_network_name);
729
      }
730
    }
731
  } else if (mm) {
732
    char buf[128];
733
    dvb_mux_conf_t tuning_new, tuning_old;
734
    dvb_mux_t *lm = (dvb_mux_t*)mm;
735
    int change = (ln->mn_autodiscovery == MN_DISCOVERY_CHANGE) || force;
736
    /* the nit tables may be inconsistent (like rolloff ping-pong) */
737
    /* accept information only from one origin mux */
738
    if (mm->mm_dmc_origin_expire > mclk() && mm->mm_dmc_origin && mm->mm_dmc_origin != origin)
739
      goto noop;
740
    #define COMPARE(x, cbit) ({ \
741
      int xr = dmc->x != lm->lm_tuning.x; \
742
      if (xr) { \
743
        tvhtrace(LS_MPEGTS, "create mux dmc->" #x " (%li) != lm->lm_tuning." #x \
744
                 " (%li)", (long)dmc->x, (long)tuning_new.x); \
745
        tuning_new.x = dmc->x; \
746
      } xr ? cbit : 0; })
747
    #define COMPAREN(x, cbit) ({ \
748
      int xr = dmc->x != 0 && dmc->x != 1 && dmc->x != tuning_new.x; \
749
      if (xr) { \
750
        tvhtrace(LS_MPEGTS, "create mux dmc->" #x " (%li) != lm->lm_tuning." #x \
751
                 " (%li)", (long)dmc->x, (long)tuning_new.x); \
752
        tuning_new.x = dmc->x; \
753
      } xr ? cbit : 0; })
754
    #define COMPAREN0(x, cbit) ({ \
755
      int xr = dmc->x != 1 && dmc->x != tuning_new.x; \
756
      if (xr) { \
757
        tvhtrace(LS_MPEGTS, "create mux dmc->" #x " (%li) != lm->lm_tuning." #x \
758
                 " (%li)", (long)dmc->x, (long)tuning_new.x); \
759
        tuning_new.x = dmc->x; \
760
      } xr ? cbit : 0; })
761
    tuning_new = tuning_old = lm->lm_tuning;
762
    /* Always save the orbital position */
763
    if (dmc->dmc_fe_type == DVB_TYPE_S) {
764
      if (dmc->u.dmc_fe_qpsk.orbital_pos == INT_MAX ||
765
          dvb_network_check_orbital_pos(tuning_new.u.dmc_fe_qpsk.orbital_pos,
766
                                        dmc->u.dmc_fe_qpsk.orbital_pos)) {
767
        save |= COMPARE(u.dmc_fe_qpsk.orbital_pos, CBIT_ORBITAL_POS);
768
        tuning_new.u.dmc_fe_qpsk.orbital_pos = dmc->u.dmc_fe_qpsk.orbital_pos;
769
      }
770
    }
771
    /* Do not change anything else without autodiscovery flag */
772
    if (!ln->mn_autodiscovery)
773
      goto save;
774
    /* Handle big diffs that have been allowed through for DVB-S */
775
    if (deltaU32(dmc->dmc_fe_freq, tuning_new.dmc_fe_freq) > 4000) {
776
      tuning_new.dmc_fe_freq = dmc->dmc_fe_freq;
777
      save |= CBIT_FREQ;
778
    }
779
    save |= COMPAREN(dmc_fe_modulation, CBIT_MODULATION);
780
    save |= COMPAREN(dmc_fe_inversion, CBIT_INVERSION);
781
    save |= COMPAREN(dmc_fe_rolloff, CBIT_ROLLOFF);
782
    save |= COMPAREN(dmc_fe_pilot, CBIT_PILOT);
783
    switch (dmc->dmc_fe_type) {
784
    case DVB_TYPE_T:
785
    case DVB_TYPE_DTMB:
786
      save |= COMPARE(dmc_fe_stream_id, CBIT_STREAM_ID);
787
      save |= COMPAREN(u.dmc_fe_ofdm.bandwidth, CBIT_BANDWIDTH);
788
      save |= COMPAREN(u.dmc_fe_ofdm.hierarchy_information, CBIT_HIERARCHY);
789
      save |= COMPAREN(u.dmc_fe_ofdm.code_rate_HP, CBIT_RATE_HP);
790
      save |= COMPAREN0(u.dmc_fe_ofdm.code_rate_LP, CBIT_RATE_LP);
791
      save |= COMPAREN(u.dmc_fe_ofdm.transmission_mode, CBIT_TRANS_MODE);
792
      save |= COMPAREN(u.dmc_fe_ofdm.guard_interval, CBIT_GUARD);
793
      break;
794
    case DVB_TYPE_S:
795
      save |= COMPARE(u.dmc_fe_qpsk.polarisation, CBIT_POLARISATION);
796
      save |= COMPARE(u.dmc_fe_qpsk.symbol_rate, CBIT_RATE);
797
      save |= COMPARE(dmc_fe_stream_id, CBIT_STREAM_ID);
798
      save |= COMPAREN(dmc_fe_pls_mode, CBIT_PLS_MODE);
799
      save |= COMPAREN(dmc_fe_pls_code, CBIT_PLS_CODE);
800
      save |= COMPAREN(u.dmc_fe_qpsk.fec_inner, CBIT_FEC_INNER);
801
      break;
802
    case DVB_TYPE_C:
803
    case DVB_TYPE_ATSC_C:
804
      save |= COMPARE(u.dmc_fe_qam.symbol_rate, CBIT_RATE);
805
      save |= COMPAREN(u.dmc_fe_qam.fec_inner, CBIT_FEC_INNER);
806
      break;
807
    case DVB_TYPE_ATSC_T:
808
      break;
809
    default:
810
      abort();
811
    }
812
    #undef COMPARE
813
    #undef COMPAREN
814
    /* ignore rolloff only changes (don't save) */
815
    save &= ~CBIT_ROLLOFF;
816
    if (save) {
817
      char muxname[128];
818
      mpegts_mux_nice_name((mpegts_mux_t *)mm, muxname, sizeof(muxname));
819
      dvb_mux_conf_str(&tuning_old, buf, sizeof(buf));
820
      tvhlog(change ? LOG_WARNING : LOG_NOTICE, LS_MPEGTS,
821
             "mux %s%s %s (%08x)", muxname,
822
             change ? " changed from" : " old params", buf, save);
823
      dvb_mux_conf_str(&tuning_new, buf, sizeof(buf));
824
      tvhlog(change ? LOG_WARNING : LOG_NOTICE, LS_MPEGTS,
825
             "mux %s%s %s (%08x)", muxname,
826
             change ? " changed to  " : " new params", buf, save);
827
      if (!change) save = 0;
828
    }
829
    if (save) lm->lm_tuning = tuning_new;
830
  }
831
save:
832
  if (mm && save) {
833
    mm->mm_dmc_origin        = origin;
834
    mm->mm_dmc_origin_expire = mclk() + sec2mono(3600 * 24); /* one day */
835
    idnode_changed(&mm->mm_id);
836
  }
837
noop:
838
  return (mpegts_mux_t *)mm;
839
}
840

841
static mpegts_service_t *
842
dvb_network_create_service
843
  ( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid )
844
{
845
  dvb_mux_t *lm = (dvb_mux_t *)mm;
846
  mpegts_service_t *s;
847

848
  s = mpegts_service_create1(NULL, mm, sid, pmt_pid, NULL);
849

850
  /* Set service values from mux if CableCARD */
851
  if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_CABLECARD) {
852
    mpegts_network_t *ln = mm->mm_network;
853
    if (!s->s_dvb_provider && lm->mm_provider_network_name)
854
      s->s_dvb_provider = strdup(lm->mm_provider_network_name);
855
    if (!s->s_dvb_provider && ln->mn_provider_network_name)
856
      s->s_dvb_provider = strdup(ln->mn_provider_network_name);
857
    if (!s->s_dvb_channel_num)
858
      s->s_dvb_channel_num = lm->lm_tuning.u.dmc_fe_cablecard.vchannel;
859
    if (!s->s_dvb_svcname && lm->lm_tuning.u.dmc_fe_cablecard.name)
860
      s->s_dvb_svcname = strdup(lm->lm_tuning.u.dmc_fe_cablecard.name);
861
  }
862

863
  return s;
864
}
865

866
static mpegts_mux_t *
867
dvb_network_mux_create2
868
  ( mpegts_network_t *mn, htsmsg_t *conf )
869
{
870
  dvb_network_t *ln = (dvb_network_t*)mn;
871
  dvb_mux_t *mm;
872
  mm = dvb_mux_create0(ln, MPEGTS_ONID_NONE, MPEGTS_TSID_NONE,
873
                       NULL, NULL, conf);
874
  return mpegts_mux_post_create((mpegts_mux_t *)mm);
875
}
876

877
/* ****************************************************************************
878
 * Creation/Config
879
 * ***************************************************************************/
880

881
dvb_network_t *
882
dvb_network_create0
883
  ( const char *uuid, const idclass_t *idc, htsmsg_t *conf )
884
{
885
  dvb_network_t *ln;
886
  dvb_mux_t *lm;
887
  htsmsg_t *c, *e;
888
  htsmsg_field_t *f;
889
  const char *s;
890

891
  ln = calloc(1, sizeof(dvb_network_t));
892
  ln->ln_type = dvb_fe_type_by_network_class(idc);
893
  assert(ln->ln_type != DVB_TYPE_NONE);
894

895
  /* Create */
896
  if (!(ln = (dvb_network_t*)mpegts_network_create0((void*)ln,
897
                                     idc, uuid, NULL, conf)))
898
    return NULL;
899

900
  /* Callbacks */
901
  ln->mn_create_mux     = dvb_network_create_mux;
902
  ln->mn_create_service = dvb_network_create_service;
903
  ln->mn_config_save    = dvb_network_config_save;
904
  ln->mn_mux_class      = dvb_network_mux_class;
905
  ln->mn_mux_create2    = dvb_network_mux_create2;
906

907
  /* No config */
908
  if (!conf)
909
    return ln;
910

911
  /* Set predefined muxes */
912
  /* Because PO_NOSAVE in idnode_load() this value is not set on load */
913
  if ((s = htsmsg_get_str(conf, "scanfile")) != NULL)
914
    dvb_network_class_scanfile_set(ln, s);
915

916
  /* Load muxes */
917
  if ((c = hts_settings_load_r(1, "input/dvb/networks/%s/muxes", uuid))) {
918
    HTSMSG_FOREACH(f, c) {
919
      if (!(e = htsmsg_get_map_by_field(f)))  continue;
920
      if (!(e = htsmsg_get_map(e, "config"))) continue;
921
      lm = dvb_mux_create1(ln, htsmsg_field_name(f), e);
922
      mpegts_mux_post_create((mpegts_mux_t *)lm);
923
    }
924
    htsmsg_destroy(c);
925
  }
926

927
  return ln;
928
}
929

930
static mpegts_network_t *
931
dvb_network_builder
932
  ( const idclass_t *idc, htsmsg_t *conf )
933
{
934
  return (mpegts_network_t*)dvb_network_create0(NULL, idc, conf);
935
}
936

937
static const idclass_t * dvb_network_classes[] = {
938
  &dvb_network_dvbt_class,
939
  &dvb_network_dvbc_class,
940
  &dvb_network_dvbs_class,
941
  &dvb_network_atsc_t_class,
942
  &dvb_network_atsc_c_class,
943
  &dvb_network_cablecard_class,
944
  &dvb_network_isdb_t_class,
945
  &dvb_network_isdb_c_class,
946
  &dvb_network_isdb_s_class,
947
#if 0 /* TODO: write DAB stream parser */
948
  &dvb_network_dab_class,
949
#endif
950
};
951

952
static const idclass_t * dvb_mux_classes[] = {
953
  &dvb_mux_dvbt_class,
954
  &dvb_mux_dvbc_class,
955
  &dvb_mux_dvbs_class,
956
  &dvb_mux_atsc_t_class,
957
  &dvb_mux_atsc_c_class,
958
  &dvb_mux_cablecard_class,
959
  &dvb_mux_isdb_t_class,
960
  &dvb_mux_isdb_c_class,
961
  &dvb_mux_isdb_s_class,
962
#if 0 /* TODO: write DAB stream parser */
963
  &dvb_mux_dab_class,
964
#endif
965
};
966

967
void dvb_network_init ( void )
968
{
969
  htsmsg_t *c, *e;
970
  htsmsg_field_t *f;
971
  const char *s;
972
  int i;
973

974
  /* Load list of mux charset global overrides */
975
  dvb_charset_init();
976

977
  /* Register mux classes */
978
  for (i = 0; i < ARRAY_SIZE(dvb_mux_classes); i++)
979
    idclass_register(dvb_mux_classes[i]);
980

981
  /* Register class builders */
982
  for (i = 0; i < ARRAY_SIZE(dvb_network_classes); i++)
983
    mpegts_network_register_builder(dvb_network_classes[i],
984
                                    dvb_network_builder);
985

986
  /* Load settings */
987
  if (!(c = hts_settings_load_r(1, "input/dvb/networks")))
988
    return;
989

990
  HTSMSG_FOREACH(f, c) {
991
    if (!(e = htsmsg_get_map_by_field(f)))  continue;
992
    if (!(e = htsmsg_get_map(e, "config"))) continue;
993
    if (!(s = htsmsg_get_str(e, "class")))  continue;
994
    for (i = 0; i < ARRAY_SIZE(dvb_network_classes); i++) {
995
      if (strcmp(s, "dvb_network_atsc") == 0)
996
        s = "dvb_network_atsc_t";
997
      if(!strcmp(dvb_network_classes[i]->ic_class, s)) {
998
        dvb_network_create0(htsmsg_field_name(f), dvb_network_classes[i], e);
999
        break;
1000
      }
1001
    }
1002
  }
1003
  htsmsg_destroy(c);
1004
}
1005

1006
void dvb_network_done ( void )
1007
{
1008
  int i;
1009

1010
  tvh_mutex_lock(&global_lock);
1011
  /* Unregister class builders */
1012
  for (i = 0; i < ARRAY_SIZE(dvb_network_classes); i++) {
1013
    mpegts_network_unregister_builder(dvb_network_classes[i]);
1014
    mpegts_network_class_delete(dvb_network_classes[i], 0);
1015
  }
1016
  tvh_mutex_unlock(&global_lock);
1017

1018
  dvb_charset_done();
1019
  scanfile_done();
1020
}
1021

1022
/* ****************************************************************************
1023
 * Search
1024
 * ***************************************************************************/
1025

1026
const idclass_t *dvb_network_class_by_fe_type(dvb_fe_type_t type)
1027
{
1028
  if (type == DVB_TYPE_T)
1029
    return &dvb_network_dvbt_class;
1030
  else if (type == DVB_TYPE_C)
1031
    return &dvb_network_dvbc_class;
1032
  else if (type == DVB_TYPE_S)
1033
    return &dvb_network_dvbs_class;
1034
  else if (type == DVB_TYPE_ATSC_T)
1035
    return &dvb_network_atsc_t_class;
1036
  else if (type == DVB_TYPE_ATSC_C)
1037
    return &dvb_network_atsc_c_class;
1038
  else if (type == DVB_TYPE_CABLECARD)
1039
    return &dvb_network_cablecard_class;
1040
  else if (type == DVB_TYPE_ISDB_T)
1041
    return &dvb_network_isdb_t_class;
1042
  else if (type == DVB_TYPE_ISDB_C)
1043
    return &dvb_network_isdb_c_class;
1044
  else if (type == DVB_TYPE_ISDB_S)
1045
    return &dvb_network_isdb_s_class;
1046
  else if (type == DVB_TYPE_DTMB)
1047
    return &dvb_network_dtmb_class;
1048
  else if (type == DVB_TYPE_DAB)
1049
    return &dvb_network_dab_class;
1050

1051
  return NULL;
1052
}
1053

1054
dvb_fe_type_t dvb_fe_type_by_network_class(const idclass_t *idc)
1055
{
1056
  if (idc == &dvb_network_dvbt_class)
1057
    return DVB_TYPE_T;
1058
  else if (idc == &dvb_network_dvbc_class)
1059
    return DVB_TYPE_C;
1060
  else if (idc == &dvb_network_dvbs_class)
1061
    return DVB_TYPE_S;
1062
  else if (idc == &dvb_network_atsc_t_class)
1063
    return DVB_TYPE_ATSC_T;
1064
  else if (idc == &dvb_network_atsc_c_class)
1065
    return DVB_TYPE_ATSC_C;
1066
  else if (idc == &dvb_network_cablecard_class)
1067
    return DVB_TYPE_CABLECARD;
1068
  else if (idc == &dvb_network_isdb_t_class)
1069
    return DVB_TYPE_ISDB_T;
1070
  else if (idc == &dvb_network_isdb_c_class)
1071
    return DVB_TYPE_ISDB_C;
1072
  else if (idc == &dvb_network_isdb_s_class)
1073
    return DVB_TYPE_ISDB_S;
1074
  else if (idc == &dvb_network_dtmb_class)
1075
    return DVB_TYPE_DTMB;
1076
  else if (idc == &dvb_network_dab_class)
1077
    return DVB_TYPE_DAB;
1078

1079
  return DVB_TYPE_NONE;
1080
}
1081

1082
idnode_set_t *dvb_network_list_by_fe_type(dvb_fe_type_t type)
1083
{
1084
  const idclass_t *idc = dvb_network_class_by_fe_type(type);
1085

1086
  if (!idc)
1087
    return NULL;
1088

1089
  return idnode_find_all(idc, NULL);
1090
}
1091

1092
int dvb_network_get_orbital_pos(mpegts_network_t *mn)
1093
{
1094
  dvb_network_t *ln = (dvb_network_t *)mn;
1095
  mpegts_mux_t  *mm;
1096
  dvb_mux_t     *lm = NULL;
1097

1098
  if (!ln)
1099
    return INT_MAX;
1100
  if (tvhtrace_enabled()) {
1101
    if (!idnode_is_instance(&mn->mn_id, &dvb_network_dvbs_class)) {
1102
      tvhinfo(LS_MPEGTS, "wrong dvb_network_get_orbital_pos() call");
1103
      return INT_MAX;
1104
    }
1105
  }
1106
  if (ln->mn_satpos != INT_MAX)
1107
    return ln->mn_satpos;
1108
  LIST_FOREACH(mm, &ln->mn_muxes, mm_network_link) {
1109
    lm = (dvb_mux_t *)mm;
1110
    if (lm->lm_tuning.u.dmc_fe_qpsk.orbital_pos != INT_MAX)
1111
      break;
1112
  }
1113
  if (mm)
1114
    return lm->lm_tuning.u.dmc_fe_qpsk.orbital_pos;
1115
  return INT_MAX;
1116
}
1117

1118
/******************************************************************************
1119
 * Editor Configuration
1120
 *
1121
 * vim:sts=2:ts=2:sw=2:et
1122
 *****************************************************************************/
(4-4/5)