Index: common.h
===================================================================
RCS file: /var/cvsroot/streamdev/common.h,v
retrieving revision 1.7
diff -u -r1.7 common.h
--- common.h	6 Nov 2005 16:43:58 -0000	1.7
+++ common.h	3 Apr 2007 14:34:54 -0000
@@ -83,6 +83,7 @@
 enum eSocketId {
 	siLive,
 	siReplay,
+	siLiveFilter,
 	si_Count
 };
 
@@ -121,4 +122,8 @@
 	virtual eOSState ProcessKey(eKeys Key);
 };
 
+#if VDRVERSNUM >= 10300
+#       define FILTERTEST
+#endif
+
 #endif // VDR_STREAMDEV_COMMON_H
Index: client/device.c
===================================================================
RCS file: /var/cvsroot/streamdev/client/device.c,v
retrieving revision 1.8
diff -u -r1.8 device.c
--- client/device.c	15 Jan 2007 12:15:12 -0000	1.8
+++ client/device.c	3 Apr 2007 14:34:54 -0000
@@ -59,13 +59,22 @@
 
 bool cStreamdevDevice::ProvidesSource(int Source) const {
 	Dprintf("ProvidesSource, Source=%d\n", Source);
-	return false;
+	return true;
 }
 
 bool cStreamdevDevice::ProvidesTransponder(const cChannel *Channel) const
 {
 	Dprintf("ProvidesTransponder\n");
-	return false;
+	return true;
+}
+
+bool cStreamdevDevice::IsTunedToTransponder(const cChannel *Channel)
+{
+	bool res = false;
+	if (ClientSocket.DataSocket(siLive) != NULL 
+	    && TRANSPONDER(Channel, m_Channel))
+		res = true;
+	return res;
 }
 
 bool cStreamdevDevice::ProvidesChannel(const cChannel *Channel, int Priority, 
@@ -132,12 +141,7 @@
 	Dprintf("OpenDvr\n");
 	CloseDvr();
 	if (ClientSocket.CreateDataConnection(siLive)) {
-		//m_Assembler = new cStreamdevAssembler(ClientSocket.DataSocket(siLive));
-		//m_TSBuffer = new cTSBuffer(m_Assembler->ReadPipe(), MEGABYTE(2), CardIndex() + 1);
 		m_TSBuffer = new cTSBuffer(*ClientSocket.DataSocket(siLive), MEGABYTE(2), CardIndex() + 1);
-		Dprintf("waiting\n");
-		//m_Assembler->WaitForFill();
-		Dprintf("resuming\n");
 		return true;
 	}
 	return false;
@@ -162,6 +166,19 @@
 #if VDRVERSNUM >= 10300
 int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
 	Dprintf("OpenFilter\n");
+
+# ifdef FILTERTEST
+	if(! ClientSocket.DataSocket(siLiveFilter)) {
+	        if (ClientSocket.CreateDataConnection(siLiveFilter)) {
+		        if(!m_Filters)
+			        m_Filters = new cStreamdevFilters;
+		        m_Filters->SetConnection(*ClientSocket.DataSocket(siLiveFilter));
+		} else {
+		        isyslog("OpenFilter: connect failed");
+			return -1;
+		}
+	}
+# endif
 	if (StreamdevClientSetup.StreamFilters 
 			&& ClientSocket.SetFilter(Pid, Tid, Mask, true)) {
 		return m_Filters->OpenFilter(Pid, Tid, Mask);
Index: client/device.h
===================================================================
RCS file: /var/cvsroot/streamdev/client/device.h,v
retrieving revision 1.3
diff -u -r1.3 device.h
--- client/device.h	8 Feb 2005 15:21:19 -0000	1.3
+++ client/device.h	3 Apr 2007 14:34:54 -0000
@@ -51,9 +51,10 @@
 	virtual ~cStreamdevDevice();
 
 	virtual bool ProvidesSource(int Source) const;
-  virtual bool ProvidesTransponder(const cChannel *Channel) const;
+	virtual bool ProvidesTransponder(const cChannel *Channel) const;
 	virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1,
 			bool *NeedsDetachReceivers = NULL) const;
+	virtual bool IsTunedToTransponder(const cChannel *Channel);
 
 	static bool Init(void);
 	static bool ReInit(void);
Index: client/filter.c
===================================================================
RCS file: /var/cvsroot/streamdev/client/filter.c,v
retrieving revision 1.3
diff -u -r1.3 filter.c
--- client/filter.c	6 Nov 2005 16:43:58 -0000	1.3
+++ client/filter.c	3 Apr 2007 14:34:55 -0000
@@ -7,27 +7,71 @@
 #include "tools/select.h"
 #include "common.h"
 
-#include <vdr/ringbuffer.h>
 #include <vdr/device.h>
 
 #if VDRVERSNUM >= 10300
 
+// --- cStreamdevFilter ------------------------------------------------------
+
+class cStreamdevFilter: public cListObject {
+private:
+	uchar              m_Buffer[4096];
+	int                m_Used;
+	int                m_Pipe[2];
+	u_short            m_Pid;
+	u_char             m_Tid;
+	u_char             m_Mask;
+
+public:
+	cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask);
+	virtual ~cStreamdevFilter();
+
+	bool Matches(u_short Pid, u_char Tid);
+	bool PutSection(const uchar *Data, int Length);
+	int  ReadPipe(void) const { return m_Pipe[0]; }
+
+	bool IsClosed(void);
+	void Reset(void);
+
+	u_short Pid(void) const { return m_Pid; }
+	u_char Tid(void) const { return m_Tid; }
+	u_char Mask(void) const { return m_Mask; }
+};
+
+inline bool cStreamdevFilter::Matches(u_short Pid, u_char Tid) {
+	return m_Pid == Pid && m_Tid == (Tid & m_Mask);
+}
+
+
 cStreamdevFilter::cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask) {
 	m_Used = 0;
 	m_Pid  = Pid;
 	m_Tid  = Tid;
 	m_Mask = Mask;
+	m_Pipe[0] = m_Pipe[1] = -1;
 
-	if (pipe(m_Pipe) != 0 || fcntl(m_Pipe[0], F_SETFL, O_NONBLOCK) != 0) {
-		esyslog("streamev-client: coudln't open section filter pipe: %m");
-		m_Pipe[0] = m_Pipe[1] = -1;
+#ifdef SOCK_SEQPACKET  
+	// SOCK_SEQPACKET (since kernel 2.6.4)
+	if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, m_Pipe) != 0) {
+	        esyslog("streamev-client: socketpair(SOCK_SEQPACKET) failed: %m, trying SOCK_DGRAM");
+	}
+#endif
+	if (m_Pipe[0] < 0 && socketpair(AF_UNIX, SOCK_DGRAM, 0, m_Pipe) != 0) {
+	        esyslog("streamev-client: coudln't open section filter socket: %m");
+	} 
+
+	else if(fcntl(m_Pipe[0], F_SETFL, O_NONBLOCK) != 0 ||
+		fcntl(m_Pipe[1], F_SETFL, O_NONBLOCK) != 0) {
+	        esyslog("streamev-client: coudln't set section filter socket to non-blocking mode: %m");
 	}
 }
 
 cStreamdevFilter::~cStreamdevFilter() {
 	Dprintf("~cStreamdevFilter %p\n", this);
-	if (m_Pipe[0] >= 0)
-		close(m_Pipe[0]);
+
+	// ownership of handle m_Pipe[0] has been transferred to VDR section handler
+	//if (m_Pipe[0] >= 0)
+	//	close(m_Pipe[0]);
 	if (m_Pipe[1] >= 0)
 		close(m_Pipe[1]);
 }
