Project

General

Profile

RE: UK Cable OTA EPG » otamux.c

Paul Williams, 2016-08-23 13:07

 
1
/*
2
 *  Electronic Program Guide - EPG grabber OTA functions
3
 *  Copyright (C) 2012 Adam Sutton
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 "tvheadend.h"
20
#include "queue.h"
21
#include "settings.h"
22
#include "epg.h"
23
#include "epggrab.h"
24
#include "epggrab/private.h"
25
#include "input.h"
26
#include "subscriptions.h"
27
#include "cron.h"
28
#include "dbus.h"
29

30
#include <string.h>
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <unistd.h>
34

35
#define EPGGRAB_OTA_MIN_TIMEOUT     30
36
#define EPGGRAB_OTA_MAX_TIMEOUT   7200
37

38
#define EPGGRAB_OTA_DONE_COMPLETE    0
39
#define EPGGRAB_OTA_DONE_TIMEOUT     1
40
#define EPGGRAB_OTA_DONE_NO_DATA     2
41
#define EPGGRAB_OTA_DONE_STOLEN      3
42

43
typedef TAILQ_HEAD(epggrab_ota_head,epggrab_ota_mux) epggrab_ota_head_t;
44

45
cron_multi_t                *epggrab_ota_cron_multi;
46

47
RB_HEAD(,epggrab_ota_mux)    epggrab_ota_all;
48
epggrab_ota_head_t           epggrab_ota_pending;
49
epggrab_ota_head_t           epggrab_ota_active;
50

51
mtimer_t                     epggrab_ota_kick_timer;
52
gtimer_t                     epggrab_ota_start_timer;
53

54
int                          epggrab_ota_running;
55
int                          epggrab_ota_pending_flag;
56

57
pthread_mutex_t              epggrab_ota_mutex;
58

59
SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t);
60
SKEL_DECLARE(epggrab_svc_link_skel, epggrab_ota_svc_link_t);
61

62
static void epggrab_ota_kick ( int delay );
63

64
static void epggrab_ota_timeout_cb ( void *p );
65
static void epggrab_ota_data_timeout_cb ( void *p );
66
static void epggrab_ota_kick_cb ( void *p );
67

68
static void epggrab_mux_start ( mpegts_mux_t *mm, void *p );
69

70
static void epggrab_ota_save ( epggrab_ota_mux_t *ota );
71

72
static void epggrab_ota_free ( epggrab_ota_head_t *head, epggrab_ota_mux_t *ota );
73

74
/* **************************************************************************
75
 * Utilities
76
 * *************************************************************************/
77

78
static int
79
om_id_cmp   ( epggrab_ota_mux_t *a, epggrab_ota_mux_t *b )
80
{
81
  return strcmp(a->om_mux_uuid, b->om_mux_uuid);
82
}
83

84
static int
85
om_mux_cmp  ( epggrab_ota_mux_t *a, epggrab_ota_mux_t *b )
86
{
87
  mpegts_mux_t *a1 = mpegts_mux_find(a->om_mux_uuid);
88
  mpegts_mux_t *b1 = mpegts_mux_find(b->om_mux_uuid);
89
  if (a1 == NULL || b1 == NULL) {
90
    if (a1 == NULL && b1 == NULL)
91
      return 0;
92
    return a1 == NULL ? 1 : -1;
93
  }
94
  return mpegts_mux_compare(a1, b1);
95
}
96

97
static int
98
om_svcl_cmp ( epggrab_ota_svc_link_t *a, epggrab_ota_svc_link_t *b )
99
{
100
  return strcmp(a->uuid, b->uuid);
101
}
102

103
static int
104
epggrab_ota_timeout_get ( void )
105
{
106
  int timeout = epggrab_conf.ota_timeout;
107

108
  if (timeout < EPGGRAB_OTA_MIN_TIMEOUT)
109
    timeout = EPGGRAB_OTA_MIN_TIMEOUT;
110
  if (timeout > EPGGRAB_OTA_MAX_TIMEOUT)
111
    timeout = EPGGRAB_OTA_MAX_TIMEOUT;
112

113
  return timeout;
114
}
115

116
static int
117
epggrab_ota_queue_one( epggrab_ota_mux_t *om )
118
{
119
  om->om_done = 0;
120
  om->om_requeue = 1;
121
  if (om->om_q_type != EPGGRAB_OTA_MUX_IDLE)
122
    return 0;
123
  TAILQ_INSERT_SORTED(&epggrab_ota_pending, om, om_q_link, om_mux_cmp);
124
  om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
125
  return 1;
126
}
127

