summaryrefslogtreecommitdiff
path: root/sections.c
diff options
context:
space:
mode:
Diffstat (limited to 'sections.c')
-rw-r--r--sections.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/sections.c b/sections.c
new file mode 100644
index 0000000..6b4d490
--- /dev/null
+++ b/sections.c
@@ -0,0 +1,187 @@
+/*
+ * sections.c: Section data handling
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: sections.c 1.2 2004/01/03 12:54:01 kls Exp $
+ */
+
+#include "sections.h"
+#include <unistd.h>
+#include "device.h"
+
+// --- cFilterHandle----------------------------------------------------------
+
+class cFilterHandle : public cListObject {
+public:
+ cFilterData filterData;
+ int handle;
+ int used;
+ cFilterHandle(const cFilterData &FilterData);
+ };
+
+cFilterHandle::cFilterHandle(const cFilterData &FilterData)
+{
+ filterData = FilterData;
+ handle = -1;
+ used = 0;
+}
+
+// --- cSectionHandler -------------------------------------------------------
+
+cSectionHandler::cSectionHandler(cDevice *Device)
+:cThread("Section handler")
+{
+ device = Device;
+ active = false;
+ source = 0;
+ transponder = 0;
+ statusCount = 0;
+ on = false;
+ Start();
+}
+
+cSectionHandler::~cSectionHandler()
+{
+ active = false;
+ Cancel(3);
+ cFilter *fi;
+ while ((fi = filters.First()) != NULL)
+ Detach(fi);
+}
+
+void cSectionHandler::Add(const cFilterData *FilterData)
+{
+ Lock();
+ statusCount++;
+ cFilterHandle *fh;
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask))
+ break;
+ }
+ if (!fh) {
+ fh = new cFilterHandle(*FilterData);
+ filterHandles.Add(fh);
+ fh->handle = device->OpenFilter(FilterData->pid, FilterData->tid, FilterData->mask);
+ }
+ fh->used++;
+ Unlock();
+}
+
+void cSectionHandler::Del(const cFilterData *FilterData)
+{
+ Lock();
+ statusCount++;
+ cFilterHandle *fh;
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
+ if (--fh->used <= 0) {
+ close(fh->handle);
+ filterHandles.Del(fh);
+ break;
+ }
+ }
+ }
+ Unlock();
+}
+
+void cSectionHandler::Attach(cFilter *Filter)
+{
+ Lock();
+ statusCount++;
+ filters.Add(Filter);
+ Filter->sectionHandler = this;
+ Filter->SetStatus(true);
+ Unlock();
+}
+
+void cSectionHandler::Detach(cFilter *Filter)
+{
+ Lock();
+ statusCount++;
+ Filter->SetStatus(false);
+ Filter->sectionHandler = NULL;
+ filters.Del(Filter, false);
+ Unlock();
+}
+
+void cSectionHandler::SetSource(int Source, int Transponder)
+{
+ Lock();
+ source = Source;
+ transponder = Transponder;
+ Unlock();
+}
+
+void cSectionHandler::SetStatus(bool On)
+{
+ Lock();
+ if (on != On) {
+ statusCount++;
+ for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
+ fi->SetStatus(false);
+ if (On)
+ fi->SetStatus(true);
+ }
+ on = On;
+ }
+ Unlock();
+}
+
+void cSectionHandler::Action(void)
+{
+ active = true;
+ while (active) {
+
+ Lock();
+ int NumFilters = filterHandles.Count();
+ pollfd pfd[NumFilters];
+ for (cFilterHandle *fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ int i = fh->Index();
+ pfd[i].fd = fh->handle;
+ pfd[i].events = POLLIN;
+ }
+ int oldStatusCount = statusCount;
+ Unlock();
+
+ if (poll(pfd, NumFilters, 1000) != 0) {
+ bool DeviceHasLock = device->HasLock();
+ if (!DeviceHasLock)
+ usleep(100000);
+ for (int i = 0; i < NumFilters; i++) {
+ if (pfd[i].revents & POLLIN) {
+ cFilterHandle *fh = NULL;
+ LOCK_THREAD;
+ if (statusCount != oldStatusCount)
+ break;
+ for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
+ if (pfd[i].fd == fh->handle)
+ break;
+ }
+ if (fh) {
+ // Read section data:
+ unsigned char buf[4096]; // max. allowed size for any EIT section
+ int r = safe_read(fh->handle, buf, sizeof(buf));
+ if (!DeviceHasLock)
+ continue; // we do the read anyway, to flush any data that might have come from a different transponder
+ if (r > 3) { // minimum number of bytes necessary to get section length
+ int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
+ if (len == r) {
+ // Distribute data to all attached filters:
+ int pid = fh->filterData.pid;
+ int tid = buf[0];
+ for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
+ if (fi->Matches(pid, tid))
+ fi->Process(pid, tid, buf, len);
+ }
+ }
+ else
+ dsyslog("read incomplete section - len = %d, r = %d", len, r);
+ }
+ }
+ }
+ }
+ }
+ }
+}