@@ -36,84 +80,169 @@
 	if (m_Used + Length >= (int)sizeof(m_Buffer)) {
 		esyslog("ERROR: Streamdev: Section handler buffer overflow (%d bytes lost)",
 				Length);
-		m_Used = 0;
+		Reset();
 		return true;
 	}
+
 	memcpy(m_Buffer + m_Used, Data, Length);
 	m_Used += Length;
-
 	if (m_Used > 3) {
 		int length = (((m_Buffer[1] & 0x0F) << 8) | m_Buffer[2]) + 3;
 		if (m_Used == length) {
-			if (write(m_Pipe[1], m_Buffer, length) < 0)
-				return false;
 			m_Used = 0;
+		        if (write(m_Pipe[1], m_Buffer, length) < 0) {
+			        if(errno == EAGAIN || errno == EWOULDBLOCK) 
+				        dsyslog("cStreamdevFilter::PutSection socket overflow, "
+						"Pid %4d Tid %3d", m_Pid, m_Tid);
+
+				else
+				        return false;
+			}
 		}
+
+		if (m_Used > length) {
+		        dsyslog("cStreamdevFilter::PutSection: m_Used > length !  Pid %2d, Tid%2d "
+				"(len %3d, got %d/%d)", m_Pid, m_Tid, Length, m_Used, length);
+			if(Length < TS_SIZE-5) {
+			        // TS packet not full -> this must be last TS packet of section data -> safe to reset now
+			        Reset();
+			}
+		}
+
 	}
 	return true;
 }
 
+void cStreamdevFilter::Reset(void) {
+	if(m_Used)
+		dsyslog("cStreamdevFilter::Reset skipping %d bytes", m_Used);
+	m_Used = 0;
+}
+
+bool cStreamdevFilter::IsClosed(void) {
+	char m_Buffer[3] = {0,0,0}; /* tid 0, 0 bytes */
+
+	// Test if pipe/socket has been closed by writing empty section
+	if (write(m_Pipe[1], m_Buffer, 3) < 0 &&
+	    errno != EAGAIN &&  
+	    errno != EWOULDBLOCK) {
+
+	        if (errno != ECONNREFUSED &&
+		    errno != ECONNRESET &&
+		    errno != EPIPE)
+		        esyslog("cStreamdevFilter::TestPipe: failed: %m");
+
+		return true;
+	}
+
+	return false;
+}
+
+// --- cStreamdevFilters -----------------------------------------------------
+
 cStreamdevFilters::cStreamdevFilters(void):
 		cThread("streamdev-client: sections assembler") {
 	m_Active = false;
-	m_RingBuffer = new cRingBufferLinear(MEGABYTE(1), TS_SIZE * 2, true);
-	Start();
+	m_TSBuffer = NULL;
 }
 
 cStreamdevFilters::~cStreamdevFilters() {
-	if (m_Active) {
-		m_Active = false;
-		Cancel(3);
-	}
-	delete m_RingBuffer;
+	SetConnection(-1);
 }
 
 int cStreamdevFilters::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
+	CarbageCollect();
+
 	cStreamdevFilter *f = new cStreamdevFilter(Pid, Tid, Mask);
+	int fh = f->ReadPipe();
+
+	Lock();
 	Add(f);
-	return f->ReadPipe();
+	Unlock();
+
+	return fh;
 }
 