128
void
129
epggrab_ota_queue_mux( mpegts_mux_t *mm )
130
{
131
  const char *id;
132
  epggrab_ota_mux_t *om;
133
  int epg_flag;
134
  char ubuf[UUID_HEX_SIZE];
135

136
  if (!mm)
137
    return;
138

139
  lock_assert(&global_lock);
140

141
  id = idnode_uuid_as_str(&mm->mm_id, ubuf);
142
  epg_flag = mm->mm_is_epg(mm);
143
  if (epg_flag < 0 || epg_flag == MM_EPG_DISABLE)
144
    return;
145
  RB_FOREACH(om, &epggrab_ota_all, om_global_link)
146
    if (!strcmp(om->om_mux_uuid, id)) {
147
      if (epggrab_ota_queue_one(om))
148
        epggrab_ota_kick(4);
149
      break;
150
    }
151
}
152

153
static void
154
epggrab_ota_requeue ( void )
155
{
156
  epggrab_ota_mux_t *om;
157

158
  /*
159
   * enqueue all muxes, but ommit the delayed ones (active+pending)
160
   */
161
  RB_FOREACH(om, &epggrab_ota_all, om_global_link)
162
    epggrab_ota_queue_one(om);
163
}
164

165
static void
166
epggrab_ota_kick ( int delay )
167
{
168
  /* next round is pending? queue rest of ota muxes */
169
  if (epggrab_ota_pending_flag) {
170
    epggrab_ota_pending_flag = 0;
171
    epggrab_ota_requeue();
172
  }
173

174
  if (TAILQ_EMPTY(&epggrab_ota_pending))
175
    return;
176

177
  mtimer_arm_rel(&epggrab_ota_kick_timer, epggrab_ota_kick_cb, NULL, sec2mono(delay));
178
}
179

180
static void
181
epggrab_ota_done ( epggrab_ota_mux_t *om, int reason )
182
{
183
  static const char *reasons[] = {
184
    [EPGGRAB_OTA_DONE_COMPLETE]    = "complete",
185
    [EPGGRAB_OTA_DONE_TIMEOUT]     = "timeout",
186
    [EPGGRAB_OTA_DONE_NO_DATA]     = "no data",
187
    [EPGGRAB_OTA_DONE_STOLEN]      = "stolen"
188
  };
189
  char name[256];
190
  mpegts_mux_t *mm;
191
  epggrab_ota_map_t *map;
192

193
  if (om->om_save)
194
    epggrab_ota_save(om);
195

196
  mm = mpegts_mux_find(om->om_mux_uuid);
197
  mpegts_mux_nice_name(mm, name, sizeof(name));
198
  tvhdebug(LS_EPGGRAB, "grab done for %s (%s)", name, reasons[reason]);
199

200
  mtimer_disarm(&om->om_timer);
201
  mtimer_disarm(&om->om_data_timer);
202

203
  assert(om->om_q_type == EPGGRAB_OTA_MUX_ACTIVE);
204
  TAILQ_REMOVE(&epggrab_ota_active, om, om_q_link);
205
  om->om_q_type = EPGGRAB_OTA_MUX_IDLE;
206
  if (reason == EPGGRAB_OTA_DONE_STOLEN) {
207
    /* Do not requeue completed muxes */
208
    if (!om->om_done && om->om_requeue) {
209
      TAILQ_INSERT_HEAD(&epggrab_ota_pending, om, om_q_link);
210
      om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
211
    } else {
212
      om->om_requeue = 0;
213
    }
214
  } else if (reason == EPGGRAB_OTA_DONE_TIMEOUT) {
215
    om->om_requeue = 0;
216
    LIST_FOREACH(map, &om->om_modules, om_link)
217
      if (!map->om_complete)
218
        tvhwarn(LS_EPGGRAB, "%s - data completion timeout for %s", map->om_module->name, name);
219
  } else {
220
    om->om_requeue = 0;
221
  }
222

223
  /* Remove subscriber */
224
  if (mm)
225
    mpegts_mux_unsubscribe_by_name(mm, "epggrab");
226

227
  /* Kick - try start waiting muxes */
228
  epggrab_ota_kick(1);
229
}
230

231
static void
232
epggrab_ota_complete_mark ( epggrab_ota_mux_t *om, int done )
233
{
234
  om->om_done = 1;
235
  if (!om->om_complete) {
236
    om->om_complete = 1;
237
    epggrab_ota_save(om);
238
  }
239
}
240

