Project

General

Profile

RE: UK Cable OTA EPG » mpegts.h

Paul Williams, 2016-08-23 13:07

 
1
/*
2
 *  Tvheadend - TS file input system
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
#ifndef __TVH_MPEGTS_H__
21
#define __TVH_MPEGTS_H__
22

    
23
#ifndef __TVH_INPUT_H__
24
#error "Use header file input.h not input/mpegts.h"
25
#endif
26

    
27
#include "atomic.h"
28
#include "input.h"
29
#include "service.h"
30
#include "mpegts/dvb.h"
31
#include "subscriptions.h"
32

    
33
#define MPEGTS_ONID_NONE        0xFFFF
34
#define MPEGTS_TSID_NONE        0xFFFF
35
#define MPEGTS_FULLMUX_PID      0x2000
36
#define MPEGTS_TABLES_PID       0x2001
37
#define MPEGTS_PID_NONE         0xFFFF
38

    
39
/* Types */
40
typedef struct mpegts_apid          mpegts_apid_t;
41
typedef struct mpegts_apids         mpegts_apids_t;
42
typedef struct mpegts_table         mpegts_table_t;
43
typedef struct mpegts_network       mpegts_network_t;
44
typedef struct mpegts_mux           mpegts_mux_t;
45
typedef struct mpegts_service       mpegts_service_t;
46
typedef struct mpegts_mux_instance  mpegts_mux_instance_t;
47
typedef struct mpegts_mux_sub       mpegts_mux_sub_t;
48
typedef struct mpegts_input         mpegts_input_t;
49
typedef struct mpegts_table_feed    mpegts_table_feed_t;
50
typedef struct mpegts_network_link  mpegts_network_link_t;
51
typedef struct mpegts_packet        mpegts_packet_t;
52
typedef struct mpegts_pcr           mpegts_pcr_t;
53
typedef struct mpegts_buffer        mpegts_buffer_t;
54

    
55
/* Lists */
56
typedef LIST_HEAD (,mpegts_network)             mpegts_network_list_t;
57
typedef LIST_HEAD (,mpegts_input)               mpegts_input_list_t;
58
typedef TAILQ_HEAD(mpegts_mux_queue,mpegts_mux) mpegts_mux_queue_t;
59
typedef LIST_HEAD (,mpegts_mux)                 mpegts_mux_list_t;
60
typedef LIST_HEAD (,mpegts_network_link)        mpegts_network_link_list_t;
61
typedef TAILQ_HEAD(mpegts_table_feed_queue, mpegts_table_feed)
62
  mpegts_table_feed_queue_t;
63

    
64
/* Classes */
65
extern const idclass_t mpegts_network_class;
66
extern const idclass_t mpegts_mux_class;
67
extern const idclass_t mpegts_mux_instance_class;
68
extern const idclass_t mpegts_service_class;
69
extern const idclass_t mpegts_service_raw_class;
70
extern const idclass_t mpegts_input_class;
71

    
72
/* **************************************************************************
73
 * Setup / Tear down
74
 * *************************************************************************/
75

    
76
void mpegts_init ( int linuxdvb_mask, int nosatip, str_list_t *satip_client,
77
                   str_list_t *tsfiles, int tstuners );
78
void mpegts_done ( void );
79

    
80
/* **************************************************************************
81
 * PIDs
82
 * *************************************************************************/
83

    
84
struct mpegts_apid {
85
  uint16_t pid;
86
  uint16_t weight;
87
};
88

    
89
struct mpegts_apids {
90
  mpegts_apid_t *pids;
91
  int alloc;
92
  int count;
93
  int all;
94
  int sorted;
95
};
96

    
97
int mpegts_pid_init ( mpegts_apids_t *pids );
98
void mpegts_pid_done ( mpegts_apids_t *pids );
99
mpegts_apids_t *mpegts_pid_alloc ( void );
100
void mpegts_pid_destroy ( mpegts_apids_t **pids );
101
void mpegts_pid_reset ( mpegts_apids_t *pids );
102
int mpegts_pid_add ( mpegts_apids_t *pids, uint16_t pid, uint16_t weight );
103
int mpegts_pid_add_group ( mpegts_apids_t *pids, mpegts_apids_t *vals );
104
int mpegts_pid_del ( mpegts_apids_t *pids, uint16_t pid, uint16_t weight );
105
int mpegts_pid_del_group ( mpegts_apids_t *pids, mpegts_apids_t *vals );
106
int mpegts_pid_find_windex ( mpegts_apids_t *pids, uint16_t pid, uint16_t weight );
107
int mpegts_pid_find_rindex ( mpegts_apids_t *pids, uint16_t pid );
108
static inline int mpegts_pid_wexists ( mpegts_apids_t *pids, uint16_t pid, uint16_t weight )
109
  { return pids->all || mpegts_pid_find_windex(pids, pid, weight) >= 0; }
110
static inline int mpegts_pid_rexists ( mpegts_apids_t *pids, uint16_t pid )
111
  { return pids->all || mpegts_pid_find_rindex(pids, pid) >= 0; }
112
int mpegts_pid_copy ( mpegts_apids_t *dst, mpegts_apids_t *src );
113
int mpegts_pid_compare ( mpegts_apids_t *dst, mpegts_apids_t *src,
114
                         mpegts_apids_t *add, mpegts_apids_t *del );
115
int mpegts_pid_weighted( mpegts_apids_t *dst, mpegts_apids_t *src, int limit );
116
int mpegts_pid_dump ( mpegts_apids_t *pids, char *buf, int len, int wflag, int raw );
117

    
118
/* **************************************************************************
119
 * Data / SI processing
120
 * *************************************************************************/
121

    
122
struct mpegts_packet
123
{
124
  TAILQ_ENTRY(mpegts_packet)  mp_link;
125
  size_t                      mp_len;
126
  mpegts_mux_t               *mp_mux;
127
  uint8_t                     mp_cc_restart;
128
  uint8_t                     mp_data[0];
129
};
130

    
131
struct mpegts_pcr {
132
  int64_t  pcr_first;
133
  int64_t  pcr_last;
134
  uint16_t pcr_pid;
135
};
136

    
137
#define MPEGTS_DATA_CC_RESTART (1<<0)
138

    
139
typedef int (*mpegts_table_callback_t)
140
  ( mpegts_table_t*, const uint8_t *buf, int len, int tableid );
