// 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 __RTS_THREAD_H__
#define __RTS_THREAD_H__

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

#ifndef __RTS_AUDIO_H__
#include <RTS/audio.h>
#endif

#ifdef  WIN32
class __EXPORT RTSThread;
class __EXPORT RTSSendThread;
class __EXPORT RTSRecvThread;
#endif

/**
 * The RT service thread is the base class for realtime send and receive servicing.
 * An internal buffer is provided for assembling realtime 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 RTSThread : public Thread
{
private:
	struct timeval _tv;
	timeout_t _timeout;
	int _startup;
	
protected:
	/**
	 * Working buffer for rtp data packets.
	 */
	unsigned char rtpdata[1500];
	/**
	 * Set the thread timeout.
	 * 
	 * @param timeout for this realtime service thread in milliseconds.
	 */
	void setTimeout(timeout_t timer)
		{_timeout = timer;};
	/**
	 * Add to current service thread startup delay.
	 *
	 * @param number of timeouts to add to the current startup.
	 */
	void setServiceDelay(int number)
		{_startup += number;};
	/**
	 * Test for and update service delay timer.
	 *
	 * @return true if service delay in effect.
	 */
	bool isServiceDelay(void);
	/**
	 * 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);
	/**
	 * Compute the amount of time that has transpired since the last
	 * time sync mark was computed.  This can be used to determine if
	 * a blocking operation has caused frame delays.
	 *
	 * @return used time in milliseconds.
	 */
	timeout_t getTimeUsed(void);
	/**
	 * Adjust current time marker for this thread.  This can be used
	 * in place of pausing when updating for delays that have already
	 * occured.
	 *
	 * @param timeout to adjust start time by.
	 */
	void addTimeUsed(timeout_t timeout);
	/**
	 * Set audio sampling format for this service
	 * thread.  This change is assumed to take effect on the
	 * next operation.
	 * 
	 * @param audio sampling format.
	 */
	virtual void setAudioSampling(unsigned format)
		{return;};
public:
	/**
	 * Get the timeout for this service thread.
	 * 
	 * @return service thread timeout in milliseconds.
	 */
	timeout_t getTimeout(void)
		{return _timeout;};
	/**
	 * 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.
	 */
	RTSThread(Semaphore *start = NULL, int pri = 0);
	/**
	 * Destroy an realtime service thread.  Wait for any remaining time
	 * synchronization and exit.
	 */
	virtual ~RTSThread();
	/**
	 * Determine audio format being supported by
	 * the service thread for the specified payload
	 * identifier currently in effect.
	 * 
	 * @param payload identifier.
	 * @return 0 on error.
	 */
	virtual unsigned getAudioSampling(unsigned payload)               
		{return RTS_AUDIO_UNSUPPORTED;};
	/**
	 * Get audio encoding codec to use for processing this
	 * realtime service stream based on the current payload
	 * identifier in effect.
	 *
	 * @param payload identifier.
	 * @return audio codec (base) to use or NULL if none.
	 */
	virtual AudioCodec *getAudioEncoding(unsigned format)
		{return NULL;};
};

/**
 * The service thread used to send real-time packets.  This
 * virtual service thread provides the core functionality for streaming
 * of outbound media packets.  In fact, streaming includes abstract I/O
 * services that are implemented on a per protocol bases which allows
 * RTSSendThread to drive IPX "RTP" sockets or even VAT sessions.
 * 
 * @short Service thread for real-time streaming input.
 * @author David Sugar (dyfet@ostel.com)
 */
class RTSSendThread : public RTSThread
{
private:
	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);
	/**
	 * Send realtime data from the service thread into the derived
	 * socket layer protocol.
	 * 
	 * @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 RTSSend(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 RTSFetch(unsigned char *buf, timeout_t timer) = 0;
	/**
	 * Update the time stamp for the next sent packet in the derived
	 * protocol for the service thread.
	 */
	virtual void RTSUpdate(void);
	/**
	 * Error handler for derived class.
	 */
	virtual void RTSSendError(void);
public:
	/**
	 * Construct realtime 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.
	 */
	RTSSendThread(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 ~RTSSendThread();
	/**
	 * 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
 * RTSRecvThread to drive IPX "RTP" sockets or even VAT sessions.
 * 
 * @short Service thread for real-time streaming input.
 * @author David Sugar (dyfet@ostel.com)
 */
class RTSRecvThread : public RTSThread
{
private:
	unsigned long _starting;

	void Run(void)
		{RunReceiver();};
	
	void Initial(void)
		{InitReceiver();};
	
	void Final(void)
		{ExitReceiver();};
protected:
	/**
	 * Set starting timestamp for the current window.  
	 * This starting time stamp is used to compute the
	 * relative offset of the received packet for posting into
	 * a pending delivery queue with RTSPost.
	 *
	 * @param value of starting time stamp for frame buffer.
	 */
	void setStarting(unsigned long value);
	/**
	 * The RTSOutput() method must use addStartup() to adjust
	 * the timestamp for the next packets received once real-
	 * time data has been retrieved.
	 *
	 * @param offset timestamp by specified samples.
	 * @return new base timestamp in effect.
	 */
	unsigned long addStarting(unsigned long offset);
	/**
	 * 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 realtime 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 encoding sample format of received packet (after codec).
	 * @param timestamp of received packet.
	 */
	virtual ssize_t RTSRecv(unsigned char *buf, unsigned short *encoding, unsigned long *timestamp) = 0;
	/**
	 * Process an output frame for timed playback.  Posting is assumed to
	 * post data into a buffer queue buffer.  Playback may also
	 * simply update the 'timing' window of the current frame.
	 *
	 * @param timeout of audio frames.
	 */
	virtual void RTSOutput(timeout_t timeout)
		{addStarting(8 * timeout);};
	/**
	 * Wait for the specified timeout duration for data to appear at the
	 * socket and then do a blind "internal" peek of the message header
	 * so that getPeerHeader() will be functional.
	 * 
	 * @return 0 if data available, -1 on failure.
	 * @param timeout of current session in milliseconds.
	 */
	virtual int RTSWait(timeout_t timeout);
	/**
	 * 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 encoding sample format of last read packet.
	 * @param time stamp of this packet.
	 */
	virtual size_t RTSPost(unsigned char *buf, unsigned short encoding, unsigned long timestamp, size_t len) = 0;
	/**
	 * Error processing routine for receive failures.
	 */
	virtual void RTSRecvError(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 RTS service thread for receiving packets.  
	 * 
	 * @param start semaphore to use for synchronized startup.
	 * @param pri level of this thread relative to parent.
	 * @param timer for synchronizing frames, default 20ms audio.
	 */
	RTSRecvThread(Semaphore *start = NULL, int pri = 0, timeout_t timer = 20);
	/**
	 * Terminate the receiving thread service.
	 */
	virtual ~RTSRecvThread()
		{Terminate();};

	/**
	 * Compute offset in pending queue for the specified packet
	 * based on it's timestamp.
	 *
	 * @return adjusted timestamp based on window offset. 
	 * @param timestamp of received packet.
	 */
	unsigned long getStarting(unsigned long stamp);
};

#endif

Documentation generated by dyfet@home.tycho.com on Fri Jul 2 11:43:56 EDT 1999