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	23 Apr 2007 19:35:09 -0000
@@ -83,6 +83,7 @@
 enum eSocketId {
 	siLive,
 	siReplay,
+	siLiveFilter,
 	si_Count
 };
 
Index: client/device.c
===================================================================
RCS file: /var/cvsroot/streamdev/client/device.c,v
retrieving revision 1.9
diff -u -r1.9 device.c
--- client/device.c	23 Apr 2007 11:42:16 -0000	1.9
+++ client/device.c	23 Apr 2007 19:35:10 -0000
@@ -42,6 +42,9 @@
 #endif
 
 	m_Device = this;
+	m_Pids = 0;
+	m_DvrClosed = true;
+	m_TSFails = 0;
 
 	if (StreamdevClientSetup.SyncEPG)	
 		ClientSocket.SynchronizeEPG();
@@ -132,37 +135,113 @@
 bool cStreamdevDevice::SetPid(cPidHandle *Handle, int Type, bool On) {
 	Dprintf("SetPid, Pid=%d, Type=%d, On=%d, used=%d\n", Handle->pid, Type, On,
 			Handle->used);
-	if (Handle->pid && (On || !Handle->used))
-		return ClientSocket.SetPid(Handle->pid, On);
-	return true;
+	LOCK_THREAD;
+
+	if (On && !m_TSBuffer) {
+		Dprintf("SetPid: no data connection -> OpenDvr()");
+		OpenDvrInt();
+	}
+
+        bool res = true; 
+	if (Handle->pid && (On || !Handle->used)) {
+		res = ClientSocket.SetPid(Handle->pid, On);
+
+		m_Pids += (!res) ? 0 : On ? 1 : -1;
+		if (m_Pids < 0) 
+			m_Pids = 0;
+
+		if(m_Pids < 1 && m_DvrClosed) { 
+			Dprintf("SetPid: 0 pids left -> CloseDvr()"); 
+			CloseDvrInt(); 
+		}
+	}
+
+	return res;
 }
 
-bool cStreamdevDevice::OpenDvr(void) {
-	Dprintf("OpenDvr\n");
-	CloseDvr();
+bool cStreamdevDevice::OpenDvrInt(void) {
+	Dprintf("OpenDvrInt\n");
+	LOCK_THREAD;
+
+	CloseDvrInt();
+	if (m_TSBuffer) {
+		Dprintf("cStreamdevDevice::OpenDvrInt(): DVR connection already open\n");
+		return true;
+	}
+
+	Dprintf("cStreamdevDevice::OpenDvrInt(): Connecting ...\n");
 	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;
 	}
+	esyslog("cStreamdevDevice::OpenDvrInt(): DVR connection FAILED");
 	return false;
 }
 