141

    
142
struct mpegts_table_mux_cb
143
{
144
  int tag;
145
  int (*cb) ( mpegts_table_t*, mpegts_mux_t *mm, uint16_t nbid,
146
              const uint8_t dtag, const uint8_t *dptr, int dlen );
147
};
148

    
149
typedef struct mpegts_pid_sub
150
{
151
  RB_ENTRY(mpegts_pid_sub) mps_link;
152
  LIST_ENTRY(mpegts_pid_sub) mps_raw_link;
153
  LIST_ENTRY(mpegts_pid_sub) mps_svcraw_link;
154
#define MPS_NONE    0x00
155
#define MPS_ALL     0x01
156
#define MPS_RAW     0x02
157
#define MPS_STREAM  0x04
158
#define MPS_SERVICE 0x08
159
#define MPS_TABLE   0x10
160
#define MPS_FTABLE  0x20
161
#define MPS_TABLES  0x40
162
  int   mps_type;
163
#define MPS_WEIGHT_PAT     1000
164
#define MPS_WEIGHT_CAT      999
165
#define MPS_WEIGHT_SDT      999
166
#define MPS_WEIGHT_NIT      999
167
#define MPS_WEIGHT_BAT      999
168
#define MPS_WEIGHT_VCT      999
169
#define MPS_WEIGHT_EIT      999
170
#define MPS_WEIGHT_ETT      999
171
#define MPS_WEIGHT_MGT      999
172
#define MPS_WEIGHT_PMT      998
173
#define MPS_WEIGHT_PCR      997
174
#define MPS_WEIGHT_CA       996
175
#define MPS_WEIGHT_VIDEO    900
176
#define MPS_WEIGHT_AUDIO    800
177
#define MPS_WEIGHT_SUBTITLE 700
178
#define MPS_WEIGHT_ESOTHER  500
179
#define MPS_WEIGHT_RAW      400
180
#define MPS_WEIGHT_NIT2     300
181
#define MPS_WEIGHT_SDT2     300
182
#define MPS_WEIGHT_TDT      101
183
#define MPS_WEIGHT_STT      101
184
#define MPS_WEIGHT_PMT_SCAN 100
185
  int   mps_weight;
186
  void *mps_owner;
187
} mpegts_pid_sub_t;
188

    
189
typedef struct mpegts_pid
190
{
191
  int                      mp_pid;
192
  int                      mp_type; // mask for all subscribers
193
  int8_t                   mp_cc;
194
  RB_HEAD(,mpegts_pid_sub) mp_subs; // subscribers to pid
195
  LIST_HEAD(,mpegts_pid_sub) mp_raw_subs;
196
  LIST_HEAD(,mpegts_pid_sub) mp_svc_subs;
197
  RB_ENTRY(mpegts_pid)     mp_link;
198
} mpegts_pid_t;
199

    
200
struct mpegts_table
201
{
202
  mpegts_psi_table_t;
203

    
204
  /**
205
   * Flags, must never be changed after creation.
206
   * We inspect it without holding global_lock
207
   */
208
  int mt_flags;
209

    
210
#define MT_CRC        0x0001
211
#define MT_FULL       0x0002
212
#define MT_QUICKREQ   0x0004
213
#define MT_FASTSWITCH 0x0008
214
#define MT_ONESHOT    0x0010
215
#define MT_RECORD     0x0020
216
#define MT_SKIPSUBS   0x0040
217
#define MT_SCANSUBS   0x0080
218
#define MT_FAST       0x0100
219
#define MT_SLOW       0x0200
220
#define MT_DEFER      0x0400
221

    
222
  /**
223
   * PID subscription weight
224
   */
225
  int mt_weight;
226

    
227
  /**
228
   * Cycle queue
229
   * Tables that did not get a fd or filter in hardware will end up here
230
   * waiting for any other table to be received so it can reuse that fd.
231
   * Only linked if fd == -1
232
   */
233
  TAILQ_ENTRY(mpegts_table) mt_pending_link;
234

    
235
  /**
236
   * File descriptor for filter
237
   */
238

    
239
  TAILQ_ENTRY(mpegts_table) mt_defer_link;
240
  mpegts_mux_t *mt_mux;
241

    
242
  void *mt_bat;
243
  mpegts_table_callback_t mt_callback;
244

    
245
  uint8_t mt_subscribed;
246
  uint8_t mt_defer_cmd;
247

    
248
#define MT_DEFER_OPEN_PID  1
249
#define MT_DEFER_CLOSE_PID 2
250

    
251
  int mt_working;
252

    
253
  int mt_count;
254

    
255
  int mt_id;
256
 
257
  int mt_destroyed; // Refcounting
258
  int mt_arefcount;
259

    
260
  struct mpegts_table_mux_cb *mt_mux_cb;
261

    
262
  mpegts_service_t *mt_service;
263
  
264
  void (*mt_destroy) (mpegts_table_t *mt); // Allow customisable destroy hook
265
                                           // useful for dynamic allocation of
266
                                           // the opaque field
267
};
268

    
269
/**
270
 * When in raw mode we need to enqueue raw TS packet
271
 * to a different thread because we need to hold
272
 * global_lock when doing delivery of the tables
273
 */
274

    
275
struct mpegts_table_feed {
276
  TAILQ_ENTRY(mpegts_table_feed) mtf_link;
277
  int mtf_len;
278
  mpegts_mux_t *mtf_mux;
279
  uint8_t mtf_tsb[0];
280
};
281

    
282
/* **************************************************************************
283
 * Logical network
284
 * *************************************************************************/