-cStreamdevFilter *cStreamdevFilters::Matches(u_short Pid, u_char Tid) {
-	for (cStreamdevFilter *f = First(); f; f = Next(f)) {
-		if (f->Matches(Pid, Tid))
-			return f;
+void cStreamdevFilters::CarbageCollect(void) {
+	Lock();
+	for (cStreamdevFilter *fi = First(); fi;) {
+	        if (fi->IsClosed()) {
+		        if (errno == ECONNREFUSED ||
+			    errno == ECONNRESET ||
+			    errno == EPIPE) {
+			        ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), false);
+				//dsyslog("   * CarbageCollector: filter closed: Pid %4d, Tid %3d, Mask %2x (%d filters left)", 
+				//	(int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
+
+				cStreamdevFilter *next = Prev(fi);
+				Del(fi);
+				fi = next ? Next(next) : First();
+			} else {
+			        isyslog("   * CarbageCollector: error: Pid %4d, Tid %3d, Mask %2x (%d filters left)", 
+					(int)fi->Pid(), (int)fi->Tid(), fi->Mask(), Count()-1);
+				LOG_ERROR;
+				fi = Next(fi);
+			}
+		} else {
+		        fi = Next(fi);
+		}
 	}
-	return NULL;
+	Unlock();
 }
 