-void cStreamdevDevice::CloseDvr(void) {
-	Dprintf("CloseDvr\n");
+bool cStreamdevDevice::OpenDvr(void) {
+	Dprintf("OpenDvr\n");
+	LOCK_THREAD;
 
-	//DELETENULL(m_Assembler);
+	m_DvrClosed = false;
+	return OpenDvrInt();
+}
+
+void cStreamdevDevice::CloseDvrInt(void) {
+	Dprintf("CloseDvrInt\n");
+	LOCK_THREAD;
+
+	if (ClientSocket.CheckConnection()) {
+		if (!m_DvrClosed) {
+			Dprintf("cStreamdevDevice::CloseDvrInt(): m_DvrClosed=false -> not closing yet\n");
+			return;
+		}
+		if (m_Pids > 0) {
+			Dprintf("cStreamdevDevice::CloseDvrInt(): %d active pids -> not closing yet\n", m_Pids);
+			return;
+		}
+	} else {
+		Dprintf("cStreamdevDevice::CloseDvrInt(): Control connection gone !\n");
+	}
+
+	Dprintf("cStreamdevDevice::CloseDvrInt(): Closing DVR connection\n");
 	DELETENULL(m_TSBuffer);
 	ClientSocket.CloseDvr();
 }
 
+void cStreamdevDevice::CloseDvr(void) {
+	Dprintf("CloseDvr\n");
+	LOCK_THREAD;
+
+	m_DvrClosed = true;
+	CloseDvrInt();
+}
+
 bool cStreamdevDevice::GetTSPacket(uchar *&Data) {
 	if (m_TSBuffer) {
 		Data = m_TSBuffer->Get();
+#if 1 // TODO: this should be fixed in vdr cTSBuffer
+		// simple disconnect detection
+		if (!Data) {
+			cPoller Poller(*ClientSocket.DataSocket(siLive));
+			errno = 0;
+			if (Poller.Poll() && !errno) {
+				char tmp[1];
+				if (recv(*ClientSocket.DataSocket(siLive), tmp, 1, MSG_PEEK) == 0 && !errno) {
+esyslog("cStreamDevice::GetTSPacket: GetChecked: NOTHING (%d)", m_TSFails);
+                                        m_TSFails++; 
+					if (m_TSFails > 10) {
+						isyslog("cStreamdevDevice::GetTSPacket(): disconnected");
+						m_Pids = 0;
+						CloseDvrInt();
+						m_TSFails = 0;
+						return false;
+					}
+					return true;
+				}
+			}
+			m_TSFails = 0;
+		}
+#endif
 		return true;
 	}
 	return false;
@@ -171,11 +250,24 @@
 #if VDRVERSNUM >= 10300
 int cStreamdevDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) {
 	Dprintf("OpenFilter\n");
-	if (StreamdevClientSetup.StreamFilters 
-			&& ClientSocket.SetFilter(Pid, Tid, Mask, true)) {
-		return m_Filters->OpenFilter(Pid, Tid, Mask);
-	} else
+
+	if (!StreamdevClientSetup.StreamFilters)
 		return -1;
+
+
+	if (!ClientSocket.DataSocket(siLiveFilter)) {
+		if (ClientSocket.CreateDataConnection(siLiveFilter)) {
+			m_Filters->SetConnection(*ClientSocket.DataSocket(siLiveFilter));
+		} else {
+			isyslog("cStreamdevDevice::OpenFilter: connect failed: %m");
+			return -1;
+		}
+	}
+
+	if (ClientSocket.SetFilter(Pid, Tid, Mask, true))
+		return m_Filters->OpenFilter(Pid, Tid, Mask);
+
+	return -1;
 }
 #endif
 
Index: client/device.h
===================================================================
RCS file: /var/cvsroot/streamdev/client/device.h,v
retrieving revision 1.4
diff -u -r1.4 device.h
--- client/device.h	23 Apr 2007 11:42:16 -0000	1.4
+++ client/device.h	23 Apr 2007 19:35:10 -0000
@@ -25,9 +25,15 @@
 #if VDRVERSNUM >= 10307
 	cStreamdevFilters   *m_Filters;
 #endif
+	int                  m_Pids;
+	bool                 m_DvrClosed;
+	int                  m_TSFails;
 
 	static cStreamdevDevice *m_Device;
 
+	bool OpenDvrInt(void);
+	void CloseDvrInt(void);
+
 protected:
 	virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
 	virtual bool HasLock(int TimeoutMs) 
Index: client/filter.c
===================================================================
RCS file: /var/cvsroot/streamdev/client/filter.c,v
retrieving revision 1.10
diff -u -r1.10 filter.c
--- client/filter.c	23 Apr 2007 12:52:28 -0000	1.10
+++ client/filter.c	23 Apr 2007 19:35:10 -0000
@@ -27,7 +27,7 @@
 	virtual ~cStreamdevFilter();
 
 	bool Matches(u_short Pid, u_char Tid);
-	bool PutSection(const uchar *Data, int Length);
+	bool PutSection(const uchar *Data, int Length, bool pusi);
 	int  ReadPipe(void) const { return m_Pipe[0]; }
 
 	bool IsClosed(void);
@@ -75,7 +75,13 @@
 		close(m_Pipe[1]);
 }
 