285

    
286
typedef enum {
287
  MN_DISCOVERY_DISABLE = 0,
288
  MN_DISCOVERY_NEW     = 1,
289
  MN_DISCOVERY_CHANGE  = 2
290
} mpegts_discovery_t;
291

    
292
/* Network/Input linkage */
293
struct mpegts_network_link
294
{
295
  int                             mnl_mark;
296
  mpegts_input_t                  *mnl_input;
297
  mpegts_network_t                *mnl_network;
298
  LIST_ENTRY(mpegts_network_link) mnl_mn_link;
299
  LIST_ENTRY(mpegts_network_link) mnl_mi_link;
300
};
301

    
302
/* Network */
303
struct mpegts_network
304
{
305
  idnode_t                   mn_id;
306
  LIST_ENTRY(mpegts_network) mn_global_link;
307

    
308
  /*
309
   * Identification
310
   */
311
  char                    *mn_network_name;
312
  char                    *mn_provider_network_name;
313
  int                      mn_wizard;
314
  uint8_t                  mn_wizard_free;
315

    
316
  /*
317
   * Inputs
318
   */
319
  mpegts_network_link_list_t   mn_inputs;
320

    
321
  /*
322
   * Multiplexes
323
   */
324
  mpegts_mux_list_t       mn_muxes;
325

    
326
  /*
327
   * Scanning
328
   */
329
  mpegts_mux_queue_t mn_scan_pend;    // Pending muxes
330
  mpegts_mux_queue_t mn_scan_active;  // Active muxes
331
  mtimer_t           mn_scan_timer;   // Timer for activity
332

    
333
  /*
334
   * Functions
335
   */
336
  void              (*mn_delete)       (mpegts_network_t*, int delconf);
337
  void              (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
338
  htsmsg_t *        (*mn_config_save)  (mpegts_network_t*, char *filename, size_t fsize);
339
  mpegts_mux_t*     (*mn_create_mux)
340
    (mpegts_network_t*, void *origin, uint16_t onid, uint16_t tsid,
341
     void *conf, int force);
342
  mpegts_service_t* (*mn_create_service)
343
    (mpegts_mux_t*, uint16_t sid, uint16_t pmt_pid);
344
  const idclass_t*  (*mn_mux_class)   (mpegts_network_t*);
345
  mpegts_mux_t *    (*mn_mux_create2) (mpegts_network_t *mn, htsmsg_t *conf);
346

    
347
  /*
348
   * Configuration
349
   */
350
  uint16_t mn_nid;
351
  uint16_t mn_satip_source;
352
  int      mn_autodiscovery;
353
  int      mn_skipinitscan;
354
  char    *mn_charset;
355
  int      mn_idlescan;
356
  int      mn_ignore_chnum;
357
  int      mn_sid_chnum;
358
  int      mn_localtime;
359
  int      mn_satpos;
360
};
361

    
362
typedef enum mpegts_mux_scan_state
363
{
364
  MM_SCAN_STATE_IDLE,     // Nothing
365
  MM_SCAN_STATE_PEND,     // Queue'd pending scan
366
  MM_SCAN_STATE_ACTIVE,   // Scan is active
367
} mpegts_mux_scan_state_t;
368

    
369
typedef enum mpegts_mux_scan_result
370
{
371
  MM_SCAN_NONE,
372
  MM_SCAN_OK,
373
  MM_SCAN_FAIL,
374
  MM_SCAN_PARTIAL,
375
  MM_SCAN_IGNORE,
376
} mpegts_mux_scan_result_t;
377

    
378
#define MM_SCAN_CHECK_OK(mm) \
379
  ((mm)->mm_scan_result == MM_SCAN_OK || (mm)->mm_scan_result == MM_SCAN_PARTIAL)
380

    
381
enum mpegts_mux_enable
382
{
383
  MM_IGNORE  = -1,
384
  MM_DISABLE =  0,
385
  MM_ENABLE  =  1,
386
};
387

    
388
enum mpegts_mux_epg_flag
389
{
390
  MM_EPG_DISABLE,
391
  MM_EPG_ENABLE,
392
  MM_EPG_FORCE,
393
  MM_EPG_ONLY_EIT,
394
  MM_EPG_ONLY_UK_FREESAT,
395
  MM_EPG_ONLY_UK_FREEVIEW,
396
  MM_EPG_ONLY_VIASAT_BALTIC,
397
  MM_EPG_ONLY_OPENTV_SKY_UK,
398
  MM_EPG_ONLY_OPENTV_SKY_ITALIA,
399
  MM_EPG_ONLY_OPENTV_SKY_AUSAT,
400
  MM_EPG_ONLY_BULSATCOM_39E,
401
  MM_EPG_ONLY_UK_CABLE,
402
  MM_EPG_ONLY_PSIP,
403
};
404
#define MM_EPG_LAST MM_EPG_ONLY_PSIP
405

    
406
enum mpegts_mux_ac3_flag
407
{
408
  MM_AC3_STANDARD,
409
  MM_AC3_PMT_06,
410
  MM_AC3_PMT_N05,
411
};
412

    
413
typedef struct tsdebug_packet {
414
  TAILQ_ENTRY(tsdebug_packet) link;
415
  uint8_t pkt[188];
416
  off_t pos;
417
} tsdebug_packet_t;
418

    
419
/* Multiplex */
420
struct mpegts_mux
421
{
422
  idnode_t mm_id;
423
  int      mm_refcount;
424

    
425
  /*
426
   * Identification
427
   */
428
  
429
  LIST_ENTRY(mpegts_mux)  mm_network_link;
430
  mpegts_network_t       *mm_network;
431
  char                   *mm_provider_network_name;
432
  uint16_t                mm_onid;
433
  uint16_t                mm_tsid;
434
  int                     mm_tsid_checks;
435
  int                     mm_tsid_accept_zero_value;
436
  tvhlog_limit_t          mm_tsid_loglimit;
437

    
438
  int                     mm_update_pids_flag;
439
  mtimer_t                mm_update_pids_timer;
440

    
441
  /*
442
   * Services
443
   */
444
  
445
  LIST_HEAD(,mpegts_service) mm_services;
446

    
447
  /*
448
   * Scanning
449
   */
450

    
451
  mpegts_mux_scan_result_t mm_scan_result;  ///< Result of last scan
452
  int                      mm_scan_weight;  ///< Scan priority
453
  int                      mm_scan_flags;   ///< Subscription flags
454
  int                      mm_scan_init;    ///< Flag to timeout handler
455
  mtimer_t                 mm_scan_timeout; ///< Timer to handle timeout
456
  TAILQ_ENTRY(mpegts_mux)  mm_scan_link;    ///< Link to Queue
457
  mpegts_mux_scan_state_t  mm_scan_state;   ///< Scanning state
458

    
459
#if 0
460
  enum {
461
    MM_ORIG_USER, ///< Manually added
462
    MM_ORIG_FILE, ///< Added from scan file
463
    MM_ORIG_AUTO  ///< From NIT
464
  }                        mm_dmc_origin2;
465
#endif
466
  void                    *mm_dmc_origin;
467
  int64_t                  mm_dmc_origin_expire;
468

    
469
  char                    *mm_fastscan_muxes;
470

    
471
  /*
472
   * Physical instances
473
   */
474

    
475
  LIST_HEAD(, mpegts_mux_instance) mm_instances;
476
  mpegts_mux_instance_t      *mm_active;
477
  LIST_HEAD(,service)         mm_transports;
478

    
479
  /*
480
   * Raw subscriptions
481
   */
482

    
483
  LIST_HEAD(, th_subscription) mm_raw_subs;
484

    
485
  /*
486
   * Data processing
487
   */
488

    
489
  RB_HEAD(, mpegts_pid)       mm_pids;
490
  LIST_HEAD(, mpegts_pid_sub) mm_all_subs;
491
  int                         mm_last_pid;
492
  mpegts_pid_t               *mm_last_mp;
493

    
494
  int                         mm_num_tables;
495
  LIST_HEAD(, mpegts_table)   mm_tables;
496
  TAILQ_HEAD(, mpegts_table)  mm_defer_tables;
497
  pthread_mutex_t             mm_tables_lock;
498
  TAILQ_HEAD(, mpegts_table)  mm_table_queue;
499

    
500
  LIST_HEAD(, caid)           mm_descrambler_caids;
501
  TAILQ_HEAD(, descrambler_table) mm_descrambler_tables;
502
  TAILQ_HEAD(, descrambler_emm) mm_descrambler_emms;
503
  pthread_mutex_t             mm_descrambler_lock;
504
  int                         mm_descrambler_flush;
505

    
506
  /*
507
   * Functions
508
   */
509

    
510
  void (*mm_delete)           (mpegts_mux_t *mm, int delconf);
511
  void (*mm_free)             (mpegts_mux_t *mm);
512
  htsmsg_t *(*mm_config_save) (mpegts_mux_t *mm, char *filename, size_t fsize);
513
  void (*mm_display_name)     (mpegts_mux_t*, char *buf, size_t len);
514
  int  (*mm_is_enabled)       (mpegts_mux_t *mm);
515
  void (*mm_stop)             (mpegts_mux_t *mm, int force, int reason);
516
  void (*mm_open_table)       (mpegts_mux_t*,mpegts_table_t*,int subscribe);
517
  void (*mm_unsubscribe_table)(mpegts_mux_t*,mpegts_table_t*);
518
  void (*mm_close_table)      (mpegts_mux_t*,mpegts_table_t*);
519
  void (*mm_create_instances) (mpegts_mux_t*);
520
  int  (*mm_is_epg)           (mpegts_mux_t*);
521

    
522
  /*
523
   * Configuration
524
   */
525
  char *mm_crid_authority;
526
  int   mm_enabled;
527
  int   mm_epg;
528
  char *mm_charset;
529
  int   mm_pmt_ac3;
530
  int   mm_eit_tsid_nocheck;
531

    
532
  /*
533
   * TSDEBUG
534
   */
535
#if ENABLE_TSDEBUG
536
  int   mm_tsdebug_fd;
537
  int   mm_tsdebug_fd2;
538
  off_t mm_tsdebug_pos;
539
  TAILQ_HEAD(, tsdebug_packet) mm_tsdebug_packets;
540
#endif
541
};
542

    
543
#define PREFCAPID_OFF      0
544
#define PREFCAPID_ON       1
545
#define PREFCAPID_FORCE    2
546

    
547
/* Service */
548
struct mpegts_service
549
{
550
  service_t; // Parent
551

    
552
  int (*s_update_pids)(mpegts_service_t *t, struct mpegts_apids *pids);
553
  int (*s_link)(mpegts_service_t *master, mpegts_service_t *slave);
554
  int (*s_unlink)(mpegts_service_t *master, mpegts_service_t *slave);
555

    
556
  int      s_dvb_subscription_flags;
557
  int      s_dvb_subscription_weight;
558

    
559
  mpegts_apids_t             *s_pids;
560
  idnode_set_t                s_masters;
561
  LIST_HEAD(, mpegts_service) s_slaves;
562
  LIST_ENTRY(mpegts_service)  s_slaves_link;
563
  mpegts_apids_t             *s_slaves_pids;
564

    
565
  /*
566
   * Fields defined by DVB standard EN 300 468
567
   */
568

    
569
  uint32_t s_dvb_channel_num;
570
  uint16_t s_dvb_channel_minor;
571
  uint8_t  s_dvb_channel_dtag;
572
  uint16_t s_dvb_service_id;
573
  char    *s_dvb_svcname;
574
  char    *s_dvb_provider;
575
  char    *s_dvb_cridauth;
576
  uint16_t s_dvb_servicetype;
577
  int      s_dvb_ignore_eit;
578
  char    *s_dvb_charset;
579
  uint16_t s_dvb_prefcapid;
580
  int      s_dvb_prefcapid_lock;
581
  uint16_t s_dvb_forcecaid;
582
  time_t   s_dvb_created;
583
  time_t   s_dvb_last_seen;
584
  time_t   s_dvb_check_seen;
585

    
586
  /*
587
   * EIT/EPG control
588
   */
589

    
590
  int      s_dvb_eit_enable;
591
  uint64_t s_dvb_opentv_chnum;
592
  uint16_t s_dvb_opentv_id;
593
  uint16_t s_atsc_source_id;
594

    
595
  /*
596
   * Link to carrying multiplex and active adapter
597
   */
598

    
599
  LIST_ENTRY(mpegts_service) s_dvb_mux_link;
600
  mpegts_mux_t               *s_dvb_mux;
601
  mpegts_input_t             *s_dvb_active_input;
602

    
603
  /*
604
   * Streaming elements
605
   *
606
   * see service.h for locking rules
607
   */
608

    
609
  /**
610
   * When a subscription request SMT_MPEGTS, chunk them togeather 
611
   * in order to recude load.
612
   */
613
  sbuf_t s_tsbuf;
614
  int64_t s_tsbuf_last;
615

    
616
  /**
617
   * PCR drift compensation. This should really be per-packet.
618
   */
619
  int64_t  s_pcr_drift;
620

    
621
  /**
622
   * PMT/CAT monitoring
623
   */
624

    
625
  mpegts_table_t *s_pmt_mon; ///< Table entry for monitoring PMT
626
  mpegts_table_t *s_cat_mon; ///< Table entry for monitoring CAT
627

    
628
};
629

    
630
/* **************************************************************************
631
 * Physical Network
632
 * *************************************************************************/
633

    
634
/* Physical mux instance */
635
struct mpegts_mux_instance
636
{
637
  tvh_input_instance_t;
638

    
639
  LIST_ENTRY(mpegts_mux_instance) mmi_mux_link;
640
  LIST_ENTRY(mpegts_mux_instance) mmi_active_link;
641

    
642
  streaming_pad_t mmi_streaming_pad;
643
  
644
  mpegts_mux_t   *mmi_mux;
645
  mpegts_input_t *mmi_input;
646

    
647
  int             mmi_start_weight;
648
  int             mmi_tune_failed;
649
};
650

    
651
struct mpegts_mux_sub
652
{
653
  RB_ENTRY(mpegts_mux_sub)  mms_link;
654
  void                     *mms_src;
655
  int                       mms_weight;
656
};
657

    
658
/* Input source */
659
struct mpegts_input
660
{
661
  tvh_input_t;
662

    
663
  int mi_enabled;
664

    
665
  int mi_instance;
666

    
667
  char *mi_name;
668

    
669
  int mi_priority;
670
  int mi_streaming_priority;
671

    
672
  int mi_ota_epg;
673

    
674
  int mi_initscan;
675
  int mi_idlescan;
676
  uint32_t mi_free_weight;
677

    
678
  char *mi_linked;
679

    
680
  LIST_ENTRY(mpegts_input) mi_global_link;
681

    
682
  mpegts_network_link_list_t mi_networks;
683

    
684
  LIST_HEAD(,tvh_input_instance) mi_mux_instances;
685

    
686

    
687
  /*
688
   * Status
689
   */
690
  mtimer_t mi_status_timer;
691

    
692
  /*
693
   * Input processing
694
   */
695

    
696
  int mi_running;            /* threads running */
697
  int64_t mi_last_dispatch;
698

    
699
  /* Data input */
700
  // Note: this section is protected by mi_input_lock
701
  pthread_t                       mi_input_tid;
702
  mtimer_t                        mi_input_thread_start;
703
  pthread_mutex_t                 mi_input_lock;
704
  tvh_cond_t                      mi_input_cond;
705
  TAILQ_HEAD(,mpegts_packet)      mi_input_queue;
706
  uint64_t                        mi_input_queue_size;
707
  tvhlog_limit_t                  mi_input_queue_loglimit;
708

    
709
  /* Data processing/output */
710
  // Note: this lock (mi_output_lock) protects all the remaining
711
  //       data fields (excluding the callback functions)
712
  pthread_mutex_t                 mi_output_lock;
713

    
714
  /* Active sources */
715
  LIST_HEAD(,mpegts_mux_instance) mi_mux_active;
716

    
717
  /* Table processing */
718
  pthread_t                       mi_table_tid;
719
  tvh_cond_t                      mi_table_cond;
720
  mpegts_table_feed_queue_t       mi_table_queue;
721
  uint64_t                        mi_table_queue_size;
722
  tvhlog_limit_t                  mi_table_queue_loglimit;
723

    
724
  /* DBus */
725
#if ENABLE_DBUS_1
726
  int64_t                         mi_dbus_subs;
727
#endif
728

    
729
  /*
730
   * Functions
731
   */
732
  int  (*mi_is_enabled)     (mpegts_input_t*, mpegts_mux_t *mm, int flags, int weight);
733
  void (*mi_enabled_updated)(mpegts_input_t*);
734
  void (*mi_display_name)   (mpegts_input_t*, char *buf, size_t len);
735
  int  (*mi_get_weight)     (mpegts_input_t*, mpegts_mux_t *mm, int flags, int weight);
736
  int  (*mi_get_priority)   (mpegts_input_t*, mpegts_mux_t *mm, int flags);
737
  int  (*mi_get_grace)      (mpegts_input_t*, mpegts_mux_t *mm);
738
  int  (*mi_warm_mux)       (mpegts_input_t*,mpegts_mux_instance_t*);
739
  int  (*mi_start_mux)      (mpegts_input_t*,mpegts_mux_instance_t*, int weight);
740
  void (*mi_stop_mux)       (mpegts_input_t*,mpegts_mux_instance_t*);
741
  void (*mi_open_service)   (mpegts_input_t*,mpegts_service_t*, int flags, int first, int weight);
742
  void (*mi_close_service)  (mpegts_input_t*,mpegts_service_t*);
743
  void (*mi_update_pids)    (mpegts_input_t*,mpegts_mux_t*);
744
  void (*mi_create_mux_instance) (mpegts_input_t*,mpegts_mux_t*);
745
  void (*mi_started_mux)    (mpegts_input_t*,mpegts_mux_instance_t*);
746
  void (*mi_stopping_mux)   (mpegts_input_t*,mpegts_mux_instance_t*);
747
  void (*mi_stopped_mux)    (mpegts_input_t*,mpegts_mux_instance_t*);
748
  int  (*mi_has_subscription) (mpegts_input_t*, mpegts_mux_t *mm);
749
  void (*mi_tuning_error)   (mpegts_input_t*, mpegts_mux_t *);
750
  void (*mi_empty_status)   (mpegts_input_t*, tvh_input_stream_t *);
751
  idnode_set_t *(*mi_network_list) (mpegts_input_t*);
752
};
753

    
754
/* ****************************************************************************
755
 * Lists
756
 * ***************************************************************************/
757

    
758
extern mpegts_network_list_t mpegts_network_all;
759

    
760
typedef struct mpegts_network_builder {
761
  LIST_ENTRY(mpegts_network_builder) link;
762
  const idclass_t     *idc;
763
  mpegts_network_t * (*build) ( const idclass_t *idc, htsmsg_t *conf );
764
} mpegts_network_builder_t;
765

    
766

    
767
typedef LIST_HEAD(,mpegts_network_builder) mpegts_network_builder_list_t;
768

    
769
extern mpegts_network_builder_list_t mpegts_network_builders;
770

    
771
extern mpegts_input_list_t mpegts_input_all;
772

    
773
/* ****************************************************************************
774
 * Functions
775
 * ***************************************************************************/
776

    
777
mpegts_input_t *mpegts_input_create0
778
  ( mpegts_input_t *mi, const idclass_t *idc, const char *uuid, htsmsg_t *c );
779

    
780
#define mpegts_input_create(t, u, c)\
781
  (struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), &t##_class, u, c)
782

    
783
#define mpegts_input_create1(u, c)\
784
  mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
785
                       &mpegts_input_class, u, c)