241
static void
242
epggrab_ota_start ( epggrab_ota_mux_t *om, mpegts_mux_t *mm )
243
{
244
  epggrab_module_t  *m;
245
  epggrab_ota_map_t *map;
246
  char *modname = om->om_force_modname;
247
  mpegts_mux_instance_t *mmi = mm->mm_active;
248
  int grace;
249

250
  /* In pending queue? Remove.. */
251
  if (om->om_q_type == EPGGRAB_OTA_MUX_PENDING)
252
    TAILQ_REMOVE(&epggrab_ota_pending, om, om_q_link);
253
  else
254
    assert(om->om_q_type == EPGGRAB_OTA_MUX_IDLE);
255

256
  TAILQ_INSERT_TAIL(&epggrab_ota_active, om, om_q_link);
257
  om->om_q_type = EPGGRAB_OTA_MUX_ACTIVE;
258
  grace = mpegts_input_grace(mmi->mmi_input, mm);
259
  mtimer_arm_rel(&om->om_timer, epggrab_ota_timeout_cb, om,
260
                 sec2mono(epggrab_ota_timeout_get() + grace));
261
  mtimer_arm_rel(&om->om_data_timer, epggrab_ota_data_timeout_cb, om,
262
                 sec2mono(30 + grace)); /* 30 seconds to receive any EPG info */
263
  if (modname) {
264
    LIST_FOREACH(m, &epggrab_modules, link)
265
      if (!strcmp(m->id, modname)) {
266
        epggrab_ota_register((epggrab_module_ota_t *)m, om, mm);
267
        break;
268
      }
269
  }
270
  LIST_FOREACH(map, &om->om_modules, om_link) {
271
    map->om_first    = 1;
272
    map->om_forced   = 0;
273
    if (modname && !strcmp(modname, map->om_module->id))
274
      map->om_forced = 1;
275
    map->om_complete = 0;
276
    if (map->om_module->start(map, mm) < 0) {
277
      map->om_complete = 1;
278
    } else
279
      tvhdebug(map->om_module->subsys, "%s: grab started", map->om_module->id);
280
  }
281
}
282

283
/* **************************************************************************
284
 * MPEG-TS listener
285
 * *************************************************************************/
286

287
static void
288
epggrab_mux_start ( mpegts_mux_t *mm, void *p )
289
{
290
  epggrab_module_t  *m;
291
  epggrab_ota_mux_t *ota;
292
  char ubuf[UUID_HEX_SIZE];
293
  const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
294

295
  /* Already started */
296
  TAILQ_FOREACH(ota, &epggrab_ota_active, om_q_link)
297
    if (!strcmp(ota->om_mux_uuid, uuid))
298
      return;
299

300
  /* Register all modules */
301
  ota = NULL;
302
  LIST_FOREACH(m, &epggrab_modules, link) {
303
    if (m->type == EPGGRAB_OTA && m->enabled)
304
      ota = epggrab_ota_register((epggrab_module_ota_t *)m, ota, mm);
305
  }
306

307
  if (ota)
308
    epggrab_ota_start(ota, mm);
309
}
310

311
static void
312
epggrab_mux_stop ( mpegts_mux_t *mm, void *p, int reason )
313
{
314
  epggrab_ota_mux_t *ota;
315
  char ubuf[UUID_HEX_SIZE], name[256];
316
  const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
317
  int done = EPGGRAB_OTA_DONE_STOLEN;
318

319
  if (reason == SM_CODE_NO_INPUT)
320
    done = EPGGRAB_OTA_DONE_NO_DATA;
321

322
  if (tvhtrace_enabled()) {
323
    mpegts_mux_nice_name(mm, name, sizeof(name));
324
    tvhtrace(LS_EPGGRAB, "mux %s (%p) stop", name, mm);
325
  }
326
  TAILQ_FOREACH(ota, &epggrab_ota_active, om_q_link)
327
    if (!strcmp(ota->om_mux_uuid, uuid)) {
328
      epggrab_ota_done(ota, done);
329
      break;
330
    }
331
}
332

333
/* **************************************************************************
334
 * Module methods
335
 * *************************************************************************/
336

337
epggrab_ota_mux_t *
338
epggrab_ota_register
339
  ( epggrab_module_ota_t *mod, epggrab_ota_mux_t *ota, mpegts_mux_t *mm )
340
{
341
  int save = 0;
342
  epggrab_ota_map_t *map;
343

344
  if (!atomic_get(&epggrab_ota_running))
345
    return NULL;
346

347
  if (ota == NULL) {
348
    /* Find mux entry */
349
    char ubuf[UUID_HEX_SIZE];
350
    const char *uuid = idnode_uuid_as_str(&mm->mm_id, ubuf);
351
    SKEL_ALLOC(epggrab_ota_mux_skel);
352
    epggrab_ota_mux_skel->om_mux_uuid = (char*)uuid;
353

354
    ota = RB_INSERT_SORTED(&epggrab_ota_all, epggrab_ota_mux_skel, om_global_link, om_id_cmp);
355
    if (!ota) {
356
      char buf[256];
357
      mpegts_mux_nice_name(mm, buf, sizeof(buf));
358
      tvhinfo(mod->subsys, "%s: registering mux %s", buf, mod->id);
359
      ota  = epggrab_ota_mux_skel;
360
      SKEL_USED(epggrab_ota_mux_skel);
361
      ota->om_mux_uuid = strdup(uuid);
362
      TAILQ_INSERT_SORTED(&epggrab_ota_pending, ota, om_q_link, om_mux_cmp);
363
      ota->om_q_type = EPGGRAB_OTA_MUX_PENDING;
364
      if (TAILQ_FIRST(&epggrab_ota_pending) == ota)
365
        epggrab_ota_kick(1);
366
      save = 1;
367
    }
368
  }
369
  
370
  /* Find module entry */
371
  LIST_FOREACH(map, &ota->om_modules, om_link)
372
    if (map->om_module == mod)
373
      break;
374
  if (!map) {
375
    map = calloc(1, sizeof(epggrab_ota_map_t));
376
    RB_INIT(&map->om_svcs);
377
    map->om_module   = mod;
378
    LIST_INSERT_HEAD(&ota->om_modules, map, om_link);
379
    save = 1;
380
  }
381

382
  /* Save config */
383
  if (save) epggrab_ota_save(ota);
384

385
  return ota;
386
}
387