-bool cStreamdevFilter::PutSection(const uchar *Data, int Length) {
+bool cStreamdevFilter::PutSection(const uchar *Data, int Length, bool pusi) {
+
+	if (!m_Used && !pusi) /* wait for payload unit start indicator */
+		return true;
+	if (m_Used && pusi)   /* reset at payload unit start */
+		Reset();
+
 	if (m_Used + Length >= (int)sizeof(m_Buffer)) {
 		esyslog("ERROR: Streamdev: Section handler buffer overflow (%d bytes lost)",
 				Length);
@@ -141,17 +147,11 @@
 
 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) {
@@ -194,46 +194,101 @@
 	}
 }
 
-cStreamdevFilter *cStreamdevFilters::Matches(u_short Pid, u_char Tid) {
-	for (cStreamdevFilter *f = First(); f; f = Next(f)) {
-		if (f->Matches(Pid, Tid))
-			return f;
-	}
-	return NULL;
+bool cStreamdevFilters::ReActivateFilters(void)
+{
+	LOCK_THREAD;
+
+	bool res = true;
+	CarbageCollect();
+	for (cStreamdevFilter *fi = First(); fi; fi = Next(fi)) {
+		res = ClientSocket.SetFilter(fi->Pid(), fi->Tid(), fi->Mask(), true) && res;
+		Dprintf("ReActivateFilters(%d, %d, %d) -> %s", fi->Pid(), fi->Tid(), fi->Mask(), res ? "Ok" :"FAIL");
+	}
+	return res;
 }
 
-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) {
+
+	Cancel(2);
+	DELETENULL(m_TSBuffer);
+
+	if (Handle >= 0) {
+		m_TSBuffer = new cTSBuffer(Handle, MEGABYTE(1), 1);
+		ReActivateFilters();
+		Start();
+	}
 }
 
 void cStreamdevFilters::Action(void) {
-	m_Active = true;
-	while (m_Active) {
-		int recvd;
-		const uchar *block = m_RingBuffer->Get(recvd);
+	int fails = 0;
 
-		if (block && recvd > 0) {
-			cStreamdevFilter *f;
+	while (Running()) {
+		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) {
+			bool pusi = block[1] & 0x40;
+			int len = block[4];
+#if 0
+			if (block[1] == 0xff &&
+			    block[2] == 0xff &&
+			    block[3] == 0xff &&
+			    block[4] == 0x7f)
+				isyslog("*********** TRANSPONDER -> %s **********", block+5);
+#endif
+			LOCK_THREAD;
+			cStreamdevFilter *f = First();
+			while (f) {
+				cStreamdevFilter *next = Next(f);
+				if (f->Matches(pid, tid)) {
+
+					if (f->PutSection(block + 5, len, pusi))
+						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;
+			}
+		} else {
+#if 1 // TODO: this should be fixed in vdr cTSBuffer
+			// Check disconnection
+			int fd = *ClientSocket.DataSocket(siLiveFilter);
+			if(fd < 0)
+				break;
+			cPoller Poller(fd);
+			if (Poller.Poll()) {
+				char tmp[1];
+				errno = 0;
+				Dprintf("cStreamdevFilters::Action(): checking connection");
+				if (recv(fd, tmp, 1, MSG_PEEK) == 0 && errno != EAGAIN) {
+					++fails;
+					if (fails >= 10) {
+						esyslog("cStreamdevFilters::Action(): stream disconnected ?");
+						ClientSocket.CloseDataConnection(siLiveFilter);
+						break;
+					}
+				} else {
+					fails = 0;
 				}
+			} else {
+				fails = 0;
 			}
-			m_RingBuffer->Del(TS_SIZE);
-		} else
-			usleep(1);
+			cCondWait::SleepMs(10);
+#endif
+		}
 	}
+
+	DELETENULL(m_TSBuffer);
+	dsyslog("StreamdevFilters::Action() ended");
 }
 
 #endif // VDRVERSNUM >= 10300
Index: client/filter.h
===================================================================
RCS file: /var/cvsroot/streamdev/client/filter.h,v
retrieving revision 1.3
diff -u -r1.3 filter.h
--- client/filter.h	23 Apr 2007 12:52:28 -0000	1.3
+++ client/filter.h	23 Apr 2007 19:35:10 -0000
@@ -12,26 +12,25 @@
 #include <vdr/tools.h>
 #include <vdr/thread.h>
 
-class cRingBufferLinear;
 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);
 
+	bool ReActivateFilters(void);
+
 public:
 	cStreamdevFilters(void);
 	virtual ~cStreamdevFilters();
 
+	void SetConnection(int Handle);
 	int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
-	cStreamdevFilter *Matches(u_short Pid, u_char Tid);
-	void Put(const uchar *Data);
 };
 
 #	endif // VDRVERSNUM >= 10300
Index: client/socket.c
===================================================================
RCS file: /var/cvsroot/streamdev/client/socket.c,v
retrieving revision 1.7
diff -u -r1.7 socket.c
--- client/socket.c	15 Jan 2007 11:45:48 -0000	1.7
+++ client/socket.c	23 Apr 2007 19:35:10 -0000
@@ -215,6 +215,24 @@
 	return true;
 }
 
+bool cClientSocket::CloseDataConnection(eSocketId Id) {
+	//if (!CheckConnection()) return false;
+
+	CMD_LOCK;
+
+	if(Id == siLive || Id == siLiveFilter)
+		if (m_DataSockets[Id] != NULL) {
+			std::string command = (std::string)"ABRT " + (const char*)itoa(Id);
+			if (!Command(command, 220)) {
+				if (errno == 0)
+					esyslog("ERROR: Streamdev: Couldn't cleanly close data connection");
+				//return false;
+			}		
+			DELETENULL(m_DataSockets[Id]);
+		}
+	return true;
+}
+
 bool cClientSocket::SetChannelDevice(const cChannel *Channel) {
 	if (!CheckConnection()) return false;
 
Index: client/socket.h
===================================================================
RCS file: /var/cvsroot/streamdev/client/socket.h,v
retrieving revision 1.3
diff -u -r1.3 socket.h
--- client/socket.h	8 Feb 2005 17:22:35 -0000	1.3
+++ client/socket.h	23 Apr 2007 19:35:10 -0000
@@ -47,6 +47,7 @@
 	bool CheckConnection(void);
 	bool ProvidesChannel(const cChannel *Channel, int Priority);
 	bool CreateDataConnection(eSocketId Id);
+	bool CloseDataConnection(eSocketId Id);
 	bool SetChannelDevice(const cChannel *Channel);
 	bool SetPid(int Pid, bool On);
 #if VDRVERSNUM >= 10300
Index: server/connectionVTP.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/connectionVTP.c,v
retrieving revision 1.9
diff -u -r1.9 connectionVTP.c
--- server/connectionVTP.c	16 Apr 2007 11:01:02 -0000	1.9
+++ server/connectionVTP.c	23 Apr 2007 19:35:11 -0000
@@ -466,6 +466,8 @@
 		cServerConnection("VTP"),
 		m_LiveSocket(NULL),
 		m_LiveStreamer(NULL),
+		m_FilterSocket(NULL),
+		m_FilterStreamer(NULL),
 		m_LastCommand(NULL),
 		m_NoTSPIDS(false),
 		m_LSTEHandler(NULL),
@@ -480,11 +482,18 @@
 		free(m_LastCommand);
 	delete m_LiveStreamer;
 	delete m_LiveSocket;
+	delete m_FilterStreamer;
+	delete m_FilterSocket;
 	delete m_LSTTHandler;
 	delete m_LSTCHandler;
 	delete m_LSTEHandler;
 }
 