786

    
787
void mpegts_input_stop_all ( mpegts_input_t *mi );
788

    
789
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
790

    
791
static inline mpegts_input_t *mpegts_input_find(const char *uuid)
792
  { return idnode_find(uuid, &mpegts_input_class, NULL); }
793

    
794
int mpegts_input_set_networks ( mpegts_input_t *mi, htsmsg_t *msg );
795

    
796
int mpegts_input_add_network  ( mpegts_input_t *mi, mpegts_network_t *mn );
797

    
798
void mpegts_input_open_service ( mpegts_input_t *mi, mpegts_service_t *s, int flags, int init, int weight );
799
void mpegts_input_close_service ( mpegts_input_t *mi, mpegts_service_t *s );
800

    
801
void mpegts_input_status_timer ( void *p );
802

    
803
int mpegts_input_grace ( mpegts_input_t * mi, mpegts_mux_t * mm );
804

    
805
int mpegts_input_is_enabled ( mpegts_input_t * mi, mpegts_mux_t *mm, int flags, int weight );
806

    
807
void mpegts_input_set_enabled ( mpegts_input_t *mi, int enabled );
808

    
809
void mpegts_input_empty_status ( mpegts_input_t *mi, tvh_input_stream_t *st );
810

    
811

    
812
/* TODO: exposing these class methods here is a bit of a hack */
813
const void *mpegts_input_class_network_get  ( void *o );
814
int         mpegts_input_class_network_set  ( void *o, const void *p );
815
htsmsg_t   *mpegts_input_class_network_enum ( void *o, const char *lang );
816
char       *mpegts_input_class_network_rend ( void *o, const char *lang );
817

    
818
int mpegts_mps_weight(elementary_stream_t *st);
819

    
820
int mpegts_mps_cmp( mpegts_pid_sub_t *a, mpegts_pid_sub_t *b );
821

    
822
void mpegts_network_register_builder
823
  ( const idclass_t *idc,
824
    mpegts_network_t *(*build)(const idclass_t *idc, htsmsg_t *conf) );