388
void
389
epggrab_ota_complete
390
  ( epggrab_module_ota_t *mod, epggrab_ota_mux_t *ota )
391
{
392
  int done = 1;
393
  epggrab_ota_map_t *map;
394
  lock_assert(&global_lock);
395

396
  if (!ota->om_complete)
397
    tvhdebug(mod->subsys, "%s: grab complete", mod->id);
398

399
  /* Test for completion */
400
  LIST_FOREACH(map, &ota->om_modules, om_link) {
401
    if (map->om_module == mod) {
402
      map->om_complete = 1;
403
    } else if (!map->om_complete && !map->om_first) {
404
      done = 0;
405
    }
406
    tvhtrace(LS_EPGGRAB, "%s complete %i first %i",
407
                        map->om_module->id, map->om_complete, map->om_first);
408
  }
409

410
  epggrab_ota_complete_mark(ota, done);
411

412
  if (!done) return;
413

414
  /* Done */
415
  if (ota->om_q_type == EPGGRAB_OTA_MUX_ACTIVE)
416
    epggrab_ota_done(ota, EPGGRAB_OTA_DONE_COMPLETE);
417
  else if (ota->om_q_type == EPGGRAB_OTA_MUX_PENDING) {
418
    TAILQ_REMOVE(&epggrab_ota_pending, ota, om_q_link);
419
    ota->om_q_type = EPGGRAB_OTA_MUX_IDLE;
420
  }
421
}
422

423
/* **************************************************************************
424
 * Timer callbacks
425
 * *************************************************************************/
426

427
static void
428
epggrab_ota_timeout_cb ( void *p )
429
{
430
  epggrab_ota_mux_t *om = p;
431

432
  lock_assert(&global_lock);
433

434
  if (!om)
435
    return;
436

437
  /* Abort */
438
  epggrab_ota_done(om, EPGGRAB_OTA_DONE_TIMEOUT);
439
  /* Not completed, but no further data for a long period */
440
  /* wait for a manual mux tuning */
441
  epggrab_ota_complete_mark(om, 1);
442
}
443

444
static void
445
epggrab_ota_data_timeout_cb ( void *p )
446
{
447
  epggrab_ota_mux_t *om = p;
448
  epggrab_ota_map_t *map;
449

450
  lock_assert(&global_lock);
451

452
  if (!om)
453
    return;
454

455
  /* Test for any valid data reception */
456
  LIST_FOREACH(map, &om->om_modules, om_link) {
457
    if (!map->om_first)
458
      break;
459
  }
460

461
  if (map == NULL) {
462
    /* Abort */
463
    epggrab_ota_done(om, EPGGRAB_OTA_DONE_NO_DATA);
464
    /* Not completed, but no data - wait for a manual mux tuning */
465
    epggrab_ota_complete_mark(om, 1);
466
  } else {
467
    tvhtrace(LS_EPGGRAB, "data timeout check succeed");
468
  }
469
}
470