+inline bool cConnectionVTP::Abort(void) const
+{
+	return m_LiveStreamer && m_LiveStreamer->Abort();
+}
+
 void cConnectionVTP::Welcome(void) 
 {
 	Respond(220, "Welcome to Video Disk Recorder (VTP)");
@@ -498,12 +507,14 @@
 
 void cConnectionVTP::Detach(void) 
 {
-	if (m_LiveStreamer != NULL) m_LiveStreamer->Detach();
+	if (m_LiveStreamer) m_LiveStreamer->Detach();
+	if (m_FilterStreamer) m_FilterStreamer->Detach();
 }
 
 void cConnectionVTP::Attach(void) 
 {
-	if (m_LiveStreamer != NULL) m_LiveStreamer->Attach();
+	if (m_LiveStreamer) m_LiveStreamer->Attach();
+	if (m_FilterStreamer) m_FilterStreamer->Attach();
 }
 
 bool cConnectionVTP::Command(char *Cmd) 
@@ -547,8 +558,8 @@
 	else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param);
 	else if (strcasecmp(Cmd, "DELF") == 0) return CmdDELF(param);
 	else if (strcasecmp(Cmd, "ABRT") == 0) return CmdABRT(param);
-	else if (strcasecmp(Cmd, "QUIT") == 0) return CmdQUIT(param);
-	else if (strcasecmp(Cmd, "SUSP") == 0) return CmdSUSP(param);
+	else if (strcasecmp(Cmd, "QUIT") == 0) return CmdQUIT();
+	else if (strcasecmp(Cmd, "SUSP") == 0) return CmdSUSP();
 	// Commands adopted from SVDRP
 	//else if (strcasecmp(Cmd, "DELR") == 0) return CmdDELR(param);
 	else if (strcasecmp(Cmd, "MODT") == 0) return CmdMODT(param);
@@ -571,6 +582,14 @@
 		return Respond(220, "Capability \"%s\" accepted", Opts);
 	}
 
+#if VDRVERSNUM >= 10300
+	//
+	// 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);
 }
 
@@ -603,9 +622,14 @@
 	id = strtoul(Opts, &ep, 10);
 	if (ep == Opts || !isspace(*ep))
 		return Respond(500, "Use: PORT Id Destination");
-
-	if (id != 0)
+	
+#if VDRVERSNUM >= 10300
+	if (id != siLive && id != siLiveFilter)
+		return Respond(501, "Wrong connection id %d", id);
+#else
+	if (id != siLive)
 		return Respond(501, "Wrong connection id %d", id);
+#endif
 	
 	Opts = skipspace(ep);
 	n = 0;
@@ -632,6 +656,33 @@
 
 	isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
 
+#if VDRVERSNUM >= 10300
+	if (id == siLiveFilter) {
+		if(m_FilterStreamer)
+			m_FilterStreamer->Stop();
+		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");
+		}
+
+		if(!m_FilterStreamer)
+			m_FilterStreamer = new cStreamdevFilterStreamer;
+		m_FilterStreamer->Start(m_FilterSocket);
+		m_FilterStreamer->Activate(true);
+
+		return Respond(220, "Port command ok, data connection opened");
+	}
+#endif
+
+	if(m_LiveSocket && m_LiveStreamer)
+		m_LiveStreamer->Stop();
+	delete m_LiveSocket;
+
 	m_LiveSocket = new cTBSocket(SOCK_STREAM);
 	if (!m_LiveSocket->Connect(dataip, dataport)) {
 		esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
@@ -640,10 +691,10 @@
 		return Respond(551, "Couldn't open data connection");
 	}
 
-	if (id == siLive)
+	if(m_LiveStreamer)
 		m_LiveStreamer->Start(m_LiveSocket);
 
-  return Respond(220, "Port command ok, data connection opened");
+	return Respond(220, "Port command ok, data connection opened");
 }
 
 bool cConnectionVTP::CmdTUNE(char *Opts) 
@@ -657,6 +708,11 @@
 	if ((dev = GetDevice(chan, 0)) == NULL)
 		return Respond(560, "Channel not available");
 
+#if VDRVERSNUM >= 10300
+	//if(m_FilterStreamer)
+	//	m_FilterStreamer->SetChannel(NULL);
+#endif
+
 	if (!dev->SwitchChannel(chan, false))
 		return Respond(560, "Channel not available");
 
@@ -664,7 +720,16 @@
 	m_LiveStreamer = new cStreamdevLiveStreamer(1);
 	m_LiveStreamer->SetChannel(chan, m_NoTSPIDS ? stTS : stTSPIDS);
 	m_LiveStreamer->SetDevice(dev);
