// Copyright (C) 1999 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.

#ifndef	__APE_RTP_H__
#define	__APE_RTP_H__

#ifndef __APE_THREAD_H__
#include <APE/thread.h>
#endif

#ifndef	__APE_SOCKET_H__
#include <APE/socket.h>
#endif

enum
{
	RTP_SAMPLING_ULAW,
	RTP_SAMPLING_8KHZ = RTP_SAMPLING_ULAW,
	RTP_SAMPLING_PCM16,
	RTP_SAMPLING_CDMONO,
	RTP_SAMPLING_CDSTERIO
};

#ifdef	WIN32
class __EXPORT RTPThread;
class __EXPORT RTPSendThread;
class __EXPORT RTPRecvThread;
class __EXPORT RTPSocket;
class __EXPORT RTPBroadcast;
#endif

/**
 * The RTP thread is the base class for RTP socket send and receive servicing.
 * An internal buffer is provided for assembling RTP data packets, and a
 * new time synchronization service is offered so that threads can sleep
 * intervals that can be adjusted to the passing of actual time to account
 * for processing drift.
 * 
 * @short Base thread class for servicing real time queues.
 * @author David Sugar (dyfet@ostel.com)
 */

class RTPThread : public Thread
{
private:
	struct timeval _tv;
	
protected:
	/**
	 * Working buffer for rtp data packets.
	 */
	unsigned char rtpdata[1500];
	/**
	 * Reset the pause timer to the current time of day.  This is
	 * used to initially synchronize the stream timer when time clock
	 * based "pacing" is required, such as when streaming data that
	 * is not realtime in origin.
	 */
	void Reset(void);
	/**
	 * This service provides a time synchronized delay via APE sleep.
	 * The delay is computed by adjusting the time forward.
	 * 
	 * @return true if delay needed (after sleeping).
	 * @param time interval to synchronize on.
	 */
	bool Pause(timeout_t sync);
public:
	/**
	 * Construct and set initial timer for a new RTP service thread.
	 * 
	 * @param start starting semaphore for synchronization.
	 * @param pri thread base priority relative to it's parent.
	 */
       	RTPThread(Semaphore *start = NULL, int pri = 0);
	/**
	 * Destroy an RTP service thread.  Wait for any remaining time
	 * synchronization and exit.
	 */
	virtual ~RTPThread();
};

/**
 * The service thread used to deliver received rtp packets.  This
 * virtual service thread provides the core functionality for streaming
 * of inbound media packets.  In fact, streaming includes abstract I/O
 * services that are implemented on a per protocol bases which allows
 * RTPRecvThread to drive IPX "RTP" sockets or even VAT sessions.
 * 
 * @short Service thread for real-time streaming input.
 * @author David Sugar (dyfet@ostel.com)
 */
class RTPSendThread : public RTPThread
{
private:
	timeout_t timeout;
	
	void Run(void)
		{RunSender();};
	
	void Initial(void)
		{InitSender();};
	
	void Final(void)
		{ExitSender();};
protected:
	/**
	 * Initial thread service.  This is used to support multiple
	 * inheretance of sending and receiving threads in a single object.
	 */
	virtual void InitSender(void)
		{return;};
	/**
	 * Exit thread service for self destructing objects.  This is
	 * used to support multiple inheretance of sending and receiving
	 * threads in a single object.
	 */
	virtual void ExitSender(void)
		{return;};
	/**
	 * The default run method of a sending service thread.  This is
	 * used to support multipe inheretance of sending and receiving
	 * threads in a single object.
	 */
	virtual void RunSender(void);
	/**
	 * Receive RTP data into an RTP formatted packet using the current
	 * protocol from the read routine in the derived class.  This
	 * may apply decompression and other codec functions.  This
	 * function normally blocks until a RTP packet is received.
	 * 
	 * @return actual number of bytes sent on success, -1 on error.
	 * @param buf pointer to rtpdata buffer.
	 * @param len of bytes to write.
	 */
	virtual ssize_t RTPSend(unsigned char *buf, size_t len) = 0;
	/**
	 * Fetch a sample of data in the current sampling format for
	 * the time interval specified.
	 * 
	 * @return number of bytes fetched on success, -1 on failure.
	 * @param buf pointer to rtpdata buffer.
	 * @param timer for data frame to read.
	 */
	virtual size_t RTPFetch(unsigned char *buf, timeout_t timer) = 0;
	/**
	 * Update the time stamp for the next sent packet in the derived
	 * protocol.
	 *
	 * @param current sending timeout.
	 */
	virtual void RTPUpdate(timeout_t timer);
	/**
	 * Error handler for derived class.
	 */
	virtual void RTPSendError(void);
	/**
	 * Set the effective time frame for sending RTP data.  This cal
	 * should be made within a derived RTPUpdate() method to assure
	 * it does not occur during processing.
	 * 
	 * @param new timeout.
	 */
	inline void setTimeout(timeout_t timer)
		{timeout = timer;};
public:
	/**
	 * Construct a RTP service thread for sending packets.  We normally
	 * use 20ms timing frames.
	 * 
	 * @param start semaphore to use for synchronized startup.
	 * @param pri level of this thread relative to parent.
	 */
	RTPSendThread(Semaphore *start = NULL, int pri = 0, timeout_t timer = 20);
	/**
	 * Terminate the sending thread service after timing out until
	 * the current frame has a chance to be sent.
	 */
	virtual ~RTPSendThread();
	/**
	 * Allows derived class to retrieve data sampling format.  This
	 * may be useful in conjunction with some codec's.  The derived
	 * RTPFetch() may use this to determine recording format, etc.
	 * 
	 * @return RTP data sampling format in use.
	 */
	virtual inline unsigned getSampling(void)
		{return RTP_SAMPLING_8KHZ;};
	/**
	 * This may be used to specify a new session id number to use.
	 * 
	 * @param session id.
	 */
	virtual void setSession(unsigned long session)
       		{return;};
};