-void cStreamdevFilters::Put(const uchar *Data) {
-	int p = m_RingBuffer->Put(Data, TS_SIZE);
-	if (p != TS_SIZE)
-		m_RingBuffer->ReportOverflow(TS_SIZE - p);
+void cStreamdevFilters::SetConnection(int Handle) {
+
+	if(m_Active) {
+		m_Active = false;
+		Cancel(1);
+	}
+	if(m_TSBuffer)
+	      DELETENULL(m_TSBuffer);
+
+	if(Handle >= 0) {
+	        m_TSBuffer = new cTSBuffer(Handle, MEGABYTE(1), 1);
+		m_Active = true;
+		Start();
+	}
 }
 
 void cStreamdevFilters::Action(void) {
-	m_Active = true;
 	while (m_Active) {
-		int recvd;
-		const uchar *block = m_RingBuffer->Get(recvd);
-
-		if (block && recvd > 0) {
-			cStreamdevFilter *f;
+		const uchar *block = m_TSBuffer->Get();
+		if (block) {
 			u_short pid = (((u_short)block[1] & PID_MASK_HI) << 8) | block[2];
 			u_char tid = block[3];
-		
-			if ((f = Matches(pid, tid)) != NULL) {
-				int len = block[4];
-				if (!f->PutSection(block + 5, len)) {
-					if (errno != EPIPE) {
+			int len = block[4];
+
+			LOCK_THREAD;
+			cStreamdevFilter *f = First();
+
+			while(f) {
+			        cStreamdevFilter *next = Next(f);
+				if (f->Matches(pid, tid)) {
+
+				        if (f->PutSection(block + 5, len))
+					        break;
+
+					if (errno != ECONNREFUSED && 
+					    errno != ECONNRESET &&
+					    errno != EPIPE) {
+					        Dprintf("FATAL ERROR: %m\n");
 						esyslog("streamdev-client: couldn't send section packet: %m");
-						Dprintf("FATAL ERROR: %m\n");
 					}
 					ClientSocket.SetFilter(f->Pid(), f->Tid(), f->Mask(), false);
 					Del(f);
+					// Filter was closed.
+					//  - need to check remaining filters for another match
 				}
+				f = next;
 			}
-			m_RingBuffer->Del(TS_SIZE);
-		} else
+		} else {
 			usleep(1);
+		}
 	}
+
+	dsyslog("StreamdevFilters::Action() ended");
 }
 
 #endif // VDRVERSNUM >= 10300
Index: client/filter.h
===================================================================
RCS file: /var/cvsroot/streamdev/client/filter.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 filter.h
--- client/filter.h	30 Dec 2004 22:44:04 -0000	1.1.1.1
+++ client/filter.h	3 Apr 2007 14:34:55 -0000
@@ -12,52 +12,25 @@
 #include <vdr/tools.h>
 #include <vdr/thread.h>
 
-class cRingBufferFrame;
-class cRingBufferLinear;
-
-class cStreamdevFilter: public cListObject {
-private:
-	uchar              m_Buffer[4096];
-	int                m_Used;
-	int                m_Pipe[2];
-	u_short            m_Pid;
-	u_char             m_Tid;
-	u_char             m_Mask;
-	cRingBufferFrame  *m_RingBuffer;
-
-public:
-	cStreamdevFilter(u_short Pid, u_char Tid, u_char Mask);
-	virtual ~cStreamdevFilter();
-
-	bool Matches(u_short Pid, u_char Tid);
-	bool PutSection(const uchar *Data, int Length);
-	int ReadPipe(void) const { return m_Pipe[0]; }
-
-	u_short Pid(void) const { return m_Pid; }
-	u_char Tid(void) const { return m_Tid; }
-	u_char Mask(void) const { return m_Mask; }
-
-};
-
-inline bool cStreamdevFilter::Matches(u_short Pid, u_char Tid) {
-	return m_Pid == Pid && m_Tid == (Tid & m_Mask);
-}
+class cTSBuffer;
+class cStreamdevFilter;
 
 class cStreamdevFilters: public cList<cStreamdevFilter>, public cThread {
 private:
 	bool               m_Active;
-	cRingBufferLinear *m_RingBuffer;
-
+	cTSBuffer         *m_TSBuffer;
+	
 protected:
 	virtual void Action(void);
 
+	void CarbageCollect(void);
+
 public:
 	cStreamdevFilters(void);
 	virtual ~cStreamdevFilters();
 
 	int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
-	cStreamdevFilter *Matches(u_short Pid, u_char Tid);
-	void Put(const uchar *Data);
+	void SetConnection(int Handle);
 };
 
 #	endif // VDRVERSNUM >= 10300
Index: server/connectionVTP.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/connectionVTP.c,v
retrieving revision 1.8
diff -u -r1.8 connectionVTP.c
--- server/connectionVTP.c	2 Mar 2007 15:27:07 -0000	1.8
+++ server/connectionVTP.c	3 Apr 2007 14:34:55 -0000
@@ -468,6 +468,8 @@
 		cServerConnection("VTP"),
 		m_LiveSocket(NULL),
 		m_LiveStreamer(NULL),
+		m_FilterSocket(NULL),
+		m_FilterStreamer(NULL),
 		m_LastCommand(NULL),
 		m_NoTSPIDS(false),
 		m_LSTEHandler(NULL),
@@ -482,6 +484,8 @@
 		free(m_LastCommand);
 	delete m_LiveStreamer;
 	delete m_LiveSocket;
+	delete m_FilterStreamer;
+	delete m_FilterSocket;
 	delete m_LSTTHandler;
 	delete m_LSTCHandler;
 	delete m_LSTEHandler;
@@ -501,11 +505,13 @@
 void cConnectionVTP::Detach(void) 
 {
 	if (m_LiveStreamer != NULL) m_LiveStreamer->Detach();
+	if (m_FilterStreamer != NULL) m_FilterStreamer->Detach();
 }
 
 void cConnectionVTP::Attach(void) 
 {
 	if (m_LiveStreamer != NULL) m_LiveStreamer->Attach();
+	if (m_FilterStreamer != NULL) m_FilterStreamer->Attach();
 }
 
 bool cConnectionVTP::Command(char *Cmd) 
@@ -575,6 +581,15 @@
 		return Respond(220, "Capability \"%s\" accepted", Opts);
 	}
 
+#ifdef FILTERTEST
+	//
+	// Deliver section filters data in separate, channel-independent data stream
+	//
+	if (strcasecmp(Opts, "FILTERS") == 0) {
+		return Respond(220, "Capability \"%s\" accepted", Opts);
+	}
+#endif
+
 	return Respond(561, "Capability \"%s\" not known", Opts);
 }
 
@@ -608,8 +623,13 @@
 	if (ep == Opts || !isspace(*ep))
 		return Respond(500, "Use: PORT Id Destination");
 
+#ifdef FILTERTEST
+	if (id != siLive && id != siLiveFilter)
+		return Respond(501, "Wrong connection id %d", id);
+#else
 	if (id != 0)
 		return Respond(501, "Wrong connection id %d", id);
+#endif
 	
 	Opts = skipspace(ep);
 	n = 0;
@@ -636,6 +656,23 @@
 
 	isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
 
+#ifdef FILTERTEST
+	if (id == siLiveFilter) {
+		delete m_FilterSocket;
+		m_FilterSocket = new cTBSocket(SOCK_STREAM);
+		if (!m_FilterSocket->Connect(dataip, dataport)) {
+			esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
+				dataip, dataport, strerror(errno));
+			DELETENULL(m_FilterSocket);
+			return Respond(551, "Couldn't open data connection");
+		}
+		m_FilterStreamer->Start(m_FilterSocket);
+		m_FilterStreamer->Activate(true);
+
+		return Respond(220, "Port command ok, data connection opened");
+	}
+#endif
+
 	m_LiveSocket = new cTBSocket(SOCK_STREAM);
 	if (!m_LiveSocket->Connect(dataip, dataport)) {
 		esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
@@ -669,6 +706,11 @@
 	m_LiveStreamer->SetChannel(chan, m_NoTSPIDS ? stTS : stTSPIDS);
 	m_LiveStreamer->SetDevice(dev);
 	
+# ifdef FILTERTEST
+	if(!m_FilterStreamer)
+	        m_FilterStreamer = new cStreamdevFilterStreamer;
+	m_FilterStreamer->SetDevice(dev);
+# endif	
 	return Respond(220, "Channel tuned");
 }
 
@@ -706,8 +748,13 @@
 	int pid, tid, mask;
 	char *ep;
 
+# ifdef FILTERTEST
+	if (m_FilterStreamer == NULL)
+		return Respond(560, "Can't set filters without a filter stream");
+# else
 	if (m_LiveStreamer == NULL)
 		return Respond(560, "Can't set filters without a stream");
+# endif
 	
 	pid = strtol(Opts, &ep, 10);
 	if (ep == Opts || (*ep != ' '))
@@ -721,9 +768,14 @@
 	if (ep == Opts || (*ep != '\0' && *ep != ' '))
 		return Respond(500, "Use: ADDF Pid Tid Mask");
 
+# ifdef FILTERTEST
+	m_FilterStreamer->SetFilter(pid, tid, mask, true);
+	return Respond(220, "Filter %d transferring", pid);
+# else
 	return m_LiveStreamer->SetFilter(pid, tid, mask, true)
 			? Respond(220, "Filter %d transferring", pid)
 			: Respond(560, "Filter %d not available", pid);
+# endif
 #else
 	return Respond(500, "ADDF known but unimplemented with VDR < 1.3.0");
 #endif
@@ -735,8 +787,13 @@
 	int pid, tid, mask;
 	char *ep;
 	
-	if (m_LiveStreamer == NULL)
+# ifdef FILTERTEST
+	if (m_FilterStreamer == NULL)
 		return Respond(560, "Can't delete filters without a stream");
+# else
+	if (m_LiveStreamer == NULL)
+		return Respond(560, "Can't delete filters without a filter stream");
+# endif
 	
 	pid = strtol(Opts, &ep, 10);
 	if (ep == Opts || (*ep != ' '))
@@ -750,9 +807,14 @@
 	if (ep == Opts || (*ep != '\0' && *ep != ' '))
 		return Respond(500, "Use: DELF Pid Tid Mask");
 
+# ifdef FILTERTEST
+	m_FilterStreamer->SetFilter(pid, tid, mask, false);
+	return  Respond(220, "Filter %d stopped", pid);
+# else
 	return m_LiveStreamer->SetFilter(pid, tid, mask, false)
 			? Respond(220, "Filter %d stopped", pid)
 			: Respond(560, "Filter %d not transferring", pid);
+# endif
 #else
 	return Respond(500, "DELF known but unimplemented with VDR < 1.3.0");
 #endif
@@ -768,7 +830,15 @@
 		return Respond(500, "Use: ABRT Id");
 
 	switch (id) {
-	case 0: DELETENULL(m_LiveStreamer); break;
+	case siLive: DELETENULL(m_LiveStreamer); break;
+#ifdef FILTERTEST
+	case siLiveFilter:
+isyslog("cConnectionVTP::CmdABRT(siLiveFilter)");
+	        DELETENULL(m_FilterStreamer);
+		DELETENULL(m_FilterSocket);
+		return Respond(220, "Data connection closed");
+		break;
+#endif	 
 	}
 
 	DELETENULL(m_LiveSocket);
Index: server/connectionVTP.h
===================================================================
RCS file: /var/cvsroot/streamdev/server/connectionVTP.h,v
retrieving revision 1.6
diff -u -r1.6 connectionVTP.h
--- server/connectionVTP.h	2 Apr 2007 10:32:34 -0000	1.6
+++ server/connectionVTP.h	3 Apr 2007 14:34:55 -0000
@@ -5,6 +5,8 @@
 #include "server/livestreamer.h"
 
 class cTBSocket;
+class cStreamdevLiveStreamer;
+class cStreamdevFilterStreamer;
 class cLSTEHandler;
 class cLSTCHandler;
 class cLSTTHandler;
@@ -18,6 +20,8 @@
 private:
 	cTBSocket              *m_LiveSocket;
 	cStreamdevLiveStreamer *m_LiveStreamer;
+	cTBSocket                *m_FilterSocket;
+	cStreamdevFilterStreamer *m_FilterStreamer;
 
 	char                   *m_LastCommand;
 	bool                    m_NoTSPIDS;
Index: server/livefilter.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/livefilter.c,v
retrieving revision 1.2
diff -u -r1.2 livefilter.c
--- server/livefilter.c	8 Feb 2005 13:59:16 -0000	1.2
+++ server/livefilter.c	3 Apr 2007 14:34:55 -0000
@@ -3,18 +3,22 @@
  */
 
 #include "server/livefilter.h"
-#include "server/livestreamer.h"
+#include "server/streamer.h"
 #include "common.h"
 
+#ifndef TS_SIZE
+#    define TS_SIZE          188
+#endif
+#ifndef TS_SYNC_BYTE
+#    define TS_SYNC_BYTE     0x47
+#endif
+
 #if VDRVERSNUM >= 10300
 
-cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevLiveStreamer *Streamer) {
+cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) {
 	m_Streamer = Streamer;
 }
 