+	if(m_LiveSocket)
+		m_LiveStreamer->Start(m_LiveSocket);
 	
+#if VDRVERSNUM >= 10300
+	if(!m_FilterStreamer)
+		m_FilterStreamer = new cStreamdevFilterStreamer;
+	m_FilterStreamer->SetDevice(dev);
+	//m_FilterStreamer->SetChannel(chan);
+#endif
+
 	return Respond(220, "Channel tuned");
 }
 
@@ -702,8 +767,8 @@
 	int pid, tid, mask;
 	char *ep;
 
-	if (m_LiveStreamer == NULL)
-		return Respond(560, "Can't set filters without a stream");
+	if (m_FilterStreamer == NULL)
+		return Respond(560, "Can't set filters without a filter stream");
 	
 	pid = strtol(Opts, &ep, 10);
 	if (ep == Opts || (*ep != ' '))
@@ -717,9 +782,9 @@
 	if (ep == Opts || (*ep != '\0' && *ep != ' '))
 		return Respond(500, "Use: ADDF Pid Tid Mask");
 
-	return m_LiveStreamer->SetFilter(pid, tid, mask, true)
-			? Respond(220, "Filter %d transferring", pid)
-			: Respond(560, "Filter %d not available", pid);
+	return m_FilterStreamer->SetFilter(pid, tid, mask, true)
+	     ? Respond(220, "Filter %d transferring", pid)
+	     : Respond(560, "Filter %d not available", pid);
 #else
 	return Respond(500, "ADDF known but unimplemented with VDR < 1.3.0");
 #endif
@@ -731,7 +796,7 @@
 	int pid, tid, mask;
 	char *ep;
 	
-	if (m_LiveStreamer == NULL)
+	if (m_FilterStreamer == NULL)
 		return Respond(560, "Can't delete filters without a stream");
 	
 	pid = strtol(Opts, &ep, 10);
@@ -746,9 +811,8 @@
 	if (ep == Opts || (*ep != '\0' && *ep != ' '))
 		return Respond(500, "Use: DELF Pid Tid Mask");
 
-	return m_LiveStreamer->SetFilter(pid, tid, mask, false)
-			? Respond(220, "Filter %d stopped", pid)
-			: Respond(560, "Filter %d not transferring", pid);
+	m_FilterStreamer->SetFilter(pid, tid, mask, false);
+	return  Respond(220, "Filter %d stopped", pid);
 #else
 	return Respond(500, "DELF known but unimplemented with VDR < 1.3.0");
 #endif
@@ -764,20 +828,32 @@
 		return Respond(500, "Use: ABRT Id");
 
 	switch (id) {
-	case 0: DELETENULL(m_LiveStreamer); break;
+	case siLive: 
+		DELETENULL(m_LiveStreamer); 
+		DELETENULL(m_LiveSocket);
+		break;
+#if VDRVERSNUM >= 10300
+	case siLiveFilter:
+	        DELETENULL(m_FilterStreamer);
+		DELETENULL(m_FilterSocket);
+		break;
+#endif
+	default:
+		return Respond(501, "Wrong connection id %d", id);
+		break;
+
 	}
 
-	DELETENULL(m_LiveSocket);
 	return Respond(220, "Data connection closed");
 }
 
-bool cConnectionVTP::CmdQUIT(char *Opts) 
+bool cConnectionVTP::CmdQUIT(void) 
 {
 	DeferClose();
 	return Respond(221, "Video Disk Recorder closing connection");
 }
 
-bool cConnectionVTP::CmdSUSP(char *Opts) 
+bool cConnectionVTP::CmdSUSP(void) 
 {
 	if (StreamdevServerSetup.SuspendMode == smAlways || cSuspendCtl::IsActive())
 		return Respond(220, "Server is suspended");
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	23 Apr 2007 19:35:11 -0000
@@ -2,9 +2,10 @@
 #define VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
 
 #include "server/connection.h"
-#include "server/livestreamer.h"
 
 class cTBSocket;
+class cStreamdevLiveStreamer;
+class cStreamdevFilterStreamer;
 class cLSTEHandler;
 class cLSTCHandler;
 class cLSTTHandler;
@@ -18,6 +19,8 @@
 private:
 	cTBSocket              *m_LiveSocket;
 	cStreamdevLiveStreamer *m_LiveStreamer;
+	cTBSocket                *m_FilterSocket;
+	cStreamdevFilterStreamer *m_FilterStreamer;
 
 	char                   *m_LastCommand;
 	bool                    m_NoTSPIDS;
@@ -53,8 +56,8 @@
 	bool CmdADDF(char *Opts);
 	bool CmdDELF(char *Opts);
 	bool CmdABRT(char *Opts);
-	bool CmdQUIT(char *Opts);
-	bool CmdSUSP(char *Opts);
+	bool CmdQUIT(void);
+	bool CmdSUSP(void);
 
 	// Thread-safe implementations of SVDRP commands
 	bool CmdLSTE(char *Opts);
@@ -73,9 +76,4 @@
 			__attribute__ ((format (printf, 3, 4)));
 };
 