825

    
826
void mpegts_network_unregister_builder
827
  ( const idclass_t *idc );
828

    
829
mpegts_network_builder_t *mpegts_network_builder_find ( const char *clazz );
830

    
831
mpegts_network_t *mpegts_network_build
832
  ( const char *clazz, htsmsg_t *conf );
833
                 
834
mpegts_network_t *mpegts_network_create0
835
  ( mpegts_network_t *mn, const idclass_t *idc, const char *uuid,
836
    const char *name, htsmsg_t *conf );
837

    
838
#define mpegts_network_create(t, u, n, c)\
839
  (struct t*)mpegts_network_create0(calloc(1, sizeof(struct t)), &t##_class, u, n, c)
840

    
841
extern const idclass_t mpegts_network_class;
842

    
843
static inline mpegts_network_t *mpegts_network_find(const char *uuid)
844
  { return idnode_find(uuid, &mpegts_network_class, NULL); }
845

    
846
mpegts_mux_t *mpegts_network_find_mux
847
  (mpegts_network_t *mn, uint16_t onid, uint16_t tsid, int check);
848

    
849
void mpegts_network_class_delete ( const idclass_t *idc, int delconf );
850

    
851
void mpegts_network_delete ( mpegts_network_t *mn, int delconf );
852

    
853
int mpegts_network_set_nid          ( mpegts_network_t *mn, uint16_t nid );
854
int mpegts_network_set_network_name ( mpegts_network_t *mn, const char *name );
855
void mpegts_network_scan ( mpegts_network_t *mn );
856
void mpegts_network_get_type_str( mpegts_network_t *mn, char *buf, size_t buflen );
857

    
858
htsmsg_t * mpegts_network_wizard_get ( mpegts_input_t *mi, const idclass_t *idc,
859
                                       mpegts_network_t *mn, const char *lang );
860
void mpegts_network_wizard_create ( const char *clazz, htsmsg_t **nlist, const char *lang );
861

    
862
mpegts_mux_t *mpegts_mux_create0
863
  ( mpegts_mux_t *mm, const idclass_t *class, const char *uuid,
864
    mpegts_network_t *mn, uint16_t onid, uint16_t tsid,
865
    htsmsg_t *conf );
866

    
867
#define mpegts_mux_create(type, uuid, mn, onid, tsid, conf)\
868
  (struct type*)mpegts_mux_create0(calloc(1, sizeof(struct type)),\
869
                                   &type##_class, uuid,\
870
                                   mn, onid, tsid, conf)
871
#define mpegts_mux_create1(uuid, mn, onid, tsid, conf)\
872
  mpegts_mux_create0(calloc(1, sizeof(mpegts_mux_t)), &mpegts_mux_class, uuid,\
873
                     mn, onid, tsid, conf)
874

    
875
static inline mpegts_mux_t *mpegts_mux_find(const char *uuid)
876
  { return idnode_find(uuid, &mpegts_mux_class, NULL); }
877

    
878
#define mpegts_mux_delete_by_uuid(u, delconf)\
879
  { mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
880

    
881
void mpegts_mux_delete ( mpegts_mux_t *mm, int delconf );
882

    
883
void mpegts_mux_free ( mpegts_mux_t *mm );
884

    
885
static inline void mpegts_mux_grab ( mpegts_mux_t *mm )
886
{
887
  int v = atomic_add(&mm->mm_refcount, 1);
888
  assert(v > 0);
889
}
890

    
891
static inline int mpegts_mux_release ( mpegts_mux_t *mm )
892
{
893
  int v = atomic_dec(&mm->mm_refcount, 1);
894
  assert(v > 0);
895
  if (v == 1) {
896
    mm->mm_free(mm);
897
    return 1;
898
  }
899
  return 0;
900
}
901

    
902
void mpegts_mux_save ( mpegts_mux_t *mm, htsmsg_t *c );
903

    
904
void mpegts_mux_tuning_error( const char *mux_uuid, mpegts_mux_instance_t *mmi_match );
905

    
906
mpegts_mux_instance_t *mpegts_mux_instance_create0
907
  ( mpegts_mux_instance_t *mmi, const idclass_t *class, const char *uuid,
908
    mpegts_input_t *mi, mpegts_mux_t *mm );
909

    
910
mpegts_service_t *mpegts_mux_find_service(mpegts_mux_t *ms, uint16_t sid);
911

    
912
#define mpegts_mux_instance_create(type, uuid, mi, mm)\
913
  (struct type*)mpegts_mux_instance_create0(calloc(1, sizeof(struct type)),\
914
                                            &type##_class, uuid,\
915
                                            mi, mm);
916

    
917
void mpegts_mux_instance_delete ( tvh_input_instance_t *tii );
918

    
919
int mpegts_mux_instance_start
920
  ( mpegts_mux_instance_t **mmiptr, service_t *t, int weight );
921

    
922
int mpegts_mux_instance_weight ( mpegts_mux_instance_t *mmi );
923

    
924
int mpegts_mux_set_network_name ( mpegts_mux_t *mm, const char *name );
925
int mpegts_mux_set_tsid ( mpegts_mux_t *mm, uint16_t tsid, int force );
926
int mpegts_mux_set_onid ( mpegts_mux_t *mm, uint16_t onid );
927
int mpegts_mux_set_crid_authority ( mpegts_mux_t *mm, const char *defauth );
928

    
929
void mpegts_mux_open_table ( mpegts_mux_t *mm, mpegts_table_t *mt, int subscribe );
930
void mpegts_mux_unsubscribe_table ( mpegts_mux_t *mm, mpegts_table_t *mt );
931
void mpegts_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt );
932

    
933
void mpegts_mux_remove_subscriber(mpegts_mux_t *mm, th_subscription_t *s, int reason);
934
int  mpegts_mux_subscribe(mpegts_mux_t *mm, mpegts_input_t *mi,
935
                          const char *name, int weight, int flags);
936
void mpegts_mux_unsubscribe_by_name(mpegts_mux_t *mm, const char *name);
937
th_subscription_t *mpegts_mux_find_subscription_by_name(mpegts_mux_t *mm, const char *name);
938

    
939
void mpegts_mux_unsubscribe_linked(mpegts_input_t *mi, service_t *t);
940

    
941
void mpegts_mux_scan_done ( mpegts_mux_t *mm, const char *buf, int res );
942

    
943
void mpegts_mux_bouquet_rescan ( const char *src, const char *extra );
944

    
945
void mpegts_mux_nice_name( mpegts_mux_t *mm, char *buf, size_t len );
946

    
947
int mpegts_mux_class_scan_state_set ( void *, const void * );
948

    
949
static inline int mpegts_mux_scan_state_set ( mpegts_mux_t *m, int state )
950
  { return mpegts_mux_class_scan_state_set ( m, &state ); }
951

    
952
mpegts_pid_t *mpegts_mux_find_pid_(mpegts_mux_t *mm, int pid, int create);
953

    
954
static inline mpegts_pid_t *
955
mpegts_mux_find_pid(mpegts_mux_t *mm, int pid, int create)
956
{
957
  if (mm->mm_last_pid != pid)
958
    return mpegts_mux_find_pid_(mm, pid, create);
959
  else
960
    return mm->mm_last_mp;
961
}
962

    
963
void mpegts_mux_update_pids ( mpegts_mux_t *mm );
964

    
965
int mpegts_mux_compare ( mpegts_mux_t *a, mpegts_mux_t *b );
966

    
967
void mpegts_input_recv_packets
968
  (mpegts_input_t *mi, mpegts_mux_instance_t *mmi, sbuf_t *sb,
969
   int flags, mpegts_pcr_t *pcr);
970

    
971
int mpegts_input_get_weight ( mpegts_input_t *mi, mpegts_mux_t *mm, int flags, int weight );
972
int mpegts_input_get_priority ( mpegts_input_t *mi, mpegts_mux_t *mm, int flags );
973
int mpegts_input_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm );
974
int mpegts_input_warm_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi );
975

    
976
void mpegts_input_save ( mpegts_input_t *mi, htsmsg_t *c );
977

    
978
void mpegts_input_flush_mux ( mpegts_input_t *mi, mpegts_mux_t *mm );
979

    
980
mpegts_pid_t * mpegts_input_open_pid
981
  ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, int weight, void *owner, int reopen );