-cStreamdevLiveFilter::~cStreamdevLiveFilter() {
-}
-
 void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) 
 {
 	uchar buffer[TS_SIZE];
@@ -39,3 +43,10 @@
 }
 
 #endif // VDRVERSNUM >= 10300
+
+// Local Variables:
+// c-basic-offset: 8
+// indent-tabs-mode: t
+// End:
+//
+// vim: et sts=8 sw=8
Index: server/livefilter.h
===================================================================
RCS file: /var/cvsroot/streamdev/server/livefilter.h,v
retrieving revision 1.2
diff -u -r1.2 livefilter.h
--- server/livefilter.h	7 Nov 2005 19:28:41 -0000	1.2
+++ server/livefilter.h	3 Apr 2007 14:34:55 -0000
@@ -11,20 +11,20 @@
 
 #include <vdr/filter.h>
 
-class cStreamdevLiveStreamer;
+class cStreamdevStreamer;
 
 class cStreamdevLiveFilter: public cFilter {
 	friend class cStreamdevLiveStreamer;
+	friend class cStreamdevFilterStreamer;
 
 private:
-	cStreamdevLiveStreamer *m_Streamer;
+	cStreamdevStreamer *m_Streamer;
 
 protected:
 	virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
 
 public:
-	cStreamdevLiveFilter(cStreamdevLiveStreamer *Streamer);
-	virtual ~cStreamdevLiveFilter();
+	cStreamdevLiveFilter(cStreamdevStreamer *Streamer);
 };
 
 #	endif // VDRVERSNUM >= 10300
Index: server/livestreamer.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/livestreamer.c,v
retrieving revision 1.11
diff -u -r1.11 livestreamer.c
--- server/livestreamer.c	15 Jan 2007 12:00:19 -0000	1.11
+++ server/livestreamer.c	3 Apr 2007 14:34:55 -0000
@@ -1,6 +1,12 @@
+#include <assert.h>
+
 #include <vdr/ringbuffer.h>
 
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+
 #include "server/livestreamer.h"
+#include "server/livefilter.h"
 #include "remux/ts2ps.h"
 #include "remux/ts2es.h"
 #include "remux/extern.h"
@@ -8,12 +14,31 @@
 
 // --- cStreamdevLiveReceiver -------------------------------------------------
 