-inline bool cConnectionVTP::Abort(void) const
-{
-	return m_LiveStreamer && m_LiveStreamer->Abort();
-}
-
 #endif // VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
Index: server/livefilter.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/livefilter.c,v
retrieving revision 1.3
diff -u -r1.3 livefilter.c
--- server/livefilter.c	23 Apr 2007 15:44:55 -0000	1.3
+++ server/livefilter.c	23 Apr 2007 19:35:11 -0000
@@ -28,7 +28,7 @@
 	while (length > 0) {
 		int chunk = min(length, TS_SIZE - 5);
 		buffer[0] = TS_SYNC_BYTE;
-		buffer[1] = (Pid >> 8) & 0xff;
+		buffer[1] = ((Pid >> 8) & 0x3f) | (pos==0 ? 0x40 : 0); /* bit 6: payload unit start indicator (PUSI) */
 		buffer[2] = Pid & 0xff;
 		buffer[3] = Tid;
 		buffer[4] = (uchar)chunk;
@@ -43,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.3
diff -u -r1.3 livefilter.h
--- server/livefilter.h	23 Apr 2007 15:44:55 -0000	1.3
+++ server/livefilter.h	23 Apr 2007 19:35:11 -0000
@@ -22,6 +22,13 @@
 
 public:
 	cStreamdevLiveFilter(cStreamdevStreamer *Streamer);
+
+	void Set(u_short Pid, u_char Tid, u_char Mask) {
+		cFilter::Set(Pid, Tid, Mask);
+	}
+	void Del(u_short Pid, u_char Tid, u_char Mask) {
+		cFilter::Del(Pid, Tid, Mask);
+	}
 };
 
 #	endif // VDRVERSNUM >= 10300
Index: server/livestreamer.c
===================================================================
RCS file: /var/cvsroot/streamdev/server/livestreamer.c,v
retrieving revision 1.12
diff -u -r1.12 livestreamer.c
--- server/livestreamer.c	23 Apr 2007 15:44:55 -0000	1.12
+++ server/livestreamer.c	23 Apr 2007 19:35:12 -0000
@@ -1,6 +1,12 @@
+#include <assert.h>
+
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+
 #include <vdr/ringbuffer.h>
 
 #include "server/livestreamer.h"
+#include "server/livefilter.h"
 #include "remux/ts2ps.h"
 #include "remux/ts2es.h"
 #include "remux/extern.h"
@@ -58,6 +64,221 @@
 	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);
+
+	int GetPid(SI::PMT::Stream& stream);
+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[] = {
+	"UNKNOWN", 
+	"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)",
+	"",
+};
+
+int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
+{
+	SI::Descriptor *d;
+
+	if (!stream.getPid()) 
+		return 0;
+
+	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()]);
+		return stream.getPid();
+	case 0x05: // ISO/IEC 13818-1 private sections
+	case 0x06: // ISO/IEC 13818-1 PES packets containing private data
+		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");
+				return stream.getPid();
+			case SI::TeletextDescriptorTag:
+				Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
+				return stream.getPid();
+			case SI::SubtitlingDescriptorTag:
+				Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
+				return stream.getPid();
+			default:
+				Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s", 
+					stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
+				break;
+			}
+			delete d;
+		}
+		break;
+	default:
+		/* This following section handles all the cases where the audio track 
+		 * info is stored in PMT user info with stream id >= 0x80
+		 * we check the registration format identifier to see if it 
+		 * holds "AC-3"
+		 */
+		if (stream.getStreamType() >= 0x80) {
+			bool found = false;
+			for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+				switch (d->getDescriptorTag()) {
+				case SI::RegistrationDescriptorTag:
+					/* unfortunately libsi does not implement RegistrationDescriptor */
+					if (d->getLength() >= 4) {
+						found = true;
+						SI::CharArray rawdata = d->getData();
+						if (/*rawdata[0] == 5 && rawdata[1] >= 4 && */
+						    rawdata[2] == 'A' && rawdata[3] == 'C' &&
+						    rawdata[4] == '-' && rawdata[5] == '3') {
+							isyslog("cStreamdevPatFilter PMT scanner:"
+								"Adding pid %d (type 0x%x) RegDesc len %d (%c%c%c%c)", 
+								stream.getPid(), stream.getStreamType(), 
+								d->getLength(), rawdata[2], rawdata[3], 
+								rawdata[4], rawdata[5]);
+							return stream.getPid();
+						}
+					}
+					break;
+				default: 
+					break;
+				}
+				delete d;
+			}
+			if(!found) {
+				isyslog("Adding pid %d (type 0x%x) RegDesc not found -> assume AC-3", 
+					stream.getPid(), stream.getStreamType());
+				return stream.getPid();
+			}
+		}
+		Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s",
+			stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN");
+		break;
+	}
+	return 0;
+}
+
+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->SetPids(pmtPid);
+							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");
+				Del(pmtPid, 0x02);
+				pmtPid = 0; // this triggers PAT scan
+			}
+			return;
+		}
+		pmtVersion = pmt.getVersionNumber();
+
+		SI::PMT::Stream stream;
+		int pids[MAXRECEIVEPIDS + 1], npids = 0;
+		pids[npids++] = pmtPid;
+#if 0
+		pids[npids++] = 0x10;  // pid 0x10, tid 0x40: NIT 
+		pids[npids++] = 0x11;  // pid 0x11, tid 0x42: SDT 
+		pids[npids++] = 0x12;  // pid 0x12, tid 0x4E...0x6F: EIT 
+		pids[npids++] = 0x14;  // pid 0x14, tid 0x70: TDT 
+#endif
+		for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
+			if (0 != (pids[npids] = GetPid(stream)) && npids < MAXRECEIVEPIDS)
+				npids++;
+
+		pids[npids] = 0;
+		m_Streamer->SetPids(pmt.getPCRPid(), pids);
+	}
+}
 
 // --- cStreamdevLiveStreamer -------------------------------------------------
 
