#13795: Initial commit for sflphone-android

includes: libexpat libyaml libdbus-c++ commoncpp ccrtp
          libdbus (from android-4.0.4 sources)

TODO:
- git ignores "/jni/sflphone", sflphone repo should be cloned.
- sflphone-android only needs daemon directory. Ideally it should be possible
to clone it without cloning the whole sflphone project.
into sfl-android (commit 6a0fa7a "#13961: Fix cipher handling" has been used here)
- add pjsip-android project as a git submodule
- sflphone-android needs pjsip android project. Ideally daemon git repository
should not embed pjsip. Instead pjsip should be clone from official repositories.

Considering this, structure should have three distincts git repos:

sflphone-android/.git
sflphone-android/jni/ccrtp-1.8.0-android
sflphone-android/jni/commoncpp2-1.8.1-android
sflphone-android/jni/dbus
sflphone-android/jni/libdbus-c++-0.9.0-android
sflphone-android/jni/libexpat
sflphone-android/jni/libyaml

sflphone-android/jni/sflphone-daemon/.git
sflphone-android/jni/sflphone-daemon/src/audio
sflphone-android/jni/sflphone-daemon/src/config
sflphone-android/jni/sflphone-daemon/src/dbus
sflphone-android/jni/sflphone-daemon/src/history
sflphone-android/jni/sflphone-daemon/src/hooks
sflphone-android/jni/sflphone-daemon/src/iax
sflphone-android/jni/sflphone-daemon/src/sip
sflphone-android/jni/sflphone-daemon/src/video

sflphone-android/jni/pjsip-android/.git