/**
 * The service thread used to deliver received rtp packets.  This
 * virtual service thread provides the core functionality for streaming
 * of inbound media packets.  In fact, streaming includes abstract I/O
 * services that are implemented on a per protocol bases which allows
 * RTPRecvThread to drive IPX "RTP" sockets or even VAT sessions.
 * 
 * @short Service thread for real-time streaming input.
 * @author David Sugar (dyfet@ostel.com)
 */
class RTPRecvThread : public RTPThread
{
private:
	void Run(void)
		{RunReceiver();};
	
	void Initial(void)
		{InitReceiver();};
	
	void Final(void)
		{ExitReceiver();};
protected:
	/**
	 * Initial thread service.  This is used to support multiple
	 * inheretance of sending and receiving threads in a single object.
	 */
	virtual void InitReceiver(void)
		{return;};
	/**
	 * Exit thread service for self destructing objects.  This is
	 * used to support multiple inheretance of sending and receiving
	 * threads in a single object.
	 */
	virtual void ExitReceiver(void)
		{return;};
	/**
	 * The default run method of a sending service thread.  This is
	 * used to support multipe inheretance of sending and receiving
	 * threads in a single object.
	 */
	virtual void RunReceiver(void);
	/**
	 * Receive RTP data into an RTP formatted packet using the current
	 * protocol from the read routine in the derived class.  This
	 * may apply decompression and other codec functions.  This
	 * function normally blocks until a RTP packet is received.
	 * 
	 * @return actual number of bytes read on success, -1 on error.
	 * @param buf pointer to rtpdata buffer.
	 * @param seq number of received packet.
	 * @param timestamp of received packet.
	 */
	virtual ssize_t RTPRecv(unsigned char *buf, unsigned short *seq, unsigned long *timestamp) = 0;
	/**
	 * Virtual function used to post the last retrieved message.  This
	 * operates by calling the protocol 'derived' class which has
	 * the header information for the last read packet.
	 * 
	 * @return number of bytes posted on success, -1 on failure.
	 * @param buf pointer to rtpdata buffer.
	 * @param seq number of last read packet.
	 * @param time stamp of this packet.
	 */
	virtual size_t RTPPost(unsigned char *buf, unsigned short seq, unsigned long timestamp, size_t len) = 0;
	/**
	 * Error processing routine for receive failures.
	 */
	virtual void RTPRecvError(void)
		{return;};
	/**
	 * Protocol may use this to specify a new session has been initiated.
	 * 
	 * @param session number of this session.
	 */
	virtual void SessionId(unsigned long session)
		{return;};
public:
	/**
	 * Construct a RTP service thread for receiving packets.  
	 * 
	 * @param start semaphore to use for synchronized startup.
	 * @param pri level of this thread relative to parent.
	 */
	RTPRecvThread(Semaphore *start = NULL, int pri = 0);
	/**
	 * Terminate the receiving thread service.
	 */
	virtual ~RTPRecvThread()
		{Terminate();};
	/**
	 * Allows derived class to retrieve data sampling format.  This
	 * may be useful in conjunction with some codec's.  The derived
	 * RTPPost() may use this to determine recording format, etc.
	 * 
	 * @return RTP data sampling format in use.
	 */
	virtual inline unsigned getSampled(void)
		{return RTP_SAMPLING_8KHZ;};
};

/**
 * This abstract class implements the basic support needed for a UDP
 * RTP session.  It uses both a sending and receiving service thread
 * each of which may have derived methods in this new class.
 * 
 * @author David Sugar <dyfet@ostel.com>.
 * @short Abstract base class for UDP RTP protocol service.
 */
