vdr  2.2.0
channels.c
Go to the documentation of this file.
1 /*
2  * channels.c: Channel handling
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: channels.c 3.8 2015/02/01 13:47:05 kls Exp $
8  */
9 
10 #include "channels.h"
11 #include <ctype.h>
12 #include "device.h"
13 #include "epg.h"
14 #include "libsi/si.h"
15 #include "timers.h"
16 
17 // IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
18 // format characters in order to allow any number of blanks after a numeric
19 // value!
20 
21 // --- tChannelID ------------------------------------------------------------
22 
24 
26 {
27  char *sourcebuf = NULL;
28  int nid;
29  int tid;
30  int sid;
31  int rid = 0;
32  int fields = sscanf(s, "%m[^-]-%d-%d-%d-%d", &sourcebuf, &nid, &tid, &sid, &rid);
33  if (fields == 4 || fields == 5) {
34  int source = cSource::FromString(sourcebuf);
35  free(sourcebuf);
36  if (source >= 0)
37  return tChannelID(source, nid, tid, sid, rid);
38  }
39  return tChannelID::InvalidID;
40 }
41 
43 {
44  char buffer[256];
45  snprintf(buffer, sizeof(buffer), rid ? "%s-%d-%d-%d-%d" : "%s-%d-%d-%d", *cSource::ToString(source), nid, tid, sid, rid);
46  return buffer;
47 }
48 
50 {
51  while (tid > 100000)
52  tid -= 100000;
53  return *this;
54 }
55 
56 // --- cChannel --------------------------------------------------------------
57 
59 {
60  name = strdup("");
61  shortName = strdup("");
62  provider = strdup("");
63  portalName = strdup("");
64  memset(&__BeginData__, 0, (char *)&__EndData__ - (char *)&__BeginData__);
65  parameters = "";
66  modification = CHANNELMOD_NONE;
67  seen = 0;
68  schedule = NULL;
69  linkChannels = NULL;
70  refChannel = NULL;
71 }
72 
74 {
75  name = NULL;
76  shortName = NULL;
77  provider = NULL;
78  portalName = NULL;
79  schedule = NULL;
80  linkChannels = NULL;
81  refChannel = NULL;
82  *this = Channel;
83 }
84 
86 {
87  delete linkChannels;
88  linkChannels = NULL; // more than one channel can link to this one, so we need the following loop
89  for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
90  if (Channel->linkChannels) {
91  for (cLinkChannel *lc = Channel->linkChannels->First(); lc; lc = Channel->linkChannels->Next(lc)) {
92  if (lc->Channel() == this) {
93  Channel->linkChannels->Del(lc);
94  break;
95  }
96  }
97  if (Channel->linkChannels->Count() == 0) {
98  delete Channel->linkChannels;
99  Channel->linkChannels = NULL;
100  }
101  }
102  }
103  free(name);
104  free(shortName);
105  free(provider);
106  free(portalName);
107 }
108 
110 {
111  name = strcpyrealloc(name, Channel.name);
112  shortName = strcpyrealloc(shortName, Channel.shortName);
113  provider = strcpyrealloc(provider, Channel.provider);
114  portalName = strcpyrealloc(portalName, Channel.portalName);
115  memcpy(&__BeginData__, &Channel.__BeginData__, (char *)&Channel.__EndData__ - (char *)&Channel.__BeginData__);
116  nameSource = NULL; // these will be recalculated automatically
117  shortNameSource = NULL;
118  parameters = Channel.parameters;
119  return *this;
120 }
121 
122 const char *cChannel::Name(void) const
123 {
124  if (Setup.ShowChannelNamesWithSource && !groupSep) {
125  if (isempty(nameSource))
126  nameSource = cString::sprintf("%s (%c)", name, cSource::ToChar(source));
127  return nameSource;
128  }
129  return name;
130 }
131 
132 const char *cChannel::ShortName(bool OrName) const
133 {
134  if (OrName && isempty(shortName))
135  return Name();
136  if (Setup.ShowChannelNamesWithSource && !groupSep) {
137  if (isempty(shortNameSource))
138  shortNameSource = cString::sprintf("%s (%c)", shortName, cSource::ToChar(source));
139  return shortNameSource;
140  }
141  return shortName;
142 }
143 
144 int cChannel::Transponder(int Frequency, char Polarization)
145 {
146  // some satellites have transponders at the same frequency, just with different polarization:
147  switch (toupper(Polarization)) {
148  case 'H': Frequency += 100000; break;
149  case 'V': Frequency += 200000; break;
150  case 'L': Frequency += 300000; break;
151  case 'R': Frequency += 400000; break;
152  default: esyslog("ERROR: invalid value for Polarization '%c'", Polarization);
153  }
154  return Frequency;
155 }
156 
157 int cChannel::Transponder(void) const
158 {
159  int tf = frequency;
160  while (tf > 20000)
161  tf /= 1000;
162  if (IsSat()) {
163  const char *p = strpbrk(parameters, "HVLRhvlr"); // lowercase for backwards compatibility
164  if (p)
165  tf = Transponder(tf, *p);
166  }
167  return tf;
168 }
169 
170 bool cChannel::HasTimer(void) const
171 {
172  for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) {
173  if (Timer->Channel() == this)
174  return true;
175  }
176  return false;
177 }
178 
180 {
181  int Result = modification & Mask;
182  modification = CHANNELMOD_NONE;
183  return Result;
184 }
185 
187 {
188  if (Channel) {
189  frequency = Channel->frequency;
190  source = Channel->source;
191  srate = Channel->srate;
192  parameters = Channel->parameters;
193  }
194 }
195 
196 bool cChannel::SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet)
197 {
198  if (strchr(Parameters, ':')) {
199  esyslog("ERROR: parameter string '%s' contains ':'", Parameters);
200  return false;
201  }
202  // Workarounds for broadcaster stupidity:
203  // Some providers broadcast the transponder frequency of their channels with two different
204  // values (like 12551 and 12552), so we need to allow for a little tolerance here
205  if (abs(frequency - Frequency) <= 1)
206  Frequency = frequency;
207  // Sometimes the transponder frequency is set to 0, which is just wrong
208  if (Frequency == 0)
209  return false;
210  // Sometimes the symbol rate is off by one
211  if (abs(srate - Srate) <= 1)
212  Srate = srate;
213 
214  if (source != Source || frequency != Frequency || srate != Srate || strcmp(parameters, Parameters)) {
215  cString OldTransponderData = TransponderDataToString();
216  source = Source;
217  frequency = Frequency;
218  srate = Srate;
219  parameters = Parameters;
220  schedule = NULL;
221  nameSource = NULL;
222  shortNameSource = NULL;
223  if (Number() && !Quiet) {
224  dsyslog("changing transponder data of channel %d (%s) from %s to %s", Number(), name, *OldTransponderData, *TransponderDataToString());
225  modification |= CHANNELMOD_TRANSP;
227  }
228  }
229  return true;
230 }
231 
232 void cChannel::SetId(int Nid, int Tid, int Sid, int Rid)
233 {
234  if (nid != Nid || tid != Tid || sid != Sid || rid != Rid) {
235  if (Number()) {
236  dsyslog("changing id of channel %d (%s) from %d-%d-%d-%d to %d-%d-%d-%d", Number(), name, nid, tid, sid, rid, Nid, Tid, Sid, Rid);
237  modification |= CHANNELMOD_ID;
239  Channels.UnhashChannel(this);
240  }
241  nid = Nid;
242  tid = Tid;
243  sid = Sid;
244  rid = Rid;
245  if (Number())
246  Channels.HashChannel(this);
247  schedule = NULL;
248  }
249 }
250 
251 void cChannel::SetLcn(int Lcn)
252 {
253  if (lcn != Lcn) {
254  if (Number())
255  dsyslog("changing lcn of channel %d (%s) from %d to %d\n", Number(), name, lcn, Lcn);
256  lcn = Lcn;
257  }
258 }
259 
260 void cChannel::SetName(const char *Name, const char *ShortName, const char *Provider)
261 {
262  if (!isempty(Name)) {
263  bool nn = strcmp(name, Name) != 0;
264  bool ns = strcmp(shortName, ShortName) != 0;
265  bool np = strcmp(provider, Provider) != 0;
266  if (nn || ns || np) {
267  if (Number()) {
268  dsyslog("changing name of channel %d from '%s,%s;%s' to '%s,%s;%s'", Number(), name, shortName, provider, Name, ShortName, Provider);
269  modification |= CHANNELMOD_NAME;
271  }
272  if (nn) {
273  name = strcpyrealloc(name, Name);
274  nameSource = NULL;
275  }
276  if (ns) {
277  shortName = strcpyrealloc(shortName, ShortName);
278  shortNameSource = NULL;
279  }
280  if (np)
281  provider = strcpyrealloc(provider, Provider);
282  }
283  }
284 }
285 
286 void cChannel::SetPortalName(const char *PortalName)
287 {
288  if (!isempty(PortalName) && strcmp(portalName, PortalName) != 0) {
289  if (Number()) {
290  dsyslog("changing portal name of channel %d (%s) from '%s' to '%s'", Number(), name, portalName, PortalName);
291  modification |= CHANNELMOD_NAME;
293  }
294  portalName = strcpyrealloc(portalName, PortalName);
295  }
296 }
297 
298 #define STRDIFF 0x01
299 #define VALDIFF 0x02
300 
301 static int IntArraysDiffer(const int *a, const int *b, const char na[][MAXLANGCODE2] = NULL, const char nb[][MAXLANGCODE2] = NULL)
302 {
303  int result = 0;
304  for (int i = 0; a[i] || b[i]; i++) {
305  if (!a[i] || !b[i]) {
306  result |= VALDIFF;
307  break;
308  }
309  if (na && nb && strcmp(na[i], nb[i]) != 0)
310  result |= STRDIFF;
311  if (a[i] != b[i])
312  result |= VALDIFF;
313  }
314  return result;
315 }
316 
317 static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[][MAXLANGCODE2] = NULL, const int *t = NULL)
318 {
319  char *q = s;
320  int i = 0;
321  while (a[i] || i == 0) {
322  q += sprintf(q, Base == 16 ? "%s%X" : "%s%d", i ? "," : "", a[i]);
323  const char *Delim = "=";
324  if (a[i]) {
325  if (n && *n[i]) {
326  q += sprintf(q, "%s%s", Delim, n[i]);
327  Delim = "";
328  }
329  if (t && t[i])
330  q += sprintf(q, "%s@%d", Delim, t[i]);
331  }
332  if (!a[i])
333  break;
334  i++;
335  }
336  *q = 0;
337  return q - s;
338 }
339 
340 void cChannel::SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
341 {
342  int mod = CHANNELMOD_NONE;
343  if (vpid != Vpid || ppid != Ppid || vtype != Vtype)
344  mod |= CHANNELMOD_PIDS;
345  if (tpid != Tpid)
346  mod |= CHANNELMOD_AUX;
347  int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(atypes, Atypes) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(dtypes, Dtypes) | IntArraysDiffer(spids, Spids, slangs, SLangs);
348  if (m & STRDIFF)
349  mod |= CHANNELMOD_LANGS;
350  if (m & VALDIFF)
351  mod |= CHANNELMOD_PIDS;
352  if (mod) {
353  const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2 + 5) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod@type', +10: paranoia
354  char OldApidsBuf[BufferSize];
355  char NewApidsBuf[BufferSize];
356  char *q = OldApidsBuf;
357  q += IntArrayToString(q, apids, 10, alangs, atypes);
358  if (dpids[0]) {
359  *q++ = ';';
360  q += IntArrayToString(q, dpids, 10, dlangs, dtypes);
361  }
362  *q = 0;
363  q = NewApidsBuf;
364  q += IntArrayToString(q, Apids, 10, ALangs, Atypes);
365  if (Dpids[0]) {
366  *q++ = ';';
367  q += IntArrayToString(q, Dpids, 10, DLangs, Dtypes);
368  }
369  *q = 0;
370  const int SBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod', +10: paranoia
371  char OldSpidsBuf[SBufferSize];
372  char NewSpidsBuf[SBufferSize];
373  q = OldSpidsBuf;
374  q += IntArrayToString(q, spids, 10, slangs);
375  *q = 0;
376  q = NewSpidsBuf;
377  q += IntArrayToString(q, Spids, 10, SLangs);
378  *q = 0;
379  if (Number())
380  dsyslog("changing pids of channel %d (%s) from %d+%d=%d:%s:%s:%d to %d+%d=%d:%s:%s:%d", Number(), name, vpid, ppid, vtype, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, Vtype, NewApidsBuf, NewSpidsBuf, Tpid);
381  vpid = Vpid;
382  ppid = Ppid;
383  vtype = Vtype;
384  for (int i = 0; i < MAXAPIDS; i++) {
385  apids[i] = Apids[i];
386  atypes[i] = Atypes[i];
387  strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2);
388  }
389  apids[MAXAPIDS] = 0;
390  for (int i = 0; i < MAXDPIDS; i++) {
391  dpids[i] = Dpids[i];
392  dtypes[i] = Dtypes[i];
393  strn0cpy(dlangs[i], DLangs[i], MAXLANGCODE2);
394  }
395  dpids[MAXDPIDS] = 0;
396  for (int i = 0; i < MAXSPIDS; i++) {
397  spids[i] = Spids[i];
398  strn0cpy(slangs[i], SLangs[i], MAXLANGCODE2);
399  }
400  spids[MAXSPIDS] = 0;
401  tpid = Tpid;
402  modification |= mod;
403  if (Number())
405  }
406 }
407 
408 void cChannel::SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds)
409 {
410  if (SubtitlingTypes) {
411  for (int i = 0; i < MAXSPIDS; i++)
412  subtitlingTypes[i] = SubtitlingTypes[i];
413  }
414  if (CompositionPageIds) {
415  for (int i = 0; i < MAXSPIDS; i++)
416  compositionPageIds[i] = CompositionPageIds[i];
417  }
418  if (AncillaryPageIds) {
419  for (int i = 0; i < MAXSPIDS; i++)
420  ancillaryPageIds[i] = AncillaryPageIds[i];
421  }
422 }
423 
425 {
426  seen = time(NULL);
427 }
428 
429 void cChannel::SetCaIds(const int *CaIds)
430 {
431  if (caids[0] && caids[0] <= CA_USER_MAX)
432  return; // special values will not be overwritten
433  if (IntArraysDiffer(caids, CaIds)) {
434  char OldCaIdsBuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
435  char NewCaIdsBuf[MAXCAIDS * 5 + 10];
436  IntArrayToString(OldCaIdsBuf, caids, 16);
437  IntArrayToString(NewCaIdsBuf, CaIds, 16);
438  if (Number())
439  dsyslog("changing caids of channel %d (%s) from %s to %s", Number(), name, OldCaIdsBuf, NewCaIdsBuf);
440  for (int i = 0; i <= MAXCAIDS; i++) { // <= to copy the terminating 0
441  caids[i] = CaIds[i];
442  if (!CaIds[i])
443  break;
444  }
445  modification |= CHANNELMOD_CA;
447  }
448 }
449 
451 {
452  if (Level > 0) {
453  modification |= CHANNELMOD_CA;
455  if (Number() && Level > 1)
456  dsyslog("changing ca descriptors of channel %d (%s)", Number(), name);
457  }
458 }
459 
461 {
462  if (!linkChannels && !LinkChannels)
463  return;
464  if (linkChannels && LinkChannels) {
465  cLinkChannel *lca = linkChannels->First();
466  cLinkChannel *lcb = LinkChannels->First();
467  while (lca && lcb) {
468  if (lca->Channel() != lcb->Channel()) {
469  lca = NULL;
470  break;
471  }
472  lca = linkChannels->Next(lca);
473  lcb = LinkChannels->Next(lcb);
474  }
475  if (!lca && !lcb) {
476  delete LinkChannels;
477  return; // linkage has not changed
478  }
479  }
480  char buffer[((linkChannels ? linkChannels->Count() : 0) + (LinkChannels ? LinkChannels->Count() : 0)) * 6 + 256]; // 6: 5 digit channel number plus blank, 256: other texts (see below) plus reserve
481  char *q = buffer;
482  q += sprintf(q, "linking channel %d (%s) from", Number(), name);
483  if (linkChannels) {
484  for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) {
485  lc->Channel()->SetRefChannel(NULL);
486  q += sprintf(q, " %d", lc->Channel()->Number());
487  }
488  delete linkChannels;
489  }
490  else
491  q += sprintf(q, " none");
492  q += sprintf(q, " to");
493  linkChannels = LinkChannels;
494  if (linkChannels) {
495  for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) {
496  lc->Channel()->SetRefChannel(this);
497  q += sprintf(q, " %d", lc->Channel()->Number());
498  //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name());
499  }
500  }
501  else
502  q += sprintf(q, " none");
503  if (Number())
504  dsyslog("%s", buffer);
505 }
506 
508 {
509  refChannel = RefChannel;
510 }
511 
513 {
514  if (cSource::IsTerr(source))
515  return cString::sprintf("%d:%s:%s", frequency, *parameters, *cSource::ToString(source));
516  return cString::sprintf("%d:%s:%s:%d", frequency, *parameters, *cSource::ToString(source), srate);
517 }
518 
520 {
521  char FullName[strlen(Channel->name) + 1 + strlen(Channel->shortName) + 1 + strlen(Channel->provider) + 1 + 10]; // +10: paranoia
522  char *q = FullName;
523  q += sprintf(q, "%s", Channel->name);
524  if (!Channel->groupSep) {
525  if (!isempty(Channel->shortName))
526  q += sprintf(q, ",%s", Channel->shortName);
527  else if (strchr(Channel->name, ','))
528  q += sprintf(q, ",");
529  if (!isempty(Channel->provider))
530  q += sprintf(q, ";%s", Channel->provider);
531  }
532  *q = 0;
533  strreplace(FullName, ':', '|');
534  cString buffer;
535  if (Channel->groupSep) {
536  if (Channel->number)
537  buffer = cString::sprintf(":@%d %s\n", Channel->number, FullName);
538  else
539  buffer = cString::sprintf(":%s\n", FullName);
540  }
541  else {
542  char vpidbuf[32];
543  char *q = vpidbuf;
544  q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
545  if (Channel->ppid && Channel->ppid != Channel->vpid)
546  q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
547  if (Channel->vpid && Channel->vtype)
548  q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype);
549  *q = 0;
550  const int ABufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2 + 5) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod@type', +10: paranoia
551  char apidbuf[ABufferSize];
552  q = apidbuf;
553  q += IntArrayToString(q, Channel->apids, 10, Channel->alangs, Channel->atypes);
554  if (Channel->dpids[0]) {
555  *q++ = ';';
556  q += IntArrayToString(q, Channel->dpids, 10, Channel->dlangs, Channel->dtypes);
557  }
558  *q = 0;
559  const int TBufferSize = MAXSPIDS * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia and tpid
560  char tpidbuf[TBufferSize];
561  q = tpidbuf;
562  q += snprintf(q, sizeof(tpidbuf), "%d", Channel->tpid);
563  if (Channel->spids[0]) {
564  *q++ = ';';
565  q += IntArrayToString(q, Channel->spids, 10, Channel->slangs);
566  }
567  char caidbuf[MAXCAIDS * 5 + 10]; // 5: 4 digits plus delimiting ',', 10: paranoia
568  q = caidbuf;
569  q += IntArrayToString(q, Channel->caids, 16);
570  *q = 0;
571  buffer = cString::sprintf("%s:%d:%s:%s:%d:%s:%s:%s:%s:%d:%d:%d:%d\n", FullName, Channel->frequency, *Channel->parameters, *cSource::ToString(Channel->source), Channel->srate, vpidbuf, apidbuf, tpidbuf, caidbuf, Channel->sid, Channel->nid, Channel->tid, Channel->rid);
572  }
573  return buffer;
574 }
575 
577 {
578  return ToText(this);
579 }
580 
581 bool cChannel::Parse(const char *s)
582 {
583  bool ok = true;
584  if (*s == ':') {
585  groupSep = true;
586  if (*++s == '@' && *++s) {
587  char *p = NULL;
588  errno = 0;
589  int n = strtol(s, &p, 10);
590  if (!errno && p != s && n > 0) {
591  number = n;
592  s = p;
593  }
594  }
595  name = strcpyrealloc(name, skipspace(s));
596  strreplace(name, '|', ':');
597  }
598  else {
599  groupSep = false;
600  char *namebuf = NULL;
601  char *sourcebuf = NULL;
602  char *parambuf = NULL;
603  char *vpidbuf = NULL;
604  char *apidbuf = NULL;
605  char *tpidbuf = NULL;
606  char *caidbuf = NULL;
607  int fields = sscanf(s, "%m[^:]:%d :%m[^:]:%m[^:] :%d :%m[^:]:%m[^:]:%m[^:]:%m[^:]:%d :%d :%d :%d ", &namebuf, &frequency, &parambuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpidbuf, &caidbuf, &sid, &nid, &tid, &rid);
608  if (fields >= 9) {
609  if (fields == 9) {
610  // allow reading of old format
611  sid = atoi(caidbuf);
612  delete caidbuf;
613  caidbuf = NULL;
614  if (sscanf(tpidbuf, "%d", &tpid) != 1)
615  return false;
616  caids[0] = tpid;
617  caids[1] = 0;
618  tpid = 0;
619  }
620  vpid = ppid = 0;
621  vtype = 0;
622  apids[0] = 0;
623  atypes[0] = 0;
624  dpids[0] = 0;
625  dtypes[0] = 0;
626  spids[0] = 0;
627  ok = false;
628  if (parambuf && sourcebuf && vpidbuf && apidbuf) {
629  parameters = parambuf;
630  ok = (source = cSource::FromString(sourcebuf)) >= 0;
631 
632  char *p;
633  if ((p = strchr(vpidbuf, '=')) != NULL) {
634  *p++ = 0;
635  if (sscanf(p, "%d", &vtype) != 1)
636  return false;
637  }
638  if ((p = strchr(vpidbuf, '+')) != NULL) {
639  *p++ = 0;
640  if (sscanf(p, "%d", &ppid) != 1)
641  return false;
642  }
643  if (sscanf(vpidbuf, "%d", &vpid) != 1)
644  return false;
645  if (!ppid)
646  ppid = vpid;
647  if (vpid && !vtype)
648  vtype = 2; // default is MPEG-2
649 
650  char *dpidbuf = strchr(apidbuf, ';');
651  if (dpidbuf)
652  *dpidbuf++ = 0;
653  p = apidbuf;
654  char *q;
655  int NumApids = 0;
656  char *strtok_next;
657  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
658  if (NumApids < MAXAPIDS) {
659  atypes[NumApids] = 4; // backwards compatibility
660  char *l = strchr(q, '=');
661  if (l) {
662  *l++ = 0;
663  char *t = strchr(l, '@');
664  if (t) {
665  *t++ = 0;
666  atypes[NumApids] = strtol(t, NULL, 10);
667  }
668  strn0cpy(alangs[NumApids], l, MAXLANGCODE2);
669  }
670  else
671  *alangs[NumApids] = 0;
672  if ((apids[NumApids] = strtol(q, NULL, 10)) != 0)
673  NumApids++;
674  }
675  else
676  esyslog("ERROR: too many APIDs!"); // no need to set ok to 'false'
677  p = NULL;
678  }
679  apids[NumApids] = 0;
680  atypes[NumApids] = 0;
681  if (dpidbuf) {
682  char *p = dpidbuf;
683  char *q;
684  int NumDpids = 0;
685  char *strtok_next;
686  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
687  if (NumDpids < MAXDPIDS) {
688  dtypes[NumDpids] = SI::AC3DescriptorTag; // backwards compatibility
689  char *l = strchr(q, '=');
690  if (l) {
691  *l++ = 0;
692  char *t = strchr(l, '@');
693  if (t) {
694  *t++ = 0;
695  dtypes[NumDpids] = strtol(t, NULL, 10);
696  }
697  strn0cpy(dlangs[NumDpids], l, MAXLANGCODE2);
698  }
699  else
700  *dlangs[NumDpids] = 0;
701  if ((dpids[NumDpids] = strtol(q, NULL, 10)) != 0)
702  NumDpids++;
703  }
704  else
705  esyslog("ERROR: too many DPIDs!"); // no need to set ok to 'false'
706  p = NULL;
707  }
708  dpids[NumDpids] = 0;
709  dtypes[NumDpids] = 0;
710  }
711  int NumSpids = 0;
712  if ((p = strchr(tpidbuf, ';')) != NULL) {
713  *p++ = 0;
714  char *q;
715  char *strtok_next;
716  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
717  if (NumSpids < MAXSPIDS) {
718  char *l = strchr(q, '=');
719  if (l) {
720  *l++ = 0;
721  strn0cpy(slangs[NumSpids], l, MAXLANGCODE2);
722  }
723  else
724  *slangs[NumSpids] = 0;
725  spids[NumSpids++] = strtol(q, NULL, 10);
726  }
727  else
728  esyslog("ERROR: too many SPIDs!"); // no need to set ok to 'false'
729  p = NULL;
730  }
731  spids[NumSpids] = 0;
732  }
733  if (sscanf(tpidbuf, "%d", &tpid) != 1)
734  return false;
735  if (caidbuf) {
736  char *p = caidbuf;
737  char *q;
738  int NumCaIds = 0;
739  char *strtok_next;
740  while ((q = strtok_r(p, ",", &strtok_next)) != NULL) {
741  if (NumCaIds < MAXCAIDS) {
742  caids[NumCaIds++] = strtol(q, NULL, 16) & 0xFFFF;
743  if (NumCaIds == 1 && caids[0] <= CA_USER_MAX)
744  break;
745  }
746  else
747  esyslog("ERROR: too many CA ids!"); // no need to set ok to 'false'
748  p = NULL;
749  }
750  caids[NumCaIds] = 0;
751  }
752  }
753  strreplace(namebuf, '|', ':');
754 
755  char *p = strchr(namebuf, ';');
756  if (p) {
757  *p++ = 0;
758  provider = strcpyrealloc(provider, p);
759  }
760  p = strrchr(namebuf, ','); // long name might contain a ',', so search for the rightmost one
761  if (p) {
762  *p++ = 0;
763  shortName = strcpyrealloc(shortName, p);
764  }
765  name = strcpyrealloc(name, namebuf);
766 
767  free(parambuf);
768  free(sourcebuf);
769  free(vpidbuf);
770  free(apidbuf);
771  free(tpidbuf);
772  free(caidbuf);
773  free(namebuf);
774  nameSource = NULL;
775  shortNameSource = NULL;
776  if (!GetChannelID().Valid()) {
777  esyslog("ERROR: channel data results in invalid ID!");
778  return false;
779  }
780  }
781  else
782  return false;
783  }
784  return ok;
785 }
786 
787 bool cChannel::Save(FILE *f)
788 {
789  return fprintf(f, "%s", *ToText()) > 0;
790 }
791 
792 // --- cChannelSorter --------------------------------------------------------
793 
794 class cChannelSorter : public cListObject {
795 public:
799  channel = Channel;
800  channelID = channel->GetChannelID();
801  }
802  virtual int Compare(const cListObject &ListObject) const {
803  cChannelSorter *cs = (cChannelSorter *)&ListObject;
804  return memcmp(&channelID, &cs->channelID, sizeof(channelID));
805  }
806  };
807 
808 // --- cChannels -------------------------------------------------------------
809 
811 
813 {
814  maxNumber = 0;
815  maxChannelNameLength = 0;
816  maxShortChannelNameLength = 0;
817  modified = CHANNELSMOD_NONE;
818 }
819 
821 {
822  cList<cChannelSorter> ChannelSorter;
823  for (cChannel *channel = First(); channel; channel = Next(channel)) {
824  if (!channel->GroupSep())
825  ChannelSorter.Add(new cChannelSorter(channel));
826  }
827  ChannelSorter.Sort();
828  cChannelSorter *cs = ChannelSorter.First();
829  while (cs) {
830  cChannelSorter *next = ChannelSorter.Next(cs);
831  if (next && cs->channelID == next->channelID) {
832  dsyslog("deleting duplicate channel %s", *next->channel->ToText());
833  Del(next->channel);
834  }
835  cs = next;
836  }
837 }
838 
839 bool cChannels::Load(const char *FileName, bool AllowComments, bool MustExist)
840 {
841  if (cConfig<cChannel>::Load(FileName, AllowComments, MustExist)) {
842  DeleteDuplicateChannels();
843  ReNumber();
844  return true;
845  }
846  return false;
847 }
848 
850 {
851  channelsHashSid.Add(Channel, Channel->Sid());
852 }
853 
855 {
856  channelsHashSid.Del(Channel, Channel->Sid());
857 }
858 
860 {
861  cChannel *channel = Get(++Idx);
862  while (channel && !(channel->GroupSep() && *channel->Name()))
863  channel = Get(++Idx);
864  return channel ? Idx : -1;
865 }
866 
868 {
869  cChannel *channel = Get(--Idx);
870  while (channel && !(channel->GroupSep() && *channel->Name()))
871  channel = Get(--Idx);
872  return channel ? Idx : -1;
873 }
874 
876 {
877  cChannel *channel = Get(++Idx);
878  while (channel && channel->GroupSep())
879  channel = Get(++Idx);
880  return channel ? Idx : -1;
881 }
882 
884 {
885  cChannel *channel = Get(--Idx);
886  while (channel && channel->GroupSep())
887  channel = Get(--Idx);
888  return channel ? Idx : -1;
889 }
890 
892 {
893  channelsHashSid.Clear();
894  maxNumber = 0;
895  int Number = 1;
896  for (cChannel *channel = First(); channel; channel = Next(channel)) {
897  if (channel->GroupSep()) {
898  if (channel->Number() > Number)
899  Number = channel->Number();
900  }
901  else {
902  HashChannel(channel);
903  maxNumber = Number;
904  channel->SetNumber(Number++);
905  }
906  }
907 }
908 
909 cChannel *cChannels::GetByNumber(int Number, int SkipGap)
910 {
911  cChannel *previous = NULL;
912  for (cChannel *channel = First(); channel; channel = Next(channel)) {
913  if (!channel->GroupSep()) {
914  if (channel->Number() == Number)
915  return channel;
916  else if (SkipGap && channel->Number() > Number)
917  return SkipGap > 0 ? channel : previous;
918  previous = channel;
919  }
920  }
921  return NULL;
922 }
923 
924 cChannel *cChannels::GetByServiceID(int Source, int Transponder, unsigned short ServiceID)
925 {
926  cList<cHashObject> *list = channelsHashSid.GetList(ServiceID);
927  if (list) {
928  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
929  cChannel *channel = (cChannel *)hobj->Object();
930  if (channel->Sid() == ServiceID && channel->Source() == Source && ISTRANSPONDER(channel->Transponder(), Transponder))
931  return channel;
932  }
933  }
934  return NULL;
935 }
936 
937 cChannel *cChannels::GetByChannelID(tChannelID ChannelID, bool TryWithoutRid, bool TryWithoutPolarization)
938 {
939  int sid = ChannelID.Sid();
940  cList<cHashObject> *list = channelsHashSid.GetList(sid);
941  if (list) {
942  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
943  cChannel *channel = (cChannel *)hobj->Object();
944  if (channel->Sid() == sid && channel->GetChannelID() == ChannelID)
945  return channel;
946  }
947  if (TryWithoutRid) {
948  ChannelID.ClrRid();
949  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
950  cChannel *channel = (cChannel *)hobj->Object();
951  if (channel->Sid() == sid && channel->GetChannelID().ClrRid() == ChannelID)
952  return channel;
953  }
954  }
955  if (TryWithoutPolarization) {
956  ChannelID.ClrPolarization();
957  for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) {
958  cChannel *channel = (cChannel *)hobj->Object();
959  if (channel->Sid() == sid && channel->GetChannelID().ClrPolarization() == ChannelID)
960  return channel;
961  }
962  }
963  }
964  return NULL;
965 }
967 {
968  int source = ChannelID.Source();
969  int nid = ChannelID.Nid();
970  int tid = ChannelID.Tid();
971  for (cChannel *channel = First(); channel; channel = Next(channel)) {
972  if (channel->Tid() == tid && channel->Nid() == nid && channel->Source() == source)
973  return channel;
974  }
975  return NULL;
976 }
977 
978 bool cChannels::HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel)
979 {
980  tChannelID NewChannelID = NewChannel->GetChannelID();
981  for (cChannel *channel = First(); channel; channel = Next(channel)) {
982  if (!channel->GroupSep() && channel != OldChannel && channel->GetChannelID() == NewChannelID)
983  return false;
984  }
985  return true;
986 }
987 
988 bool cChannels::SwitchTo(int Number)
989 {
990  cChannel *channel = GetByNumber(Number);
991  return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
992 }
993 
995 {
996  if (!maxChannelNameLength) {
997  for (cChannel *channel = First(); channel; channel = Next(channel)) {
998  if (!channel->GroupSep())
999  maxChannelNameLength = max(Utf8StrLen(channel->Name()), maxChannelNameLength);
1000  }
1001  }
1002  return maxChannelNameLength;
1003 }
1004 
1006 {
1007  if (!maxShortChannelNameLength) {
1008  for (cChannel *channel = First(); channel; channel = Next(channel)) {
1009  if (!channel->GroupSep())
1010  maxShortChannelNameLength = max(Utf8StrLen(channel->ShortName(true)), maxShortChannelNameLength);
1011  }
1012  }
1013  return maxShortChannelNameLength;
1014 }
1015 
1016 void cChannels::SetModified(bool ByUser)
1017 {
1018  modified = ByUser ? CHANNELSMOD_USER : !modified ? CHANNELSMOD_AUTO : modified;
1019  maxChannelNameLength = maxShortChannelNameLength = 0;
1020 }
1021 
1023 {
1024  int Result = modified;
1025  modified = CHANNELSMOD_NONE;
1026  return Result;
1027 }
1028 
1029 cChannel *cChannels::NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid)
1030 {
1031  if (Transponder) {
1032  dsyslog("creating new channel '%s,%s;%s' on %s transponder %d with id %d-%d-%d-%d", Name, ShortName, Provider, *cSource::ToString(Transponder->Source()), Transponder->Transponder(), Nid, Tid, Sid, Rid);
1033  cChannel *NewChannel = new cChannel;
1034  NewChannel->CopyTransponderData(Transponder);
1035  NewChannel->SetId(Nid, Tid, Sid, Rid);
1036  NewChannel->SetName(Name, ShortName, Provider);
1037  NewChannel->SetSeen();
1038  Add(NewChannel);
1039  ReNumber();
1040  return NewChannel;
1041  }
1042  return NULL;
1043 }
1044 
1045 #define CHANNELMARKOBSOLETE "OBSOLETE"
1046 #define CHANNELTIMEOBSOLETE 3600 // seconds to wait before declaring a channel obsolete (in case it has actually been seen before)
1047 
1049 {
1050  for (cChannel *channel = First(); channel; channel = Next(channel)) {
1051  if (time(NULL) - channel->Seen() > CHANNELTIMEOBSOLETE && channel->Source() == Source && channel->Nid() == Nid && channel->Tid() == Tid && channel->Rid() == 0) {
1052  bool OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
1054  if (!endswith(channel->Name(), CHANNELMARKOBSOLETE))
1055  channel->SetName(cString::sprintf("%s %s", channel->Name(), CHANNELMARKOBSOLETE), channel->ShortName(), cString::sprintf("%s %s", CHANNELMARKOBSOLETE, channel->Provider()));
1056  Setup.ShowChannelNamesWithSource = OldShowChannelNamesWithSource;
1057  }
1058  }
1059 }
1060 
1061 cString ChannelString(const cChannel *Channel, int Number)
1062 {
1063  char buffer[256];
1064  if (Channel) {
1065  if (Channel->GroupSep())
1066  snprintf(buffer, sizeof(buffer), "%s", Channel->Name());
1067  else
1068  snprintf(buffer, sizeof(buffer), "%d%s %s", Channel->Number(), Number ? "-" : "", Channel->Name());
1069  }
1070  else if (Number)
1071  snprintf(buffer, sizeof(buffer), "%d-", Number);
1072  else
1073  snprintf(buffer, sizeof(buffer), "%s", tr("*** Invalid Channel ***"));
1074  return buffer;
1075 }
static cString ToString(int Code)
Definition: sources.c:55
int sid
Definition: channels.h:56
unsigned char uchar
Definition: tools.h:30
void SetId(int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:232
int Modified(void)
Returns 0 if no channels have been modified, 1 if an automatic modification has been made...
Definition: channels.c:1022
#define CHANNELTIMEOBSOLETE
Definition: channels.c:1046
int Number(void) const
Definition: channels.h:179
int tid
Definition: channels.h:121
cChannels Channels
Definition: channels.c:810
static char ToChar(int Code)
Definition: sources.h:51
bool isempty(const char *s)
Definition: tools.c:297
static tChannelID FromString(const char *s)
Definition: channels.c:25
#define dsyslog(a...)
Definition: tools.h:36
int Utf8StrLen(const char *s)
Returns the number of UTF-8 symbols formed by the given string of character bytes.
Definition: tools.c:833
int GetPrevGroup(int Idx)
Definition: channels.c:867
int MaxShortChannelNameLength(void)
Definition: channels.c:1005
int Rid(void) const
Definition: channels.h:69
void CopyTransponderData(const cChannel *Channel)
Definition: channels.c:186
#define CHANNELMOD_PIDS
Definition: channels.h:23
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2014
static cString ToText(const cChannel *Channel)
Definition: channels.c:519
#define CHANNELMOD_AUX
Definition: channels.h:25
tChannelID(void)
Definition: channels.h:59
cTimers Timers
Definition: timers.c:694
bool endswith(const char *s, const char *p)
Definition: tools.c:286
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition: tools.c:1080
#define CHANNELMOD_TRANSP
Definition: channels.h:27
int tid
Definition: channels.h:55
static bool IsTerr(int Code)
Definition: sources.h:58
int ppid
Definition: channels.h:105
#define CHANNELMOD_NONE
Definition: channels.h:20
void MarkObsoleteChannels(int Source, int Nid, int Tid)
Definition: channels.c:1048
tChannelID channelID
Definition: channels.c:797
#define esyslog(a...)
Definition: tools.h:34
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
const char * ShortName(bool OrName=false) const
Definition: channels.c:132
cChannel & operator=(const cChannel &Channel)
Definition: channels.c:109
T max(T a, T b)
Definition: tools.h:55
Definition: tools.h:489
bool GroupSep(void) const
Definition: channels.h:181
#define CHANNELMOD_CA
Definition: channels.h:26
int Sid(void) const
Definition: channels.h:68
tChannelID & ClrPolarization(void)
Definition: channels.c:49
char * name
Definition: channels.h:96
void ReNumber(void)
Definition: channels.c:891
int spids[MAXSPIDS+1]
Definition: channels.h:113
int MaxChannelNameLength(void)
Definition: channels.c:994
int nid
actually the "original" network id
Definition: channels.h:54
int Count(void) const
Definition: tools.h:485
cString ChannelString(const cChannel *Channel, int Number)
Definition: channels.c:1061
int Transponder(void) const
Returns the transponder frequency in MHz, plus the polarization in case of sat.
Definition: channels.c:157
bool groupSep
Definition: channels.h:126
int nid
Definition: channels.h:120
char * provider
Definition: channels.h:98
bool Save(FILE *f)
Definition: channels.c:787
int tpid
Definition: channels.h:118
bool Load(const char *FileName, bool AllowComments=false, bool MustExist=false)
Definition: channels.c:839
bool SetTransponderData(int Source, int Frequency, int Srate, const char *Parameters, bool Quiet=false)
Definition: channels.c:196
Definition: timers.h:27
#define CHANNELMOD_LANGS
Definition: channels.h:28
cChannel * Channel(void)
Definition: channels.h:82
char * shortName
Definition: channels.h:97
#define STRDIFF
Definition: channels.c:298
const char * Name(void) const
Definition: channels.c:122
cChannel * NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid=0)
Definition: channels.c:1029
T * Next(const T *object) const
Definition: tools.h:495
void SetName(const char *Name, const char *ShortName, const char *Provider)
Definition: channels.c:260
int Source(void) const
Definition: channels.h:152
#define ISTRANSPONDER(f1, f2)
Definition: channels.h:18
virtual int Compare(const cListObject &ListObject) const
Must return 0 if this object is equal to ListObject, a positive value if it is "greater", and a negative value if it is "smaller".
Definition: channels.c:802
char alangs[MAXAPIDS][MAXLANGCODE2]
Definition: channels.h:109
cChannel(void)
Definition: channels.c:58
bool Parse(const char *s)
Definition: channels.c:581
#define CHANNELMOD_NAME
Definition: channels.h:22
cListObject * Next(void) const
Definition: tools.h:468
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:750
int GetNextNormal(int Idx)
Definition: channels.c:875
#define VALDIFF
Definition: channels.c:299
int source
Definition: channels.h:53
#define CHANNELSMOD_NONE
Definition: channels.h:31
int GetPrevNormal(int Idx)
Definition: channels.c:883
void Sort(void)
Definition: tools.c:2115
#define CA_USER_MAX
Definition: channels.h:47
void SetCaDescriptors(int Level)
Definition: channels.c:450
cChannels(void)
Definition: channels.c:812
int __EndData__
Definition: channels.h:127
char dlangs[MAXDPIDS][MAXLANGCODE2]
Definition: channels.h:112
int atypes[MAXAPIDS+1]
Definition: channels.h:108
int rid
Definition: channels.h:123
cSetup Setup
Definition: config.c:372
tChannelID GetChannelID(void) const
Definition: channels.h:190
int frequency
Definition: channels.h:101
void SetModified(bool ByUser=false)
Definition: channels.c:1016
int GetNextGroup(int Idx)
Definition: channels.c:859
cString TransponderDataToString(void) const
Definition: channels.c:512
void SetLcn(int Lcn)
Definition: channels.c:251
cChannel * GetByServiceID(int Source, int Transponder, unsigned short ServiceID)
Definition: channels.c:924
int __BeginData__
Definition: channels.h:100
static int IntArrayToString(char *s, const int *a, int Base=10, const char n[][MAXLANGCODE2]=NULL, const int *t=NULL)
Definition: channels.c:317
void SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds)
Definition: channels.c:408
cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false)
Definition: channels.c:937
int vpid
Definition: channels.h:104
#define MAXLANGCODE2
Definition: channels.h:41
bool HasTimer(void) const
Definition: channels.c:170
bool Valid(void) const
Definition: channels.h:62
#define CHANNELSMOD_AUTO
Definition: channels.h:32
int sid
Definition: channels.h:122
void SetLinkChannels(cLinkChannels *LinkChannels)
Definition: channels.c:460
bool HasUniqueChannelID(cChannel *NewChannel, cChannel *OldChannel=NULL)
Definition: channels.c:978
#define MAXDPIDS
Definition: channels.h:36
T * First(void) const
Definition: tools.h:492
cString ToString(void) const
Definition: channels.c:42
void SetRefChannel(cChannel *RefChannel)
Definition: channels.c:507
int ShowChannelNamesWithSource
Definition: config.h:359
int dpids[MAXDPIDS+1]
Definition: channels.h:110
cChannel * GetByNumber(int Number, int SkipGap=0)
Definition: channels.c:909
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:137
void DeleteDuplicateChannels(void)
Definition: channels.c:820
static int FromString(const char *s)
Definition: sources.c:68
#define tr(s)
Definition: i18n.h:85
~cChannel()
Definition: channels.c:85
int source
Definition: channels.h:102
cChannel * channel
Definition: channels.c:796
char * skipspace(const char *s)
Definition: tools.h:200
cString parameters
Definition: channels.h:130
#define CHANNELSMOD_USER
Definition: channels.h:33
char * strcpyrealloc(char *dest, const char *src)
Definition: tools.c:114
static int IntArraysDiffer(const int *a, const int *b, const char na[][MAXLANGCODE2]=NULL, const char nb[][MAXLANGCODE2]=NULL)
Definition: channels.c:301
int rid
Definition: channels.h:57
char slangs[MAXSPIDS][MAXLANGCODE2]
Definition: channels.h:114
#define MAXSPIDS
Definition: channels.h:37
int vtype
Definition: channels.h:106
int caids[MAXCAIDS+1]
Definition: channels.h:119
int Tid(void) const
Definition: channels.h:67
cChannel * GetByTransponderID(tChannelID ChannelID)
Definition: channels.c:966
static const tChannelID InvalidID
Definition: channels.h:72
int Modification(int Mask=CHANNELMOD_ALL)
Definition: channels.c:179
bool SwitchTo(int Number)
Definition: channels.c:988
void UnhashChannel(cChannel *Channel)
Definition: channels.c:854
cChannelSorter(cChannel *Channel)
Definition: channels.c:798
int number
Definition: channels.h:125
#define MAXCAIDS
Definition: channels.h:38
void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, int *Atypes, char ALangs[][MAXLANGCODE2], int *Dpids, int *Dtypes, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
Definition: channels.c:340
int Sid(void) const
Definition: channels.h:176
void SetPortalName(const char *PortalName)
Definition: channels.c:286
tChannelID & ClrRid(void)
Definition: channels.h:63
#define CHANNELMARKOBSOLETE
Definition: channels.c:1045
char * portalName
Definition: channels.h:99
void SetSeen(void)
Definition: channels.c:424
#define CHANNELMOD_ID
Definition: channels.h:24
char * strreplace(char *s, char c1, char c2)
Definition: tools.c:139
void SetCaIds(const int *CaIds)
Definition: channels.c:429
cString ToText(void) const
Definition: channels.c:576
int srate
Definition: channels.h:103
void HashChannel(cChannel *Channel)
Definition: channels.c:849
Definition: tools.h:168
int Source(void) const
Definition: channels.h:65
int apids[MAXAPIDS+1]
Definition: channels.h:107
#define MAXAPIDS
Definition: channels.h:35
int Nid(void) const
Definition: channels.h:66
int dtypes[MAXAPIDS+1]
Definition: channels.h:111