+class cStreamdevLiveReceiver: public cReceiver {
+        friend class cStreamdevStreamer;
+
+private:
+	cStreamdevStreamer *m_Streamer;
+
+protected:
+	virtual void Activate(bool On);
+	virtual void Receive(uchar *Data, int Length);
+
+public:
+#if VDRVERSNUM < 10500
+	cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, int Priority, const int *Pids);
+#else
+	cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
+#endif
+	virtual ~cStreamdevLiveReceiver();
+};
+
 #if VDRVERSNUM < 10500
-cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, int Ca, 
+cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, int Ca, 
                                                int Priority, const int *Pids):
 		cReceiver(Ca, Priority, 0, Pids),
 #else
-cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, tChannelID ChannelID, 
+cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, 
                                                int Priority, const int *Pids):
 		cReceiver(ChannelID, Priority, 0, Pids),
 #endif
@@ -33,6 +58,179 @@
 		m_Streamer->ReportOverflow(Length - p);
 }
 
+inline void cStreamdevLiveReceiver::Activate(bool On) 
+{ 
+	Dprintf("LiveReceiver->Activate(%d)\n", On);
+	m_Streamer->Activate(On); 
+}
+
+// --- cStreamdevPatFilter ----------------------------------------------------
+
+class cStreamdevPatFilter : public cFilter {
+private:
+	int    pmtPid;
+	int    pmtSid;
+	int    pmtVersion;
+
+	const cChannel *m_Channel;
+	cStreamdevLiveStreamer *m_Streamer;
+
+	virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+public:
+	cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel);
+};
+
+cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel)
+{
+	Dprintf("cStreamdevPatFilter(\"%s\")", Channel->Name());
+	assert(Streamer);
+	m_Channel = Channel;
+	m_Streamer = Streamer;
+	pmtPid = 0;
+	pmtSid = 0;
+	pmtVersion = -1;
+	Set(0x00, 0x00);  // PAT
+}
+
+static const char * const psStreamTypes[] = {
+	"0", 
+	"ISO/IEC 11172 Video", 
+	"ISO/IEC 13818-2 Video", 
+	"ISO/IEC 11172 Audio", 
+	"ISO/IEC 13818-3 Audio",
+	"ISO/IEC 13818-1 Privete sections", 
+	"ISO/IEC 13818-1 Private PES data",
+	"ISO/IEC 13512 MHEG", 
+	"ISO/IEC 13818-1 Annex A DSM CC",
+	"0x09",
+	"ISO/IEC 13818-6 Multiprotocol encapsulation",
+	"ISO/IEC 13818-6 DSM-CC U-N Messages",
+	"ISO/IEC 13818-6 Stream Descriptors",
+	"ISO/IEC 13818-6 Sections (any type, including private data)",
+	"ISO/IEC 13818-1 auxiliary",
+	"ISO/IEC 13818-7 Audio with ADTS transport sytax",
+	"ISO/IEC 14496-2 Visual (MPEG-4)",
+	"ISO/IEC 14496-3 Audio with LATM transport syntax",
+	"0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a",
+	"ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)",
+	"",
+};
+
+void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+	if (Pid == 0x00) {
+		if (Tid == 0x00 && !pmtPid) {
+			SI::PAT pat(Data, false);
+			if (!pat.CheckCRCAndParse())
+				return;
+			SI::PAT::Association assoc;
+			for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
+				if (!assoc.isNITPid()) {
+					const cChannel *Channel =  Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
+					if (Channel && (Channel == m_Channel)) {
+						if (0 != (pmtPid = assoc.getPid())) {
+							Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d", Channel->Name(), pmtPid);
+							pmtSid = assoc.getServiceId();
+							if (Length < TS_SIZE-5) {
+								// repack PAT to TS frame and send to client
+								uint8_t pat_ts[TS_SIZE] = {TS_SYNC_BYTE, 0x40 /* pusi=1 */, 0 /* pid=0 */, 0x10 /* adaption=1 */, 0 /* pointer */};
+								memcpy(pat_ts + 5, Data, Length);
+								m_Streamer->Put(pat_ts, TS_SIZE);
+							} else 
+								isyslog("cStreamdevPatFilter: PAT size %d too large to fit in one TS", Length);
+							m_Streamer->SetPid(pmtPid, true);
+							Add(pmtPid, 0x02);
+							pmtVersion = -1;
+							return;
+						}
+					}
+				}
+			}
+		}
+	} else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) {
+		SI::PMT pmt(Data, false);
+		if (!pmt.CheckCRCAndParse())
+			return;
+		if (pmt.getServiceId() != pmtSid)
+			return; // skip broken PMT records
+		if (pmtVersion != -1) {
+			if (pmtVersion != pmt.getVersionNumber()) {
+				Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids");
+				m_Streamer->ClearPids();
+				Del(pmtPid, 0x02);
+				pmtPid = 0; // this triggers PAT scan
+			}
+			return;
+		}
+		pmtVersion = pmt.getVersionNumber();
+		SI::PMT::Stream stream;
+		int Ppid = pmt.getPCRPid();
+		if (Ppid && !m_Streamer->HasPid(Ppid)) {
+			Dprintf("cStreamdevPatFilter PMT scanner: adding PCR PID %d", Ppid);
+			m_Streamer->SetPid(Ppid, true);
+		}
+		for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
+			if (stream.getPid() && !m_Streamer->HasPid(stream.getPid())) {
+				switch (stream.getStreamType()) {
+				case 0x01: // ISO/IEC 11172 Video
+				case 0x02: // ISO/IEC 13818-2 Video
+				case 0x03: // ISO/IEC 11172 Audio
+				case 0x04: // ISO/IEC 13818-3 Audio
+#if 0
+				case 0x07: // ISO/IEC 13512 MHEG 
+				case 0x08: // ISO/IEC 13818-1 Annex A  DSM CC
+				case 0x0a: // ISO/IEC 13818-6 Multiprotocol encapsulation
+				case 0x0b: // ISO/IEC 13818-6 DSM-CC U-N Messages
+				case 0x0c: // ISO/IEC 13818-6 Stream Descriptors
+				case 0x0d: // ISO/IEC 13818-6 Sections (any type, including private data)
+				case 0x0e: // ISO/IEC 13818-1 auxiliary
+#endif
+				case 0x0f: // ISO/IEC 13818-7 Audio with ADTS transport syntax
+				case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
+				case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
+				case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
+					Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)",
+						stream.getPid(), psStreamTypes[stream.getStreamType()]);
+					m_Streamer->SetPid(stream.getPid(), true);
+					break;
+				case 0x05: // ISO/IEC 13818-1 private sections
+				case 0x06: // ISO/IEC 13818-1 PES packets containing private data
+					SI::Descriptor *d;
+					for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+						switch (d->getDescriptorTag()) {
+						case SI::AC3DescriptorTag:
+							Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+								stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
+							m_Streamer->SetPid(stream.getPid(), true);
+							break;
+						case SI::TeletextDescriptorTag:
+							Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+								stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
+							m_Streamer->SetPid(stream.getPid(), true);
+							break;
+						case SI::SubtitlingDescriptorTag:
+							Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+								stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
+							m_Streamer->SetPid(stream.getPid(), true);
+							break;
+						default:
+							Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s", 
+								stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
+							break;
+						}
+						delete d;
+					}
+					break;
+				default:
+					Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s",
+						stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
+					break;
+				}
+			}
+		}
+	}
+}
+
 // --- cStreamdevLiveStreamer -------------------------------------------------
 
 cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority):