@@ -69,6 +290,7 @@
 		m_Channel(NULL),
 		m_Device(NULL),
 		m_Receiver(NULL),
+		m_PatFilter(NULL),
 		m_PESRemux(NULL),
 		m_ESRemux(NULL),
 		m_PSRemux(NULL),
@@ -80,14 +302,24 @@
 {
 	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;
 }
 
 bool cStreamdevLiveStreamer::SetPid(int Pid, bool On) 
@@ -119,6 +351,44 @@
 		}
 	}
 
+	StartReceiver();
+	return true;
+}
+
+bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2, const int *Pids3)
+{
+	m_NumPids = 0;
+
+	if (Pid)
+		m_Pids[m_NumPids++] = Pid;
+
+	if (Pids1)
+		for ( ; *Pids1 && m_NumPids < MAXRECEIVEPIDS; Pids1++)
+			if (!HasPid(*Pids1))
+				m_Pids[m_NumPids++] = *Pids1;
+
+	if (Pids2)
+		for ( ; *Pids2 && m_NumPids < MAXRECEIVEPIDS; Pids2++)
+			if (!HasPid(*Pids2))
+				m_Pids[m_NumPids++] = *Pids2;
+
+	if (Pids3)
+		for ( ; *Pids3 && m_NumPids < MAXRECEIVEPIDS; Pids3++)
+			if (!HasPid(*Pids3))
+				m_Pids[m_NumPids++] = *Pids3;
+
+	if (m_NumPids >= MAXRECEIVEPIDS) {
+		esyslog("ERROR: Streamdev: No free slot to receive pid %d\n", Pid);
+		return false;
+	}
+
+	m_Pids[m_NumPids] = 0;
+	StartReceiver();
+	return true;
+}
+
+void cStreamdevLiveStreamer::StartReceiver(void)
+{
 	DELETENULL(m_Receiver);
 	if (m_NumPids > 0) {
 		Dprintf("Creating Receiver to respect changed pids\n");
@@ -132,15 +402,19 @@
 			Attach();
 		}
 	}
-	return true;
 }
 
 bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid) 
 {
 	Dprintf("Initializing Remuxer for full channel transfer\n");
-	printf("ca pid: %d\n", Channel->Ca());
+	//printf("ca pid: %d\n", Channel->Ca());
 	m_Channel = Channel;
 	m_StreamType = StreamType;
+
+	int apid[2] = { Apid, 0 };
+	const int *Apids = Apid ? apid : m_Channel->Apids();
+	const int *Dpids = Apid ? NULL : m_Channel->Dpids();
+
 	switch (m_StreamType) {
 	case stES: 
 		{
@@ -148,51 +422,33 @@
 			if (Apid != 0)
 				pid = Apid;
 			m_ESRemux = new cTS2ESRemux(pid);
-			return SetPid(pid, true);
+			return SetPids(pid);
 		}
 
 	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)
-			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);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	case stPS:  
 		m_PSRemux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
 		                            m_Channel->Spids());
-		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);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	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);
+		}
+		// 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(),
 		                              m_Channel->Spids());
-		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);
+		return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
 
 	case stTSPIDS:
 		Dprintf("pid streaming mode\n");
@@ -201,25 +457,6 @@
 	return false;
 }
 