982

    
983
int mpegts_input_close_pid
984
  ( mpegts_input_t *mi, mpegts_mux_t *mm, int pid, int type, int weight, void *owner );
985

    
986
void mpegts_input_close_pids
987
  ( mpegts_input_t *mi, mpegts_mux_t *mm, void *owner, int all );
988

    
989
static inline void
990
tsdebug_write(mpegts_mux_t *mm, uint8_t *buf, size_t len)
991
{
992
#if ENABLE_TSDEBUG
993
  if (mm && mm->mm_tsdebug_fd2 >= 0)
994
    if (write(mm->mm_tsdebug_fd2, buf, len) != len)
995
      tvherror("tsdebug", "unable to write input data (%i)", errno);
996
#endif
997
}
998

    
999
static inline ssize_t
1000
sbuf_tsdebug_read(mpegts_mux_t *mm, sbuf_t *sb, int fd)
1001
{
1002
#if ENABLE_TSDEBUG
1003
  ssize_t r = sbuf_read(sb, fd);
1004
  tsdebug_write(mm, sb->sb_data + sb->sb_ptr - r, r);
1005
  return r;
1006
#else
1007
  return sbuf_read(sb, fd);
1008
#endif
1009
}
1010

    
1011
void mpegts_table_dispatch
1012
  (const uint8_t *sec, size_t r, void *mt);