471
static void
472
epggrab_ota_kick_cb ( void *p )
473
{
474
  extern const idclass_t mpegts_mux_class;
475
  epggrab_ota_map_t *map;
476
  epggrab_ota_mux_t *om = TAILQ_FIRST(&epggrab_ota_pending);
477
  epggrab_ota_mux_t *first = NULL;
478
  mpegts_mux_t *mm;
479
  char name[256];
480
  struct {
481
    mpegts_network_t *net;
482
    uint8_t failed;
483
    uint8_t fatal;
484
  } networks[64], *net;	/* more than 64 networks? - you're a king */
485
  int i, r, networks_count = 0, epg_flag, kick = 1;
486
  const char *modname;
487
  static const char *modnames[] = {
488
    [MM_EPG_DISABLE]                 = NULL,
489
    [MM_EPG_ENABLE]                  = NULL,
490
    [MM_EPG_FORCE]                   = NULL,
491
    [MM_EPG_ONLY_EIT]                = "eit",
492
    [MM_EPG_ONLY_PSIP]               = "psip",
493
    [MM_EPG_ONLY_UK_FREESAT]         = "uk_freesat",
494
    [MM_EPG_ONLY_UK_FREEVIEW]        = "uk_freeview",
495
    [MM_EPG_ONLY_VIASAT_BALTIC]      = "viasat_baltic",
496
    [MM_EPG_ONLY_BULSATCOM_39E]      = "Bulsatcom_39E",
497
    [MM_EPG_ONLY_UK_CABLE] 	     = "uk_cable",
498
    [MM_EPG_ONLY_OPENTV_SKY_UK]      = "opentv-skyuk",
499
    [MM_EPG_ONLY_OPENTV_SKY_ITALIA]  = "opentv-skyit",
500
    [MM_EPG_ONLY_OPENTV_SKY_AUSAT]   = "opentv-ausat",
501
  };
502

503
  lock_assert(&global_lock);
504

505
  if (!om)
506
    return;
507

508
  tvhtrace(LS_EPGGRAB, "ota - kick callback");
509

510
next_one:
511
  /* Find the mux */
512
  mm = mpegts_mux_find(om->om_mux_uuid);
513
  if (!mm) {
514
    epggrab_ota_free(&epggrab_ota_pending, om);
515
    goto done;
516
  }
517

518
  assert(om->om_q_type == EPGGRAB_OTA_MUX_PENDING);
519
  TAILQ_REMOVE(&epggrab_ota_pending, om, om_q_link);
520
  om->om_q_type = EPGGRAB_OTA_MUX_IDLE;
521

522
  /* Check if this network failed before */
523
  for (i = 0, net = NULL; i < networks_count; i++) {
524
    net = &networks[i];
525
    if (net->net == mm->mm_network) {
526
      if (net->fatal)
527
        goto done;
528
      if (net->failed) {
529
        TAILQ_INSERT_TAIL(&epggrab_ota_pending, om, om_q_link);
530
        om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
531
        goto done;
532
      }
533
      break;
534
    }
535
  }
536
  if (i >= networks_count) {
537
    net = &networks[networks_count++];
538
    net->net = mm->mm_network;
539
    net->failed = 0;
540
    net->fatal = 0;
541
  }
542

543
  epg_flag = MM_EPG_DISABLE;
544
  if (mm->mm_is_enabled(mm)) {
545
    epg_flag = mm->mm_is_epg(mm);
546
    if (epg_flag > MM_EPG_LAST)
547
      epg_flag = MM_EPG_ENABLE;
548
    modname  = epg_flag >= 0 ? modnames[epg_flag] : NULL;
549
  }
550

551
  if (epg_flag < 0 || epg_flag == MM_EPG_DISABLE) {
552
    if (tvhtrace_enabled()) {
553
      mpegts_mux_nice_name(mm, name, sizeof(name));
554
      tvhtrace(LS_EPGGRAB, "epg mux %s is disabled, skipping", name);
555
    }
556
    goto done;
557
  }
558

559
  /* Check we have modules attached and enabled */
560
  i = r = 0;
561
  LIST_FOREACH(map, &om->om_modules, om_link) {
562
    if (map->om_module->tune(map, om, mm)) {
563
      i++;
564
      if (modname && !strcmp(modname, map->om_module->id))
565
        r = 1;
566
    }
567
  }
568
  if ((i == 0 || (r == 0 && modname)) && epg_flag != MM_EPG_FORCE) {
569
    mpegts_mux_nice_name(mm, name, sizeof(name));
570
    tvhdebug(LS_EPGGRAB, "no OTA modules active for %s, check again next time", name);
571
    goto done;
572
  }
573

574
  /* Some init stuff */
575
  free(om->om_force_modname);
576
  om->om_force_modname = modname ? strdup(modname) : NULL;
577

578
  /* Subscribe to the mux */
579
  om->om_requeue = 1;
580
  if ((r = mpegts_mux_subscribe(mm, NULL, "epggrab",
581
                                SUBSCRIPTION_PRIO_EPG,
582
                                SUBSCRIPTION_EPG |
583
                                SUBSCRIPTION_ONESHOT |
584
                                SUBSCRIPTION_TABLES))) {
585
    if (r != SM_CODE_NO_ADAPTERS) {
586
      if (tvhtrace_enabled()) {
587
        mpegts_mux_nice_name(mm, name, sizeof(name));
588
        tvhtrace(LS_EPGGRAB, "subscription failed for %s (result %d)", name, r);
589
      }
590
      TAILQ_INSERT_TAIL(&epggrab_ota_pending, om, om_q_link);
591
      om->om_q_type = EPGGRAB_OTA_MUX_PENDING;
592
      if (r == SM_CODE_NO_FREE_ADAPTER)
593
        net->failed = 1;
594
      if (first == NULL)
595
        first = om;
596
    } else {
597
      if (tvhtrace_enabled()) {
598
        mpegts_mux_nice_name(mm, name, sizeof(name));
599
        tvhtrace(LS_EPGGRAB, "no free adapter for %s (subscribe)", name);
600
      }
601
      net->fatal = 1;
602
    }
603
  } else {
604
    if (tvhtrace_enabled()) {
605
      mpegts_mux_nice_name(mm, name, sizeof(name));
606
      tvhtrace(LS_EPGGRAB, "mux %s (%p), started", name, mm);
607
    }
608
    kick = 0;
609
    /* note: it is possible that the mux_start listener is not called */
610
    /* for reshared mux subscriptions, so call it (maybe second time) here.. */
611
    epggrab_mux_start(mm, NULL);
612
  }
613

614
done:
615
  om = TAILQ_FIRST(&epggrab_ota_pending);
616
  if (networks_count < ARRAY_SIZE(networks) && om && first != om)
617
    goto next_one;
618
  if (kick)
619
    epggrab_ota_kick(64); /* a random number? */
620

621
  if (tvhtrace_enabled()) {
622
    i = r = 0;
623
    RB_FOREACH(om, &epggrab_ota_all, om_global_link)
624
      i++;
625
    TAILQ_FOREACH(om, &epggrab_ota_pending, om_q_link)
626
      r++;
627
    tvhtrace(LS_EPGGRAB, "mux stats - all %i pending %i", i, r);
628
  }
629
}
630