-bool cStreamdevLiveStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On) 
-{
-#if 0
-	Dprintf("setting filter\n");
-	if (On) {
-		if (m_Filter == NULL) {
-			m_Filter = new cStreamdevLiveFilter(this);
-			Dprintf("attaching filter to device\n");
-			m_Device->AttachFilter(m_Filter);
-		}
-		m_Filter->Set(Pid, Tid, Mask);
-	} else if (m_Filter != NULL)
-		m_Filter->Del(Pid, Tid, Mask);
-	return true;
-#else
-	return false;
-#endif
-}
-
 int cStreamdevLiveStreamer::Put(const uchar *Data, int Count) 
 {
 	switch (m_StreamType) {
@@ -296,14 +533,28 @@
 	
 void cStreamdevLiveStreamer::Attach(void) 
 { 
-	printf("RIGHT ATTACH\n");
-	m_Device->AttachReceiver(m_Receiver); 
+	Dprintf("cStreamdevLiveStreamer::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("cStreamdevLiveStreamer::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) 
@@ -322,3 +573,117 @@
 	result += "\n";
 	return result;
 }
+
+// --- cStreamdevFilterStreamer -------------------------------------------------
+
+#if VDRVERSNUM >= 10300
+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("cStreamdevFilterStreamer::Attach()\n");
+	LOCK_THREAD;
+	if(m_Device && m_Filter)
+		m_Device->AttachFilter(m_Filter);
+}
+
+void cStreamdevFilterStreamer::Detach(void) 
+{ 
+	Dprintf("cStreamdevFilterStreamer::Detach()\n");
+	LOCK_THREAD;
+	if(m_Device && m_Filter)
+		m_Device->Detach(m_Filter); 
+}
+
+#if 0
+void cStreamdevFilterStreamer::SetChannel(const cChannel *Channel)
+{
+	LOCK_THREAD;
+	Dprintf("cStreamdevFilterStreamer::SetChannel(%s : %s)", Channel?Channel->Name():"<null>",
+		Channel ? *Channel->GetChannelID().ToString() : "");
+	m_Channel = Channel;
+}
+#endif
+
+void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
+{
+	Dprintf("cStreamdevFilterStreamer::SetDevice()\n");
+	LOCK_THREAD;
+	if(Device != m_Device) {
+		Detach();
+		m_Device = Device;
+		//m_Channel = NULL;
+		Attach();
+	}
+}
+
+bool cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On) 
+{	
+	Dprintf("cStreamdevFilterStreamer::SetFilter(%u,0x%x,0x%x,%s)\n", Pid, Tid, Mask, On?"On":"Off");
+
+	if(!m_Device)
+		return false;
+
+	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);
+
+	return true;
+}
+
+#if 0
+void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
+	LOCK_THREAD;
+	if(Device == m_Device) {
+		if(ChannelNumber > 0) {
+			cChannel *ch = Channels.GetByNumber(ChannelNumber);
+			if(ch != NULL) {
+				if(m_Filter != NULL &&
+				   m_Channel != NULL &&
+				   (! TRANSPONDER(ch, m_Channel))) {
+					
+					isyslog("***** LiveFilterStreamer: transponder changed ! %s",
+						*ch->GetChannelID().ToString());
+
+					uchar buffer[TS_SIZE] = {TS_SYNC_BYTE, 0xff, 0xff, 0xff, 0x7f, 0};
+					strcpy((char*)(buffer + 5), ch->GetChannelID().ToString());
+					int p = Put(buffer, TS_SIZE);
+					if (p != TS_SIZE)
+						ReportOverflow(TS_SIZE - p);
+				}
+				m_Channel = ch;
+			}
+		}
+	}
+}
+#endif
+
+#endif // if VDRVERSNUM >= 10300
+
+// 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.11
diff -u -r1.11 livestreamer.h
--- server/livestreamer.h	23 Apr 2007 15:44:55 -0000	1.11
+++ server/livestreamer.h	23 Apr 2007 19:35:12 -0000
@@ -5,13 +5,13 @@
 #include <vdr/receiver.h>
 
 #include "server/streamer.h"
-#include "server/livefilter.h"
 #include "common.h"
 
 class cTS2PSRemux;
 class cTS2ESRemux;
 class cExternRemux;
 class cRemux;
+class cStreamdevPatFilter;
 class cStreamdevLiveReceiver;
 
 // --- cStreamdevLiveStreamer -------------------------------------------------
@@ -25,19 +25,23 @@
 	const cChannel         *m_Channel;
 	cDevice                *m_Device;
 	cStreamdevLiveReceiver *m_Receiver;
+	cStreamdevPatFilter    *m_PatFilter;
 	cRemux                 *m_PESRemux;
 	cTS2ESRemux            *m_ESRemux;
 	cTS2PSRemux            *m_PSRemux;
 	cExternRemux           *m_ExtRemux;
 
+	void StartReceiver(void);
+	bool HasPid(int Pid);
+
 public:
 	cStreamdevLiveStreamer(int Priority);
 	virtual ~cStreamdevLiveStreamer();
 
 	void SetDevice(cDevice *Device) { m_Device = Device; }
 	bool SetPid(int Pid, bool On);
+	bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
 	bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0);
-	bool SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
 	
 	virtual int Put(const uchar *Data, int Count);
 	virtual uchar *Get(int &Count);
@@ -50,4 +54,43 @@
 	virtual std::string Report(void);
 };
 
+
+// --- cStreamdevFilterStreamer -------------------------------------------------
+
+#  if VDRVERSNUM >= 10300
+
+//#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 SetChannel(const cChannel *Channel);
+	bool 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 // if VDRVERSNUM >= 10300
+
 #endif // VDR_STREAMDEV_LIVESTREAMER_H
+
+// Local Variables:
+// c-basic-offset: 8
+// indent-tabs-mode: nil
+// End:
+//
+// vim: et sts=8 sw=8