1013
static inline void mpegts_table_grab
1014
  (mpegts_table_t *mt)
1015
{
1016
  int v = atomic_add(&mt->mt_arefcount, 1);
1017
  assert(v > 0);
1018
}
1019
void mpegts_table_release_
1020
  (mpegts_table_t *mt);
1021
static inline int mpegts_table_release
1022
  (mpegts_table_t *mt)
1023
{
1024
  int v = atomic_dec(&mt->mt_arefcount, 1);
1025
  assert(v > 0);
1026
  if (v == 1) {
1027
    assert(mt->mt_destroyed == 1);
1028
    mpegts_table_release_(mt);
1029
    return 1;
1030
  }
1031
  return 0;
1032
}
1033
int mpegts_table_type
1034
  ( mpegts_table_t *mt );
1035
mpegts_table_t *mpegts_table_add
1036
  (mpegts_mux_t *mm, int tableid, int mask,
1037
   mpegts_table_callback_t callback, void *opaque,
1038
   const char *name, int subsys, int flags, int pid, int weight);
1039
void mpegts_table_flush_all
1040
  (mpegts_mux_t *mm);
1041
void mpegts_table_destroy ( mpegts_table_t *mt );
1042

    
1043
void mpegts_table_consistency_check( mpegts_mux_t *mm );
1044

    
1045
void dvb_bat_destroy
1046
  (struct mpegts_table *mt);
