#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:
+ */