@@ -43,6 +241,7 @@
 		m_Channel(NULL),
 		m_Device(NULL),
 		m_Receiver(NULL),
+		m_PatFilter(NULL),
 		m_PESRemux(NULL),
 		m_ESRemux(NULL),
 		m_PSRemux(NULL),
@@ -54,14 +253,30 @@
 {
 	Dprintf("Desctructing Live streamer\n");
 	Stop();
-	delete m_Receiver;
+	if(m_PatFilter) {
+		Detach();
+		DELETENULL(m_PatFilter);
+	}
+	DELETENULL(m_Receiver);
 	delete m_PESRemux;
 	delete m_ESRemux;
 	delete m_PSRemux;
 	delete m_ExtRemux;
-#if VDRVERSNUM >= 10300
-	//delete m_Filter; TODO
-#endif
+}
+
+bool cStreamdevLiveStreamer::HasPid(int Pid) 
+{
+	int idx;
+	for (idx = 0; idx < m_NumPids; ++idx)
+		if (m_Pids[idx] == Pid)
+			return true;
+	return false;
+}
+
+void cStreamdevLiveStreamer::ClearPids(void)
+{
+	m_NumPids = 0;
+	// do not detach yet, instead wait for next PMT update
 }
 
 bool cStreamdevLiveStreamer::SetPid(int Pid, bool On) 
@@ -126,7 +341,6 @@
 		}
 
 	case stPES: 
-		Dprintf("PES\n");
 		m_PESRemux = new cRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(), 
 								m_Channel->Spids(), false);
 		if (Apid != 0)
@@ -149,13 +363,15 @@
 			    && SetPid(m_Channel->Dpid(0), true);
 
 	case stTS:
-		if (Apid != 0)
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(Apid, true);
-		else
-			return SetPid(m_Channel->Vpid(),  true)
-			    && SetPid(m_Channel->Apid(0), true)
-			    && SetPid(m_Channel->Dpid(0), true);
+		// This should never happen, but ...
+		if (m_PatFilter) {
+			Detach();
+			DELETENULL(m_PatFilter);
+			ClearPids();
+		}
+		// Set pids from PMT
+		m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
+		return true;
 
 	case stExtern:
 		m_ExtRemux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
@@ -270,14 +486,28 @@
 	
 void cStreamdevLiveStreamer::Attach(void) 
 { 
-	printf("RIGHT ATTACH\n");
-	m_Device->AttachReceiver(m_Receiver); 
+	Dprintf("RIGHT ATTACH\n");
+	if (m_Device) {
+		if (m_Receiver) {
+			m_Device->Detach(m_Receiver); 
+	        	m_Device->AttachReceiver(m_Receiver); 
+		}
+		if (m_PatFilter) {
+			m_Device->Detach(m_PatFilter); 
+			m_Device->AttachFilter(m_PatFilter); 
+		}
+	}
 }
 
 void cStreamdevLiveStreamer::Detach(void) 
 { 
-	printf("RIGHT DETACH\n");
-	m_Device->Detach(m_Receiver); 
+	Dprintf("RIGHT DETACH\n");
+	if (m_Device) {
+		if (m_Receiver)
+			m_Device->Detach(m_Receiver); 
+		if (m_PatFilter)
+			m_Device->Detach(m_PatFilter); 
+	}
 }
 
 std::string cStreamdevLiveStreamer::Report(void) 
@@ -296,3 +526,93 @@
 	result += "\n";
 	return result;
 }