class RTPSocket : public UDPSocket, public RTPSendThread, public RTPRecvThread
{
private:
	Semaphore _start;
	
#pragma pack(1)
	struct
	{
		unsigned char flags[2];
		unsigned short sequence;
		unsigned long timestamp;
		unsigned long source;
		unsigned long conf[15];
	} rtprecv, rtpsend;	       
#pragma pack()
	
protected:
	/**
	 * Update the time stamp for the next sent packet.
	 * 
	 * @param current sending timeout.
	 */
	virtual void RTPUpdate(timeout_t timer);

	/**
	 * Sets the payload id for sending RTP packets.  This is
	 * virtualized so that RTPAudio can also specify sampling
	 * rates based on the returned value.
	 * 
	 * @param payload message type (0-127) for sending.
	 */
	virtual void setPayload(unsigned payload);
	/**
	 * Add a conference id to the RTP send message.
	 * 
	 * @param source for added conference id.
	 */
	virtual void addConference(unsigned long source);
	/**
	 * Set this server's stream source id.
	 * 
	 * @param source id to use for my stream.
	 */
	 inline void setSource(unsigned long source)
		{rtpsend.source = source;};
	/**
	 * Write data to the UDP socket.  This implements the send
	 * service thread writer.
	 * 
	 * @return number of bytes written on success, -1 on failure.
	 * @param address buffer to write.
	 * @param len of bytes to write in addition to the header.
	 */
	ssize_t RTPSend(unsigned char *buf, size_t len);
	/**
	 * read data from the UDP socket.  This implements the receive
	 * service thread reader.
	 * 
	 * @return number of bytes read on success, -1 on failure.
	 * @param address buffer to read.
	 * @param sequence number received.
	 * @param timestamp received.
	 */
	ssize_t RTPRecv(unsigned char *buf, unsigned short *seq, unsigned long *timestamp);

public:
	/**
	 * Create and bind an RTP socket to an internet interface address
	 * and known port number.  The sending thread timeout can be
	 * adjusted with setTimeout() before calling Start() for the sending
	 * service thread.  One might also call setPayload, etc.
	 * 
	 * @param bind address to bind this socket to.
	 * @param port address to bind the service under.
	 * @param pri of service threads relative to parent.
	 * @param session id for sending under.
	 */
	RTPSocket(InetAddress &bind, short port, int pri, unsigned long session);
	/**
	 * Starts both service threads.  This functions similar to the APE
	 * thread Start() method and uses the private starting semaphore.
	 */
	void Start(void);
};

/**
 * This abstract class implements the basic support needed for a RTP
 * broadcast session using UDP packets.  Broadcasts are uni-directional
 * and can be used to flood a subnet with real-time streaming.  There
 * should also be a RTPMulticast added soon.
 * 
 * @author David Sugar <dyfet@ostel.com>.
 * @short Abstract base class for UDP RTP subnet broadcast.
 */
class RTPBroadcast : public UDPSocket, public RTPSendThread
{
private:
	Semaphore _start;
	
#pragma pack(1)
	struct
	{
		unsigned char flags[2];
		unsigned short sequence;
		unsigned long timestamp;
		unsigned long source;
		unsigned long conf[15];
	} rtpsend;	       
#pragma pack()
	
protected:
	/**
	 * Update the time stamp for the next sent packet.
	 * 
	 * @param current sending timeout.
	 */
	virtual void RTPUpdate(timeout_t timer);

	/**
	 * Sets the payload id for sending RTP packets.  This is
	 * virtualized so that RTPAudio can also specify sampling
	 * rates based on the returned value.
	 * 
	 * @param payload message type (0-127) for sending.
	 */
	virtual void setPayload(unsigned payload);
	/**
	 * Add a conference id to the RTP send message.
	 * 
	 * @param source for added conference id.
	 */
	virtual void addConference(unsigned long source);
	/**
	 * Set this server's stream source id.
	 * 
	 * @param source id to use for my stream.
	 */
	 inline void setSource(unsigned long source)
		{rtpsend.source = source;};
	/**
	 * Write data to the UDP socket.  This implements the send
	 * service thread writer.
	 * 
	 * @return number of bytes written on success, -1 on failure.
	 * @param address buffer to write.
	 * @param len of bytes to write in addition to the header.
	 */
	ssize_t RTPSend(unsigned char *buf, size_t len);
public:
	/**
	 * Create and bind an RTP socket to an internet interface address
	 * and known port number for the purpose of subnet broadcasting
	 * with RTP.
	 * 
	 * @param bind address to bind this socket to.
	 * @param port address to bind the service under.
	 * @param pri of service threads relative to parent.
	 * @param session id for sending under.
	 */
	RTPBroadcast(BroadcastAddress &bind, short port, int pri, unsigned long session);
};

#endif

Documentation generated by dyfet@centauri.sys on Tue Jun 29 23:36:17 EDT 1999