631
/*
632
 * Start times management
633
 */
634

635
static void
636
epggrab_ota_start_cb ( void *p );
637

638
static void
639
epggrab_ota_next_arm( time_t next )
640
{
641
  tvhtrace(LS_EPGGRAB, "next ota start event in %li seconds", next - time(NULL));
642
  gtimer_arm_absn(&epggrab_ota_start_timer, epggrab_ota_start_cb, NULL, next);
643
  dbus_emit_signal_s64("/epggrab/ota", "next", next);
644
}
645

646
static void
647
epggrab_ota_start_cb ( void *p )
648
{
649
  time_t next;
650

651
  tvhtrace(LS_EPGGRAB, "ota start callback");
652

653
  epggrab_ota_pending_flag = 1;
654

655
  epggrab_ota_kick(1);
656

657
  pthread_mutex_lock(&epggrab_ota_mutex);
658
  if (!cron_multi_next(epggrab_ota_cron_multi, gclk(), &next))
659
    epggrab_ota_next_arm(next);
660
  else
661
    tvhwarn(LS_EPGGRAB, "ota cron config invalid or unset");
662
  pthread_mutex_unlock(&epggrab_ota_mutex);
663
}
664

665
static void
666
epggrab_ota_arm ( time_t last )
667
{
668
  time_t next;
669

670
  pthread_mutex_lock(&epggrab_ota_mutex);
671

672
  if (!cron_multi_next(epggrab_ota_cron_multi, time(NULL), &next)) {
673
    /* do not trigger the next EPG scan for 1/2 hour */
674
    if (last != (time_t)-1 && last + 1800 > next)
675
      next = last + 1800;
676
    epggrab_ota_next_arm(next);
677
  } else {
678
    tvhwarn(LS_EPGGRAB, "ota cron config invalid or unset");
679
  }
680

681
  pthread_mutex_unlock(&epggrab_ota_mutex);
682
}
683

684
/*
685
 * Service management
686
 */
687

688
static void
689
epggrab_ota_service_trace ( epggrab_ota_mux_t *ota,
690
                            epggrab_ota_svc_link_t *svcl,
691
                            const char *op )
692
{
693
  char buf[256];
694
  mpegts_mux_t *mm;
695
  mpegts_service_t *svc;
696

697
  if (!tvhtrace_enabled())
698
    return;
699

700
  mm = mpegts_mux_find(ota->om_mux_uuid);
701
  svc = mpegts_service_find_by_uuid(svcl->uuid);
702
  if (mm && svc) {
703
    mpegts_mux_nice_name(mm, buf, sizeof(buf));
704
    tvhtrace(LS_EPGGRAB, "ota %s %s service %s", buf, op, svc->s_nicename);
705
  } else if (tvheadend_is_running())
706
    tvhtrace(LS_EPGGRAB, "ota %s, problem? (%p %p)", op, mm, svc);
707
}
708

709
void
710
epggrab_ota_service_add ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota,
711
                          const char *uuid, int save )
712
{
713
  epggrab_ota_svc_link_t *svcl;
714

715
  if (uuid == NULL || !atomic_get(&epggrab_ota_running))
716
    return;
717
  SKEL_ALLOC(epggrab_svc_link_skel);
718
  epggrab_svc_link_skel->uuid = (char *)uuid;
719
  svcl = RB_INSERT_SORTED(&map->om_svcs, epggrab_svc_link_skel, link, om_svcl_cmp);
720
  if (svcl == NULL) {
721
    svcl = epggrab_svc_link_skel;
722
    SKEL_USED(epggrab_svc_link_skel);
723
    svcl->uuid = strdup(uuid);
724
    if (save)
725
      ota->om_save = 1;
726
    epggrab_ota_service_trace(ota, svcl, "add new");
727
  }
728
  svcl->last_tune_count = map->om_tune_count;
729
}
730