Signed-off-by: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
diff --git a/jni/ccrtp-1.8.0-android/src/ccrtp/rtp.h b/jni/ccrtp-1.8.0-android/src/ccrtp/rtp.h
new file mode 100755
index 0000000..a3e2861
--- /dev/null
+++ b/jni/ccrtp-1.8.0-android/src/ccrtp/rtp.h
@@ -0,0 +1,1167 @@
+// Copyright (C) 1999-2005 Open Source Telecom Corporation.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free software
+// library without restriction.  Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License.  This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+//
+// This exception applies only to the code released under the name GNU
+// ccRTP.  If you copy code from other releases into a copy of GNU
+// ccRTP, as the General Public License permits, the exception does
+// not apply to the code that you add in this way.  To avoid misleading
+// anyone as to the status of such modified files, you must delete
+// this exception notice from them.
+//
+// If you write modifications of your own for GNU ccRTP, it is your choice
+// whether to permit this exception to apply to your modifications.
+// If you do not wish that, delete this exception notice.
+//
+
+/**
+ * @file rtp.h
+ *
+ * @short Generic and audio/video profile specific RTP interface of
+ * ccRTP.
+ *
+ * The classes and types in this header provide general RTP
+ * functionality (following RFC 3550) as well as audio/video RTP
+ * profile specific functionality (following RFC 3551).
+ **/
+
+#ifndef	CCXX_RTP_RTP_H_
+#define CCXX_RTP_RTP_H_
+
+#include <ccrtp/cqueue.h>
+#include <ccrtp/channel.h>
+
+#ifdef	CCXX_NAMESPACES
+namespace ost {
+#endif
+
+/**
+ * @defgroup sessions RTP sessions.
+ * @{
+ **/
+
+/**
+ * @class RTPSessionBase
+ *
+ * Generic RTP protocol stack for exchange of realtime data.  This
+ * stack uses the concept of packet send and receive queues to schedule
+ * and buffer outgoing packets and to arrange or reorder incoming packets
+ * as they arrive.
+ *
+ * This is a template class that allows customization of two aspects:
+ * the underlying network and the control protocol. The RTPDataChannel
+ * and RTCPChannel template parameters specify the socket types to
+ * use. The ServiceQueue template parameter specify which packet queue
+ * is used.
+ *
+ * RTPSessionBase objects do not have any threading policy, thus
+ * allowing to customize this aspect in derived classes (see
+ * SingleThreadRTPSession or RTPSessionPoolBase).
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short RTP protocol stack based on Common C++.
+ **/
+	template <class RTPDataChannel = DualRTPUDPIPv4Channel,
+		  class RTCPChannel = DualRTPUDPIPv4Channel,
+		  class ServiceQueue = AVPQueue>
+	class __EXPORT TRTPSessionBase : public ServiceQueue
+	{
+	public:
+		/**
+		 * Builds a session waiting for packets in a host address.
+		 *
+		 * @param ia Network address this socket is to be bound.
+		 * @param dataPort Transport port the data socket is to be bound.
+		 * @param controlPort Transport port the control socket is to be bound.
+		 * @param membersSize Initial size of the membership table.
+		 * @param app Application this session is associated to.
+		 * */
+		TRTPSessionBase(const InetHostAddress& ia, tpport_t dataPort,
+				tpport_t controlPort, uint32 membersSize,
+				RTPApplication& app) :
+			ServiceQueue(membersSize,app)
+			{ build(ia,dataPort,controlPort); }
+
+		/**
+		 * Builds a session with the specified ssrc identifier for the
+		 * local source.
+		 *
+		 * @param ssrc SSRC identifier for the local source.
+		 * @param ia Network address this socket is to be bound.
+		 * @param dataPort Transport port the data socket is to be bound.
+		 * @param controlPort Transport port the control socket is to be bound.
+		 * @param membersSize Initial size of the membership table.
+		 * @param app Application this session is associated to.
+		 **/
+		TRTPSessionBase(uint32 ssrc,
+				const InetHostAddress& ia,
+				tpport_t dataPort, tpport_t controlPort,
+				uint32 membersSize, RTPApplication& app):
+			ServiceQueue(ssrc,membersSize,app)
+			{ build(ia,dataPort,controlPort); }
+
+		/**
+		 * Builds a session waiting for packets in a multicast address.
+		 * TODO: ssrc constructor for multicast!
+		 *
+		 * @param ia Multicast address this socket is to be bound.
+		 * @param dataPort Transport port the data socket is to be bound.
+		 * @param controlPort Transport port the control socket is to be bound.
+		 * @param membersSize Initial size of the membership table.
+		 * @param app Application this session is associated to.
+		 * @param iface Index (from 0 to n) of network interface to join to
+		 * multicast group.
+		 **/
+		TRTPSessionBase(const InetMcastAddress& ia, tpport_t dataPort,
+				tpport_t controlPort, uint32 membersSize,
+				RTPApplication& app, uint32 iface) :
+			ServiceQueue(membersSize,app)
+			{ build(ia,dataPort,controlPort,iface); }
+
+		/**
+		 * Builds a session waiting for packets in a multicast
+		 * address, with the specified ssrc identifier for the local
+		 * source.
+		 *
+		 * @param ssrc SSRC identifier for the local source.
+		 * @param ia Multicast address this socket is to be bound.
+		 * @param dataPort Transport port the data socket is to be bound.
+		 * @param controlPort Transport port the control socket is to be bound.
+		 * @param membersSize Initial size of the membership table.
+		 * @param app Application this session is associated to.
+		 * @param iface Index (from 0 to n) of network interface to join to
+		 * multicast group.
+		 **/
+		TRTPSessionBase(uint32 ssrc,
+				const InetMcastAddress& ia, tpport_t dataPort,
+				tpport_t controlPort, uint32 membersSize,
+				RTPApplication& app, uint32 iface) :
+			ServiceQueue(ssrc,membersSize,app)
+			{ build(ia,dataPort,controlPort,iface); }
+
+		virtual size_t dispatchBYE(const std::string &str)
+			{
+				return QueueRTCPManager::dispatchBYE(str);
+			}
+
+		/**
+		 * Set the value of the TTL field in the sent packets.
+		 *
+		 * @param ttl Time To Live
+		 * @return error code from the socket operation
+		 */
+		inline Socket::Error
+		setMcastTTL(uint8 ttl)
+			{
+				Socket::Error error = dso->setMulticast(true);
+				if ( error ) return error;
+				error = dso->setTimeToLive(ttl);
+				if ( error ) return error;
+				error = cso->setMulticast(true);
+				if ( error ) return error;
+				return cso->setTimeToLive(ttl);
+			}
+
+		inline virtual
+		~TRTPSessionBase()
+			{
+				endSocket();
+			}
+
+		inline RTPDataChannel *getDSO(void)
+			{return dso;}
+
+	protected:
+		/**
+		 * @param timeout maximum timeout to wait, in microseconds
+		 */
+		inline bool
+		isPendingData(microtimeout_t timeout)
+			{ return dso->isPendingRecv(timeout); }
+
+		InetHostAddress
+		getDataSender(tpport_t *port = NULL) const
+			{ return dso->getSender(port); }
+
+		inline size_t
+		getNextDataPacketSize() const
+			{ return dso->getNextPacketSize(); }
+
+		/**
+		 * Receive data from the data channel/socket.
+		 *
+		 * @param buffer Memory region to read to.
+		 * @param len Maximum number of octets to get.
+		 * @param na Source network address.
+		 * @param tp Source transport port.
+		 * @return Number of octets actually read.
+		 */
+		inline size_t
+		recvData(unsigned char* buffer, size_t len,
+			 InetHostAddress& na, tpport_t& tp)
+			{ na = dso->getSender(tp); return dso->recv(buffer, len); }
+
+		inline void
+		setDataPeer(const InetAddress &host, tpport_t port)
+			{ dso->setPeer(host,port); }
+
+
+		/**
+		 * @param buffer memory region to write from
+		 * @param len number of octets to write
+		 */
+		inline size_t
+		sendData(const unsigned char* const buffer, size_t len)
+			{ return dso->send(buffer, len); }
+
+		inline SOCKET getDataRecvSocket() const
+			{ return dso->getRecvSocket(); }
+
+		/**
+		 * @param timeout maximum timeout to wait, in microseconds
+		 * @return whether there are packets waiting to be picked
+		 */
+		inline bool
+		isPendingControl(microtimeout_t timeout)
+			{ return cso->isPendingRecv(timeout); }
+
+		InetHostAddress
+		getControlSender(tpport_t *port = NULL) const
+			{ return cso->getSender(port); }
+
+		/**
+		 * Receive data from the control channel/socket.
+		 *
+		 * @param buffer Buffer where to get data.
+		 * @param len Maximum number of octets to get.
+		 * @param na Source network address.
+		 * @param tp Source transport port.
+		 * @return Number of octets actually read.
+		 **/
+		inline size_t
+		recvControl(unsigned char *buffer, size_t len,
+			    InetHostAddress& na, tpport_t& tp)
+			{ na = cso->getSender(tp); return cso->recv(buffer,len); }
+
+		inline void
+		setControlPeer(const InetAddress &host, tpport_t port)
+			{ cso->setPeer(host,port); }
+
+		/**
+		 * @return number of octets actually written
+		 * @param buffer
+		 * @param len
+		 */
+		inline size_t
+		sendControl(const unsigned char* const buffer, size_t len)
+			{ return cso->send(buffer,len); }
+
+		inline SOCKET getControlRecvSocket() const
+			{ return cso->getRecvSocket(); }
+
+		/**
+		 * Join a multicast group.
+		 *
+		 * @param ia address of the multicast group
+		 * @return error code from the socket operation
+		 */
+		inline Socket::Error
+		joinGroup(const InetMcastAddress& ia, uint32 iface)
+			{
+				Socket::Error error  = dso->setMulticast(true);
+				if ( error ) return error;
+				error = dso->join(ia,iface);
+				if ( error ) return error;
+				error = cso->setMulticast(true);
+				if ( error ) {
+					dso->drop(ia);
+					return error;
+				}
+				error = cso->join(ia,iface);
+				if ( error ) {
+					dso->drop(ia);
+					return error;
+				}
+				return Socket::errSuccess;
+			}
+
+		/**
+		 * Leave a multicast group.
+		 *
+		 * @param ia address of the multicast group
+		 * @return error code from the socket operation
+		 */
+		inline Socket::Error
+		leaveGroup(const InetMcastAddress& ia)
+			{
+				Socket::Error error = dso->setMulticast(false);
+				if ( error ) return error;
+				error = dso->leaveGroup(ia);
+				if ( error ) return error;
+				error = cso->setMulticast(false);
+				if ( error ) return error;
+				return cso->leaveGroup(ia);
+			}
+
+		inline void
+		endSocket()
+			{
+				if (dso) {
+					dso->endSocket();
+					delete dso;
+				}
+				dso = NULL;
+				if (cso) {
+					cso->endSocket();
+					delete cso;
+				}
+				cso = NULL;
+			}
+
+	private:
+		void
+		build(const InetHostAddress& ia, tpport_t dataPort,
+		      tpport_t controlPort)
+			{
+				if ( 0 == controlPort ) {
+					dataBasePort = even_port(dataPort);
+					controlBasePort = dataBasePort + 1;
+				} else {
+					dataBasePort = dataPort;
+					controlBasePort = controlPort;
+				}
+				dso = new RTPDataChannel(ia,dataBasePort);
+				cso = new RTCPChannel(ia,controlBasePort);
+			}
+
+		void
+		build(const InetMcastAddress& ia, tpport_t dataPort,
+		      tpport_t controlPort, uint32 iface)
+			{
+				if ( 0 == controlPort ) {
+					dataBasePort = even_port(dataPort);
+					controlBasePort = dataBasePort + 1;
+				} else {
+					dataBasePort = dataPort;
+					controlBasePort = controlPort;
+				}
+				dso = new RTPDataChannel(InetHostAddress("0.0.0.0"),dataBasePort);
+				cso = new RTCPChannel(InetHostAddress("0.0.0.0"),controlBasePort);
+				joinGroup(ia,iface);
+			}
+
+		/**
+		 * Ensure a port number is odd. If it is an even number, return
+		 * the next lower (odd) port number.
+		 *
+		 * @param port number to filter
+		 * @return filtered (odd) port number
+		 */
+		inline tpport_t
+		odd_port(tpport_t port)
+			{ return (port & 0x01)? (port) : (port - 1); }
+
+		/**
+		 * Ensure a port number is even. If it is an odd number, return
+		 * the next lower (even) port number.
+		 *
+		 * @param port number to filter
+		 * @return filtered (even) port number
+		 */
+		inline tpport_t
+		even_port(tpport_t port)
+			{ return (port & 0x01)? (port - 1) : (port); }
+
+		tpport_t dataBasePort;
+		tpport_t controlBasePort;
+
+	protected:
+		RTPDataChannel* dso;
+		RTCPChannel* cso;
+		friend class RTPSessionBaseHandler;
+	};
+
+/**
+ * @class SingleThreadRTPSession
+ *
+ * This template class adds the threading aspect to the RTPSessionBase
+ * template in one of the many possible ways. It inherits from a
+ * single execution thread that schedules sending of outgoing packets
+ * and receipt of incoming packets.
+ *
+ * @author Federico Montesino Pouzols <fedemp@altern.org>
+ **/
+	template
+	<class RTPDataChannel = DualRTPUDPIPv4Channel,
+	 class RTCPChannel = DualRTPUDPIPv4Channel,
+	 class ServiceQueue = AVPQueue>
+	class __EXPORT SingleThreadRTPSession :
+		protected Thread,
+		public TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
+	{
+	public:
+		SingleThreadRTPSession(const InetHostAddress& ia,
+				       tpport_t dataPort = DefaultRTPDataPort,
+				       tpport_t controlPort = 0,
+				       int pri = 0,
+				       uint32 memberssize =
+				       MembershipBookkeeping::defaultMembersHashSize,
+				       RTPApplication& app = defaultApplication()
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+			);
+#else
+		):
+		Thread(pri),
+		TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
+		(ia,dataPort,controlPort,memberssize,app)
+		{ }
+#endif
+
+        SingleThreadRTPSession(uint32 ssrc, const InetHostAddress& ia,
+                               tpport_t dataPort = DefaultRTPDataPort,
+                               tpport_t controlPort = 0,
+                               int pri = 0,
+                               uint32 memberssize =
+                               MembershipBookkeeping::defaultMembersHashSize,
+                               RTPApplication& app = defaultApplication()
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+		);
+#else
+	):
+	Thread(pri),
+	TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
+	(ssrc, ia,dataPort,controlPort,memberssize,app)
+{ }
+#endif
+
+SingleThreadRTPSession(const InetMcastAddress& ia,
+		       tpport_t dataPort = DefaultRTPDataPort,
+		       tpport_t controlPort = 0,
+		       int pri = 0,
+		       uint32 memberssize =
+		       MembershipBookkeeping::defaultMembersHashSize,
+		       RTPApplication& app = defaultApplication(),
+		       uint32 iface = 0
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+	       );
+#else
+        ):
+        Thread(pri),
+        TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
+        (ia,dataPort,controlPort,memberssize,app,iface)
+        { }
+#endif
+
+SingleThreadRTPSession(uint32 ssrc, const InetMcastAddress& ia,
+		       tpport_t dataPort = DefaultRTPDataPort,
+		       tpport_t controlPort = 0,
+		       int pri = 0,
+		       uint32 memberssize =
+		       MembershipBookkeeping::defaultMembersHashSize,
+		       RTPApplication& app = defaultApplication(),
+		       uint32 iface = 0
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+                      );
+#else
+                ):
+                Thread(pri),
+                TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
+                (ssrc,ia,dataPort,controlPort,memberssize,app,iface)
+{ }
+#endif
+
+
+~SingleThreadRTPSession()
+{
+    if (isRunning()) {
+        disableStack(); Thread::join();
+    }
+}
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+virtual void startRunning();
+#else
+/**
+ * Activate stack and start service thread.
+ **/
+void
+startRunning()
+{ enableStack(); Thread::start(); }
+#endif
+
+
+protected:
+inline void disableStack(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
+
+inline void enableStack(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
+
+inline microtimeout_t getSchedulingTimeout(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
+
+inline void controlReceptionService(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
+
+inline void controlTransmissionService(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
+
+inline timeval getRTCPCheckInterval(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
+
+inline size_t dispatchDataPacket(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+virtual void run(void);
+
+virtual void timerTick(void);
+
+virtual bool isPendingData(microtimeout_t timeout);
+#else
+
+virtual void timerTick(void)
+{return;}
+
+virtual bool isPendingData(microtimeout_t timeout)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
+
+/**
+ * Single runnable method for this RTP stacks, schedules
+ * outgoing and incoming RTP data and RTCP packets.
+ **/
+virtual void run(void)
+{
+	microtimeout_t timeout = 0;
+	while ( ServiceQueue::isActive() ) {
+		if ( timeout < 1000 ){ // !(timeout/1000)
+			timeout = getSchedulingTimeout();
+		}
+		setCancel(cancelDeferred);
+		controlReceptionService();
+		controlTransmissionService();
+		setCancel(cancelImmediate);
+		microtimeout_t maxWait =
+			timeval2microtimeout(getRTCPCheckInterval());
+		// make sure the scheduling timeout is
+		// <= the check interval for RTCP
+		// packets
+		timeout = (timeout > maxWait)? maxWait : timeout;
+		if ( timeout < 1000 ) { // !(timeout/1000)
+			setCancel(cancelDeferred);
+			dispatchDataPacket();
+			setCancel(cancelImmediate);
+			timerTick();
+		} else {
+			if ( isPendingData(timeout/1000) ) {
+				setCancel(cancelDeferred);
+                                if (ServiceQueue::isActive()) { // take in only if active
+                                    takeInDataPacket();
+                                }
+				setCancel(cancelImmediate);
+			}
+			timeout = 0;
+		}
+	}
+	dispatchBYE("GNU ccRTP stack finishing.");
+//        Thread::exit();
+}
+
+#endif
+
+inline size_t takeInDataPacket(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
+
+inline size_t dispatchBYE(const std::string &str)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
+};
+
+/**
+ * @typedef RTPSession
+ *
+ * Uses two pairs of sockets for RTP data and RTCP
+ * transmission/reception.
+ *
+ * @short UDP/IPv4 RTP Session scheduled by one thread of execution.
+ **/
+typedef SingleThreadRTPSession<> RTPSession;
+
+/**
+ * @typedef RTPSocket
+ *
+ * Alias for RTPSession.
+ **/
+typedef RTPSession RTPSocket;
+
+/**
+ * @typedef SymmetricRTPSession
+ *
+ * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
+ * transmission/reception.
+ *
+ * @short Symmetric UDP/IPv4 RTP session scheduled by one thread of execution.
+ **/
+typedef SingleThreadRTPSession<SymmetricRTPChannel,
+			       SymmetricRTPChannel> SymmetricRTPSession;
+
+#ifdef	CCXX_IPV6
+
+/**
+ * @class RTPSessionBaseIPV6
+ *
+ * Generic RTP protocol stack for exchange of realtime data.  This
+ * stack uses the concept of packet send and receive queues to schedule
+ * and buffer outgoing packets and to arrange or reorder incoming packets
+ * as they arrive.
+ *
+ * This is a template class that allows customization of two aspects:
+ * the underlying network and the control protocol. The RTPDataChannel
+ * and RTCPChannel template parameters specify the socket types to
+ * use. The ServiceQueue template parameter specify which packet queue
+ * is used.
+ *
+ * RTPSessionBase objects do not have any threading policy, thus
+ * allowing to customize this aspect in derived classes (see
+ * SingleThreadRTPSession or RTPSessionPoolBase).
+ *
+ * @author David Sugar <dyfet@ostel.com>
+ * @short RTP protocol stack based on Common C++.
+ **/
+template <class RTPDataChannel = DualRTPUDPIPv6Channel,
+	  class RTCPChannel = DualRTPUDPIPv6Channel,
+	  class ServiceQueue = AVPQueue>
+class __EXPORT TRTPSessionBaseIPV6 : public ServiceQueue
+{
+public:
+/**
+ * Builds a session waiting for packets in a host address.
+ *
+ * @param ia Network address this socket is to be bound.
+ * @param dataPort Transport port the data socket is to be bound.
+ * @param controlPort Transport port the control socket is to be bound.
+ * @param membersSize Initial size of the membership table.
+ * @param app Application this session is associated to.
+ * */
+TRTPSessionBaseIPV6(const IPV6Host& ia, tpport_t dataPort,
+	tpport_t controlPort, uint32 membersSize,
+	RTPApplication& app) :
+	ServiceQueue(membersSize,app)
+{ build(ia,dataPort,controlPort); }
+
+	/**
+	 * Builds a session with the specified ssrc identifier for the
+	 * local source.
+	 *
+	 * @param ssrc SSRC identifier for the local source.
+	 * @param ia Network address this socket is to be bound.
+	 * @param dataPort Transport port the data socket is to be bound.
+	 * @param controlPort Transport port the control socket is to be bound.
+	 * @param membersSize Initial size of the membership table.
+	 * @param app Application this session is associated to.
+	 **/
+	TRTPSessionBaseIPV6(uint32 ssrc,
+			    const IPV6Host& ia,
+			    tpport_t dataPort, tpport_t controlPort,
+			    uint32 membersSize, RTPApplication& app):
+		ServiceQueue(ssrc,membersSize,app)
+		{ build(ia,dataPort,controlPort); }
+
+	/**
+	 * Builds a session waiting for packets in a multicast address.
+	 * TODO: ssrc constructor for multicast!
+	 *
+	 * @param ia Multicast address this socket is to be bound.
+	 * @param dataPort Transport port the data socket is to be bound.
+	 * @param controlPort Transport port the control socket is to be bound.
+	 * @param membersSize Initial size of the membership table.
+	 * @param app Application this session is associated to.
+	 * @param iface Index (from 0 to n) of network interface to join to
+	 * multicast group.
+	 **/
+	TRTPSessionBaseIPV6(const IPV6Multicast& ia, tpport_t dataPort,
+			    tpport_t controlPort, uint32 membersSize,
+			    RTPApplication& app, uint32 iface) :
+		ServiceQueue(membersSize,app)
+		{ build(ia,dataPort,controlPort,iface); }
+
+	/**
+	 * Builds a session waiting for packets in a multicast
+	 * address, with the specified ssrc identifier for the local
+	 * source.
+	 *
+	 * @param ssrc SSRC identifier for the local source.
+	 * @param ia Multicast address this socket is to be bound.
+	 * @param dataPort Transport port the data socket is to be bound.
+	 * @param controlPort Transport port the control socket is to be bound.
+	 * @param membersSize Initial size of the membership table.
+	 * @param app Application this session is associated to.
+	 * @param iface Index (from 0 to n) of network interface to join to
+	 * multicast group.
+	 **/
+	TRTPSessionBaseIPV6(uint32 ssrc,
+			    const IPV6Multicast& ia, tpport_t dataPort,
+			    tpport_t controlPort, uint32 membersSize,
+			    RTPApplication& app, uint32 iface) :
+		ServiceQueue(ssrc,membersSize,app)
+		{ build(ia,dataPort,controlPort,iface); }
+
+	virtual size_t dispatchBYE(const std::string &str)
+		{
+			return QueueRTCPManager::dispatchBYE(str);
+		}
+
+	inline virtual
+	~TRTPSessionBaseIPV6()
+		{
+			endSocket();
+		}
+
+	inline RTPDataChannel *getDSO(void)
+		{return dso;}
+
+protected:
+	/**
+	 * @param timeout maximum timeout to wait, in microseconds
+	 */
+	inline bool
+	isPendingData(microtimeout_t timeout)
+		{ return dso->isPendingRecv(timeout); }
+
+	inline IPV6Host
+	getDataSender(tpport_t *port = NULL) const
+		{ return dso->getSender(port); }
+
+	inline size_t
+	getNextDataPacketSize() const
+		{ return dso->getNextPacketSize(); }
+
+	/**
+	 * Receive data from the data channel/socket.
+	 *
+	 * @param buffer Memory region to read to.
+	 * @param len Maximum number of octets to get.
+	 * @param na Source network address.
+	 * @param tp Source transport port.
+	 * @return Number of octets actually read.
+	 */
+	inline size_t
+	recvData(unsigned char* buffer, size_t len,
+		 IPV6Host& na, tpport_t& tp)
+		{ na = dso->getSender(tp); return dso->recv(buffer, len); }
+
+        inline void
+        setDataPeerIPV6(const IPV6Host &host, tpport_t port)
+		{ dso->setPeer(host,port); }
+
+	/**
+	 * @param buffer memory region to write from
+	 * @param len number of octets to write
+	 */
+	inline size_t
+	sendDataIPV6(const unsigned char* const buffer, size_t len)
+		{ return dso->send(buffer, len); }
+
+	inline SOCKET getDataRecvSocket() const
+		{ return dso->getRecvSocket(); }
+
+	/**
+	 * @param timeout maximum timeout to wait, in microseconds
+	 * @return whether there are packets waiting to be picked
+	 */
+        inline bool
+	isPendingControl(microtimeout_t timeout)
+		{ return cso->isPendingRecv(timeout); }
+
+	inline IPV6Host
+	getControlSender(tpport_t *port = NULL) const
+		{ return cso->getSender(port); }
+
+	/**
+	 * Receive data from the control channel/socket.
+	 *
+	 * @param buffer Buffer where to get data.
+	 * @param len Maximum number of octets to get.
+	 * @param na Source network address.
+	 * @param tp Source transport port.
+	 * @return Number of octets actually read.
+	 **/
+        inline size_t
+	recvControl(unsigned char *buffer, size_t len,
+		    IPV6Host& na, tpport_t& tp)
+		{ na = cso->getSender(tp); return cso->recv(buffer,len); }
+
+        inline void
+        setControlPeerIPV6(const IPV6Host &host, tpport_t port)
+		{ cso->setPeer(host,port); }
+
+	/**
+	 * @return number of octets actually written
+	 * @param buffer
+	 * @param len
+	 */
+        inline size_t
+	sendControl(const unsigned char* const buffer, size_t len)
+		{ return cso->send(buffer,len); }
+
+	inline SOCKET getControlRecvSocket() const
+		{ return cso->getRecvSocket(); }
+
+	inline void
+	endSocket()
+		{
+			dso->endSocket();
+			cso->endSocket();
+			if (dso) delete dso;
+			dso = NULL;
+			if (cso) delete cso;
+			cso = NULL;
+		}
+
+private:
+	void
+	build(const IPV6Host& ia, tpport_t dataPort,
+	      tpport_t controlPort)
+		{
+			if ( 0 == controlPort ) {
+				dataBasePort = even_port(dataPort);
+				controlBasePort = dataBasePort + 1;
+			} else {
+				dataBasePort = dataPort;
+				controlBasePort = controlPort;
+			}
+			dso = new RTPDataChannel(ia,dataBasePort);
+			cso = new RTCPChannel(ia,controlBasePort);
+		}
+
+	void
+	build(const IPV6Multicast& ia, tpport_t dataPort,
+	      tpport_t controlPort, uint32 iface)
+		{
+			if ( 0 == controlPort ) {
+				dataBasePort = even_port(dataPort);
+				controlBasePort = dataBasePort + 1;
+			} else {
+				dataBasePort = dataPort;
+				controlBasePort = controlPort;
+			}
+			dso = new RTPDataChannel(IPV6Host("0.0.0.0"),dataBasePort);
+			cso = new RTCPChannel(IPV6Host("0.0.0.0"),controlBasePort);
+			joinGroup(ia,iface);
+		}
+
+	/**
+	 * Join a multicast group.
+	 *
+	 * @param ia address of the multicast group
+	 * @return error code from the socket operation
+	 */
+	inline Socket::Error
+	joinGroup(const IPV6Multicast& ia, uint32 iface)
+		{
+			Socket::Error error  = dso->setMulticast(true);
+			if ( error ) return error;
+			error = dso->join(ia,iface);
+			if ( error ) return error;
+			error = cso->setMulticast(true);
+			if ( error ) {
+				dso->drop(ia);
+				return error;
+			}
+			error = cso->join(ia,iface);
+			if ( error ) {
+				dso->drop(ia);
+				return error;
+			}
+			return Socket::errSuccess;
+		}
+
+	/**
+	 * Leave a multicast group.
+	 *
+	 * @param ia address of the multicast group
+	 * @return error code from the socket operation
+	 */
+	inline Socket::Error
+	leaveGroup(const IPV6Multicast& ia)
+		{
+			Socket::Error error = dso->setMulticast(false);
+			if ( error ) return error;
+			error = dso->leaveGroup(ia);
+			if ( error ) return error;
+			error = cso->setMulticast(false);
+			if ( error ) return error;
+			return cso->leaveGroup(ia);
+		}
+
+	/**
+	 * Set the value of the TTL field in the sent packets.
+	 *
+	 * @param ttl Time To Live
+	 * @return error code from the socket operation
+	 */
+	inline Socket::Error
+	setMcastTTL(uint8 ttl)
+		{
+			Socket::Error error = dso->setMulticast(true);
+			if ( error ) return error;
+			error = dso->setTimeToLive(ttl);
+			if ( error ) return error;
+			error = cso->setMulticast(true);
+			if ( error ) return error;
+			return cso->setTimeToLive(ttl);
+		}
+
+	/**
+	 * Ensure a port number is odd. If it is an even number, return
+	 * the next lower (odd) port number.
+	 *
+	 * @param port number to filter
+	 * @return filtered (odd) port number
+	 */
+	inline tpport_t
+	odd_port(tpport_t port)
+		{ return (port & 0x01)? (port) : (port - 1); }
+
+	/**
+	 * Ensure a port number is even. If it is an odd number, return
+	 * the next lower (even) port number.
+	 *
+	 * @param port number to filter
+	 * @return filtered (even) port number
+	 */
+	inline tpport_t
+	even_port(tpport_t port)
+		{ return (port & 0x01)? (port - 1) : (port); }
+
+	tpport_t dataBasePort;
+	tpport_t controlBasePort;
+
+protected:
+	RTPDataChannel* dso;
+	RTCPChannel* cso;
+	friend class RTPSessionBaseHandler;
+};
+
+/**
+ * @class SingleThreadRTPSessionIPV6
+ *
+ * This template class adds the threading aspect to the RTPSessionBase
+ * template in one of the many possible ways. It inherits from a
+ * single execution thread that schedules sending of outgoing packets
+ * and receipt of incoming packets.
+ *
+ * @author David Sugar <dyfet@gnutelephony.org>
+ **/
+template
+<class RTPDataChannel = DualRTPUDPIPv6Channel,
+ class RTCPChannel = DualRTPUDPIPv6Channel,
+ class ServiceQueue = AVPQueue>
+class __EXPORT SingleThreadRTPSessionIPV6 :
+	protected Thread,
+	public TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
+{
+public:
+	SingleThreadRTPSessionIPV6(const IPV6Host& ia,
+				   tpport_t dataPort = DefaultRTPDataPort,
+				   tpport_t controlPort = 0,
+				   int pri = 0,
+				   uint32 memberssize =
+				   MembershipBookkeeping::defaultMembersHashSize,
+				   RTPApplication& app = defaultApplication()
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+		);
+#else
+	):
+	Thread(pri),
+	TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
+	(ia,dataPort,controlPort,memberssize,app)
+{ }
+#endif
+
+SingleThreadRTPSessionIPV6(const IPV6Multicast& ia,
+			   tpport_t dataPort = DefaultRTPDataPort,
+			   tpport_t controlPort = 0,
+			   int pri = 0,
+			   uint32 memberssize =
+			   MembershipBookkeeping::defaultMembersHashSize,
+			   RTPApplication& app = defaultApplication(),
+			   uint32 iface = 0
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+	);
+#else
+        ):
+        Thread(pri),
+        TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
+        (ia,dataPort,controlPort,memberssize,app,iface)
+{ }
+#endif
+
+~SingleThreadRTPSessionIPV6()
+{
+    if (isRunning()) {
+        disableStack(); Thread::join();
+    }
+}
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+virtual void startRunning();
+#else
+/**
+ * Activate stack and start service thread.
+ **/
+void
+startRunning()
+{ enableStack(); Thread::start(); }
+#endif
+
+
+protected:
+inline void enableStack(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
+
+inline void disableStack(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
+
+inline microtimeout_t getSchedulingTimeout(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
+
+inline void controlReceptionService(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
+
+inline void controlTransmissionService(void)
+{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
+
+inline timeval getRTCPCheckInterval(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
+
+inline size_t dispatchDataPacket(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
+
+#if defined(_MSC_VER) && _MSC_VER >= 1300
+virtual void run(void);
+
+virtual void timerTick(void);
+
+virtual bool isPendingData(microtimeout_t timeout);
+#else
+
+virtual void timerTick(void)
+{return;}
+
+virtual bool isPendingData(microtimeout_t timeout)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
+
+/**
+ * Single runnable method for this RTP stacks, schedules
+ * outgoing and incoming RTP data and RTCP packets.
+ **/
+virtual void run(void)
+{
+	microtimeout_t timeout = 0;
+	while ( ServiceQueue::isActive() ) {
+		if ( timeout < 1000 ){ // !(timeout/1000)
+			timeout = getSchedulingTimeout();
+		}
+		setCancel(cancelDeferred);
+		controlReceptionService();
+		controlTransmissionService();
+		setCancel(cancelImmediate);
+		microtimeout_t maxWait =
+			timeval2microtimeout(getRTCPCheckInterval());
+		// make sure the scheduling timeout is
+		// <= the check interval for RTCP
+		// packets
+		timeout = (timeout > maxWait)? maxWait : timeout;
+		if ( timeout < 1000 ) { // !(timeout/1000)
+			setCancel(cancelDeferred);
+			dispatchDataPacket();
+			setCancel(cancelImmediate);
+			timerTick();
+		} else {
+			if ( isPendingData(timeout/1000) ) {
+				setCancel(cancelDeferred);
+				takeInDataPacket();
+				setCancel(cancelImmediate);
+			}
+			timeout = 0;
+		}
+	}
+	dispatchBYE("GNU ccRTP stack finishing.");
+        Thread::exit();
+}
+
+#endif
+
+inline size_t takeInDataPacket(void)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
+
+inline size_t dispatchBYE(const std::string &str)
+{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
+};
+
+/**
+ * @typedef RTPSession
+ *
+ * Uses two pairs of sockets for RTP data and RTCP
+ * transmission/reception.
+ *
+ * @short UDP/IPv6 RTP Session scheduled by one thread of execution.
+ **/
+typedef SingleThreadRTPSessionIPV6<> RTPSessionIPV6;
+
+/**
+ * @typedef RTPSocket
+ *
+ * Alias for RTPSession.
+ **/
+typedef RTPSessionIPV6 RTPSocketIPV6;
+
+/**
+ * @typedef SymmetricRTPSession
+ *
+ * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
+ * transmission/reception.
+ *
+ * @short Symmetric UDP/IPv6 RTP session scheduled by one thread of execution.
+ **/
+ typedef SingleThreadRTPSessionIPV6<SymmetricRTPChannelIPV6,
+				    SymmetricRTPChannelIPV6> SymmetricRTPSessionIPV6;
+
+
+#endif
+
+/** @}*/ // sessions
+
+#ifdef  CCXX_NAMESPACES
+}
+#endif
+
+#endif  //CCXX_RTP_RTP_H_
+
+/** EMACS **
+ * Local variables:
+ * mode: c++
+ * c-basic-offset: 8
+ * End:
+ */