+
+// --- cStreamdevFilterStreamer -------------------------------------------------
+
+cStreamdevFilterStreamer::cStreamdevFilterStreamer():
+		cStreamdevStreamer("streamdev-filterstreaming"),
+		m_Device(NULL),
+		m_Filter(NULL),
+		m_Channel(NULL)
+{
+}
+
+cStreamdevFilterStreamer::~cStreamdevFilterStreamer() 
+{
+	Dprintf("Desctructing Filter streamer\n");
+	Detach();
+	m_Device = NULL;
+	DELETENULL(m_Filter);
+	Stop();
+}
+
+void cStreamdevFilterStreamer::Attach(void) 
+{ 
+	Dprintf("RIGHT ATTACH\n");
+	LOCK_THREAD;
+	if(m_Device && m_Filter)
+		m_Device->AttachFilter(m_Filter);
+}
+
+void cStreamdevFilterStreamer::Detach(void) 
+{ 
+	Dprintf("RIGHT DETACH\n");
+	LOCK_THREAD;
+	if(m_Device && m_Filter)
+		m_Device->Detach(m_Filter); 
+}
+
+void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
+{
+	LOCK_THREAD;
+	if(Device != m_Device) {
+		Detach();
+		m_Device = Device; 
+		Attach();
+	}
+}
+
+void cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On) 
+{
+	Dprintf("setting filter\n");
+	if (On) {
+		if (m_Filter == NULL) {
+			m_Filter = new cStreamdevLiveFilter(this);
+			Dprintf("attaching filter to device\n");
+			Attach();
+		}
+		m_Filter->Set(Pid, Tid, Mask);
+	} else if (m_Filter != NULL) 
+		m_Filter->Del(Pid, Tid, Mask);
+}
+
+void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
+
+	// TODO:
+	// Need to signal channel changes to streamdev-client 
+	// unless change request is from streamdev-client
+	// (section data will come from another transponder 
+	//  after transponder change)
+
+	LOCK_THREAD;
+	if(m_Filter != NULL &&
+	   Device == m_Device && 
+	   ChannelNumber > 0 &&
+	   m_Channel &&
+	   ! TRANSPONDER(Channels.GetByNumber(ChannelNumber), m_Channel)) {
+
+isyslog("***** LiveFilterStreamer: transponder changed !");
+
+		//SetDevice(NULL);
+		Detach();
+	}
+	m_Channel = Channels.GetByNumber(ChannelNumber);
+}
+
+// Local Variables:
+// c-basic-offset: 8
+//
+// indent-tabs-mode: t
+// End:
+//
+// vim: et sts=8 sw=8
Index: server/livestreamer.h
===================================================================
RCS file: /var/cvsroot/streamdev/server/livestreamer.h,v
retrieving revision 1.10
diff -u -r1.10 livestreamer.h
--- server/livestreamer.h	15 Jan 2007 12:00:19 -0000	1.10
+++ server/livestreamer.h	3 Apr 2007 14:34:55 -0000
@@ -5,34 +5,14 @@
 #include <vdr/receiver.h>
 
 #include "server/streamer.h"
-#include "server/livefilter.h"
 #include "common.h"
 
 class cTS2PSRemux;
 class cTS2ESRemux;
 class cExternRemux;
 class cRemux;
-
-// --- cStreamdevLiveReceiver -------------------------------------------------
-
-class cStreamdevLiveReceiver: public cReceiver {
-	friend class cStreamdevLiveStreamer;
-
-private:
-	cStreamdevLiveStreamer *m_Streamer;
-
-protected:
-	virtual void Activate(bool On);
-	virtual void Receive(uchar *Data, int Length);
-
-public:
-#if VDRVERSNUM < 10500
-	cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, int Ca, int Priority, const int *Pids);
-#else
-	cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
-#endif
-	virtual ~cStreamdevLiveReceiver();
-};
+class cStreamdevPatFilter;
+class cStreamdevLiveReceiver;
 
 // --- cStreamdevLiveStreamer -------------------------------------------------
 
@@ -45,6 +25,7 @@
 	const cChannel         *m_Channel;
 	cDevice                *m_Device;
 	cStreamdevLiveReceiver *m_Receiver;
+	cStreamdevPatFilter    *m_PatFilter;
 	cRemux                 *m_PESRemux;
 	cTS2ESRemux            *m_ESRemux;
 	cTS2PSRemux            *m_PSRemux;
@@ -66,16 +47,44 @@
 	virtual void Attach(void);
 	virtual void Detach(void);
 
+	bool HasPid(int Pid);
+	void ClearPids(void); 
+
 	// Statistical purposes:
 	virtual std::string Report(void);
 };
 
-// --- cStreamdevLiveReceiver reverse inlines ---------------------------------
+// --- cStreamdevFilterStreamer -------------------------------------------------
 
-inline void cStreamdevLiveReceiver::Activate(bool On) 
-{ 
-	Dprintf("LiveReceiver->Activate(%d)\n", On);
-	m_Streamer->Activate(On); 
-}
+#include <vdr/status.h>
+
+class cStreamdevLiveFilter;
+
+class cStreamdevFilterStreamer: public cStreamdevStreamer, public cStatus {
+private:
+	cDevice                *m_Device;
+	cStreamdevLiveFilter   *m_Filter;
+	const cChannel         *m_Channel;
+
+public:
+	cStreamdevFilterStreamer();
+	virtual ~cStreamdevFilterStreamer();
+
+	void SetDevice(cDevice *Device);
+	void SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
+	
+	virtual void Attach(void);
+	virtual void Detach(void);
+
+	// cStatus message handlers
+	virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+};
 
 #endif // VDR_STREAMDEV_LIVESTREAMER_H
+
+// Local Variables:
+// c-basic-offset: 8
+// indent-tabs-mode: nil
+// End:
+//
+// vim: et sts=8 sw=8