731
void
732
epggrab_ota_service_del ( epggrab_ota_map_t *map, epggrab_ota_mux_t *ota,
733
                          epggrab_ota_svc_link_t *svcl, int save )
734
{
735
  if (svcl == NULL || (!atomic_get(&epggrab_ota_running) && save))
736
    return;
737
  epggrab_ota_service_trace(ota, svcl, "delete");
738
  RB_REMOVE(&map->om_svcs, svcl, link);
739
  free(svcl->uuid);
740
  free(svcl);
741
  if (save)
742
    ota->om_save = 1;
743
}
744

745
/* **************************************************************************
746
 * Config
747
 * *************************************************************************/
748

749
static void
750
epggrab_ota_save ( epggrab_ota_mux_t *ota )
751
{
752
  epggrab_ota_map_t *map;
753
  epggrab_ota_svc_link_t *svcl;
754
  htsmsg_t *e, *l, *l2, *c = htsmsg_create_map();
755

756
  ota->om_save = 0;
757
  htsmsg_add_u32(c, "complete", ota->om_complete);
758
  l = htsmsg_create_list();
759
  LIST_FOREACH(map, &ota->om_modules, om_link) {
760
    e = htsmsg_create_map();
761
    htsmsg_add_str(e, "id", map->om_module->id);
762
    if (RB_FIRST(&map->om_svcs)) {
763
      l2 = htsmsg_create_list();
764
      RB_FOREACH(svcl, &map->om_svcs, link)
765
        if (svcl->uuid)
766
          htsmsg_add_str(l2, NULL, svcl->uuid);
767
      htsmsg_add_msg(e, "services", l2);
768
    }
769
    htsmsg_add_msg(l, NULL, e);
770
  }
771
  htsmsg_add_msg(c, "modules", l);
772
  hts_settings_save(c, "epggrab/otamux/%s", ota->om_mux_uuid);
773
  htsmsg_destroy(c);
774
}
775

776
static void
777
epggrab_ota_load_one
778
  ( const char *uuid, htsmsg_t *c )
779
{
780
  htsmsg_t *l, *l2, *e;
781
  htsmsg_field_t *f, *f2;
782
  mpegts_mux_t *mm;
783
  epggrab_module_ota_t *mod;
784
  epggrab_ota_mux_t *ota;
785
  epggrab_ota_map_t *map;
786
  const char *id;
787
  
788
  mm = mpegts_mux_find(uuid);
789
  if (!mm) {
790
    hts_settings_remove("epggrab/otamux/%s", uuid);
791
    return;
792
  }
793
  if (tvhtrace_enabled()) {
794
    char name[256];
795
    mpegts_mux_nice_name(mm, name, sizeof(name));
796
    tvhtrace(LS_EPGGRAB, "loading config for %s", name);
797
  }
798

799
  ota = calloc(1, sizeof(epggrab_ota_mux_t));
800
  ota->om_mux_uuid = strdup(uuid);
801
  if (RB_INSERT_SORTED(&epggrab_ota_all, ota, om_global_link, om_id_cmp)) {
802
    free(ota->om_mux_uuid);
803
    free(ota);
804
    return;
805
  }
806
  ota->om_complete = htsmsg_get_u32_or_default(c, "complete", 0) != 0;
807
  
808
  if (!(l = htsmsg_get_list(c, "modules"))) return;
809
  HTSMSG_FOREACH(f, l) {
810
    if (!(e   = htsmsg_field_get_map(f))) continue;
811
    if (!(id  = htsmsg_get_str(e, "id"))) continue;
812
    if (!(mod = (epggrab_module_ota_t*)epggrab_module_find_by_id(id)))
813
      continue;
814
    
815
    map = calloc(1, sizeof(epggrab_ota_map_t));
816
    RB_INIT(&map->om_svcs);
817
    map->om_module   = mod;
818
    if ((l2 = htsmsg_get_list(e, "services")) != NULL) {
819
      HTSMSG_FOREACH(f2, l2)
820
        epggrab_ota_service_add(map, ota, htsmsg_field_get_str(f2), 0);
821
    }
822
    LIST_INSERT_HEAD(&ota->om_modules, map, om_link);
823
  }
824
}
825