1047

    
1048
int dvb_pat_callback
1049
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1050
int dvb_cat_callback
1051
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1052
int dvb_pmt_callback
1053
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tabelid);
1054
int dvb_nit_callback
1055
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1056
int dvb_bat_callback
1057
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1058
int dvb_fs_sdt_callback
1059
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1060
int dvb_sdt_callback
1061
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1062
int dvb_tdt_callback
1063
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1064
int dvb_tot_callback
1065
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1066
int atsc_vct_callback
1067
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1068
int atsc_stt_callback
1069
  (struct mpegts_table *mt, const uint8_t *ptr, int len, int tableid);
1070

    
1071
void psi_tables_install
1072
  (mpegts_input_t *mi, mpegts_mux_t *mm, dvb_fe_delivery_system_t delsys);
1073

    
1074
mpegts_service_t *mpegts_service_create0
1075
  ( mpegts_service_t *ms, const idclass_t *class, const char *uuid,
1076
    mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, htsmsg_t *conf );
1077

    
1078
#define mpegts_service_create(t, u, m, s, p, c)\
1079
  (struct t*)mpegts_service_create0(calloc(1, sizeof(struct t)),\
1080
                                    &t##_class, u, m, s, p, c)
1081

    
1082
#define mpegts_service_create1(u, m, s, p, c)\
1083
  mpegts_service_create0(calloc(1, sizeof(mpegts_service_t)),\
1084
                         &mpegts_service_class, u, m, s, p, c)
1085

    
1086
mpegts_service_t *mpegts_service_create_raw(mpegts_mux_t *mm);
1087

    
1088
mpegts_service_t *mpegts_service_find 
1089
  ( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, int create, int *save );
1090

    
1091
service_t *
1092
mpegts_service_find_e2
1093
  ( uint32_t stype, uint32_t sid, uint32_t tsid, uint32_t onid, uint32_t hash);
1094

    
1095
mpegts_service_t *
1096
mpegts_service_find_by_pid ( mpegts_mux_t *mm, int pid );
1097

    
1098
void mpegts_service_update_slave_pids ( mpegts_service_t *t, int del );
1099

    
1100
static inline mpegts_service_t *mpegts_service_find_by_uuid(const char *uuid)
1101
  { return idnode_find(uuid, &mpegts_service_class, NULL); }
1102

    
1103
void mpegts_service_unref ( service_t *s );
1104

    
1105
void mpegts_service_delete ( service_t *s, int delconf );
1106

    
1107
/*
1108
 * MPEG-TS event handler
1109
 */
1110

    
1111
typedef struct mpegts_listener
1112
{
1113
  LIST_ENTRY(mpegts_listener) ml_link;
1114
  void *ml_opaque;
1115
  void (*ml_mux_start)  (mpegts_mux_t *mm, void *p);
1116
  void (*ml_mux_stop)   (mpegts_mux_t *mm, void *p, int reason);
1117
  void (*ml_mux_create) (mpegts_mux_t *mm, void *p);
1118
  void (*ml_mux_delete) (mpegts_mux_t *mm, void *p);
1119
} mpegts_listener_t;
1120

    
1121
LIST_HEAD(,mpegts_listener) mpegts_listeners;
1122

    
1123
#define mpegts_add_listener(ml)\
1124
  LIST_INSERT_HEAD(&mpegts_listeners, ml, ml_link)
1125

    
1126
#define mpegts_rem_listener(ml)\
1127
  LIST_REMOVE(ml, ml_link)
1128

    
1129
#define mpegts_fire_event(t, op)\
1130
{\
1131
  mpegts_listener_t *ml;\
1132
  LIST_FOREACH(ml, &mpegts_listeners, ml_link)\
1133
    if (ml->op) ml->op(t, ml->ml_opaque);\
1134
} (void)0
1135

    
1136
#define mpegts_fire_event1(t, op, arg1)\
1137
{\
1138
  mpegts_listener_t *ml;\
1139
  LIST_FOREACH(ml, &mpegts_listeners, ml_link)\
1140
    if (ml->op) ml->op(t, ml->ml_opaque, arg1);\
1141
} (void)0
1142

    
1143
#endif /* __TVH_MPEGTS_H__ */
1144

    
1145
/******************************************************************************
1146
 * Editor Configuration
1147
 *
1148
 * vim:sts=2:ts=2:sw=2:et
1149
 *****************************************************************************/
1150

    
(2-2/4)