826
void
827
epggrab_ota_init ( void )
828
{
829
  htsmsg_t *c, *m;
830
  htsmsg_field_t *f;
831
  char path[1024];
832
  struct stat st;
833

834
  epggrab_conf.ota_initial = 1;
835
  epggrab_conf.ota_timeout = 600;
836
  epggrab_conf.ota_cron    = strdup("# Default config (02:04 and 14:04 everyday)\n4 2 * * *\n4 14 * * *");
837
  epggrab_ota_cron_multi   = cron_multi_set(epggrab_conf.ota_cron);
838
  epggrab_ota_pending_flag = 0;
839

840
  RB_INIT(&epggrab_ota_all);
841
  TAILQ_INIT(&epggrab_ota_pending);
842
  TAILQ_INIT(&epggrab_ota_active);
843

844
  pthread_mutex_init(&epggrab_ota_mutex, NULL);
845

846
  /* Add listener */
847
  static mpegts_listener_t ml = {
848
    .ml_mux_start = epggrab_mux_start,
849
    .ml_mux_stop  = epggrab_mux_stop,
850
  };
851
  mpegts_add_listener(&ml);
852

853
  /* Delete old config */
854
  hts_settings_buildpath(path, sizeof(path), "epggrab/otamux");
855
  if (!lstat(path, &st))
856
    if (!S_ISDIR(st.st_mode))
857
      hts_settings_remove("epggrab/otamux");
858

859
  atomic_set(&epggrab_ota_running, 1);
860
  
861
  /* Load config */
862
  if ((c = hts_settings_load_r(1, "epggrab/otamux"))) {
863
    HTSMSG_FOREACH(f, c) {
864
      if (!(m  = htsmsg_field_get_map(f))) continue;
865
      epggrab_ota_load_one(f->hmf_name, m); 
866
    }
867
    htsmsg_destroy(c);
868
  }
869
}
870

871
void
872
epggrab_ota_trigger ( int secs )
873
{
874
  lock_assert(&global_lock);
875

876
  /* notify another system layers, that we will do EPG OTA */
877
  secs = MIN(1, MAX(secs, 7*24*3600));
878
  dbus_emit_signal_s64("/epggrab/ota", "next", time(NULL) + secs);
879
  epggrab_ota_pending_flag = 1;
880
  epggrab_ota_kick(secs);
881
}
882

883
void
884
epggrab_ota_post ( void )
885
{
886
  time_t t = (time_t)-1;
887

888
  /* Init timer (call after full init - wait for network tuners) */
889
  if (epggrab_conf.ota_initial) {
890
    epggrab_ota_trigger(15);
891
    t = time(NULL);
892
  }
893

894
  /* arm the first scheduled time */
895
  epggrab_ota_arm(t);
896
}
897

898
static void
899
epggrab_ota_free ( epggrab_ota_head_t *head, epggrab_ota_mux_t *ota  )
900
{
901
  epggrab_ota_map_t *map;
902
  epggrab_ota_svc_link_t *svcl;
903

904
  mtimer_disarm(&ota->om_timer);
905
  mtimer_disarm(&ota->om_data_timer);
906
  if (head != NULL)
907
    TAILQ_REMOVE(head, ota, om_q_link);
908
  RB_REMOVE(&epggrab_ota_all, ota, om_global_link);
909
  while ((map = LIST_FIRST(&ota->om_modules)) != NULL) {
910
    LIST_REMOVE(map, om_link);
911
    while ((svcl = RB_FIRST(&map->om_svcs)) != NULL)
912
      epggrab_ota_service_del(map, ota, svcl, 0);
913
    free(map);
914
  }
915
  free(ota->om_mux_uuid);
916
  free(ota->om_force_modname);
917
  free(ota);
918
}
919

920
void
921
epggrab_ota_shutdown ( void )
922
{
923
  epggrab_ota_mux_t *ota;
924

925
  atomic_set(&epggrab_ota_running, 0);
926
  while ((ota = TAILQ_FIRST(&epggrab_ota_active)) != NULL)
927
    epggrab_ota_free(&epggrab_ota_active, ota);
928
  while ((ota = TAILQ_FIRST(&epggrab_ota_pending)) != NULL)
929
    epggrab_ota_free(&epggrab_ota_pending, ota);
930
  while ((ota = RB_FIRST(&epggrab_ota_all)) != NULL)
931
    epggrab_ota_free(NULL, ota);
932
  SKEL_FREE(epggrab_ota_mux_skel);
933
  SKEL_FREE(epggrab_svc_link_skel);
934
  free(epggrab_ota_cron_multi);
935
  epggrab_ota_cron_multi = NULL;
936
}
937

938
/*
939
 *  Global configuration handlers
940
 */
941

942
void
943
epggrab_ota_set_cron ( void )
944
{
945
  lock_assert(&global_lock);
946

947
  pthread_mutex_lock(&epggrab_ota_mutex);
948
  free(epggrab_ota_cron_multi);
949
  epggrab_ota_cron_multi = cron_multi_set(epggrab_conf.ota_cron);
950
  pthread_mutex_unlock(&epggrab_ota_mutex);
951
  epggrab_ota_arm((time_t)-1);
952
}
953

954
/******************************************************************************
955
 * Editor Configuration
956
 *
957
 * vim:sts=2:ts=2:sw=2:et
958
 *****************************************************************************/
(4-4/4)