yate/yatephone.h

2646 lines
80 KiB
C
Raw Permalink Normal View History

/**
* yatephone.h
* This file is part of the YATE Project http://YATE.null.ro
*
* Drivers, channels and telephony related classes
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
2023-05-23 14:01:06 +00:00
* Copyright (C) 2004-2023 Null Team
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
*
* 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.
*/
#ifndef __YATEPHONE_H
#define __YATEPHONE_H
#ifndef __cplusplus
#error C++ is required
#endif
#include <yatengine.h>
/**
* Holds all Telephony Engine related classes.
*/
namespace TelEngine {
/**
* A structure to hold information about a static picture or video frame.
*/
struct YATE_API ImageInfo {
/**
* Width of the image in pixels
*/
int width;
/**
* Height of the image in pixels
*/
int height;
/**
* Bit depth of the image, 0 for unknown/irrelevant
*/
int depth;
};
/**
* A structure to hold information about a data format.
*/
struct YATE_API FormatInfo {
/**
* Standard no-blanks lowercase format name
*/
const char* name;
/**
* Format type: "audio", "video", "text"
*/
const char* type;
/**
* Frame size in octets/frame, 0 for non-framed formats
*/
int frameSize;
/**
* Frame time in microseconds, 0 for variable
*/
int frameTime;
/**
* Rate in samples/second (audio) or 1e-6 frames/second (video), 0 for unknown
*/
int sampleRate;
/**
* Number of channels, typically 1
*/
int numChannels;
/**
* If this is a valid candidate for conversion
*/
bool converter;
/**
* Guess the number of samples in an encoded data block
* @param len Length of the data block in octets
* @return Number of samples or 0 if unknown
*/
int guessSamples(int len) const;
/**
* Get the data rate in bytes/s
* @return Data rate or 0 if variable/undefined
*/
int dataRate() const;
/**
* Default constructor - used to initialize arrays
*/
inline FormatInfo()
: name(0), type("audio"),
frameSize(0), frameTime(0),
sampleRate(8000), numChannels(1),
converter(false)
{ }
/**
* Normal constructor
*/
inline explicit FormatInfo(const char* _name, int fsize = 0, int ftime = 10000,
const char* _type = "audio", int srate = 8000, int nchan = 1, bool convert = false)
: name(_name), type(_type),
frameSize(fsize), frameTime(ftime),
sampleRate(srate), numChannels(nchan),
converter(convert)
{ }
};
class DataEndpoint;
class CallEndpoint;
class Driver;
/**
* A structure to build (mainly static) translator capability tables.
* A table of such structures must end with an entry with null format names.
*/
struct YATE_API TranslatorCaps {
/** Description of source (input) data format */
const FormatInfo* src;
/** Description of destination (output) data format */
const FormatInfo* dest;
/** Computing cost in KIPS of converting a stream from src to dest */
int cost;
};
/**
* This is just a holder for the list of media formats supported by Yate
* @short A repository for media formats
*/
class YATE_API FormatRepository
{
YNOCOPY(FormatRepository); // no automatic copies please
private:
FormatRepository();
public:
/**
* Retrieve a format by name and type
* @param name Standard name of the format to find
* @return Pointer to the format info or NULL if not found
*/
static const FormatInfo* getFormat(const String& name);
/**
* Add a new format to the repository
* @param name Standard no-blanks lowercase format name
* @param fsize Data frame size in octets/frame, 0 for non-framed formats
* @param ftime Data frame duration in microseconds, 0 for variable
* @param type Format type: "audio", "video", "text"
* @param srate Rate in samples/second (audio) or 1e-6 frames/second (video), 0 for unknown
* @param nchan Number of channels, typically 1
* @return Pointer to the format info or NULL if another incompatible
* format with the same name was already registered
*/
static const FormatInfo* addFormat(const String& name, int fsize, int ftime, const String& type = "audio", int srate = 8000, int nchan = 1);
};
/**
* An extension of a String that can parse data formats
* @short A Data format
*/
class YATE_API DataFormat : public NamedList
{
public:
/**
* Creates a new, empty format string.
*/
inline DataFormat()
: NamedList((const char*)0), m_parsed(0)
{ }
/**
* Creates a new initialized format.
* @param value Initial value of the format
*/
inline DataFormat(const char* value)
: NamedList(value), m_parsed(0)
{ }
/**
* Copy constructor.
* @param value Initial value of the format
*/
inline DataFormat(const DataFormat& value)
: NamedList(value), m_parsed(value.getInfo())
{ }
/**
* Constructor from String reference
* @param value Initial value of the format
*/
inline DataFormat(const String& value)
: NamedList(value), m_parsed(0)
{ }
/**
* Constructor from NamedList reference
* @param value Initial value of the format and parameters
*/
inline DataFormat(const NamedList& value)
: NamedList(value), m_parsed(0)
{ }
/**
* Constructor from String pointer.
* @param value Initial value of the format
*/
inline DataFormat(const String* value)
: NamedList(value ? value->c_str() : (const char*)0), m_parsed(0)
{ }
/**
* Constructor from format information
* @param format Pointer to existing FormatInfo
*/
inline explicit DataFormat(const FormatInfo* format)
: NamedList(format ? format->name : (const char*)0), m_parsed(format)
{ }
/**
* Assignment operator.
*/
inline DataFormat& operator=(const DataFormat& value)
{ NamedList::operator=(value); m_parsed = value.getInfo(); return *this; }
/**
* Retrieve a pointer to the format information
* @return Pointer to the associated format info or NULL if error
*/
const FormatInfo* getInfo() const;
/**
* Retrieve the frame size
* @param defValue Default value to return if format is unknown
* @return Frame size in octets/frame, 0 for non-framed, defValue if unknown
*/
inline int frameSize(int defValue = 0) const
{ return getInfo() ? getInfo()->frameSize : defValue; }
/**
* Retrieve the frame time
* @param defValue Default value to return if format is unknown
* @return Frame time in microseconds, 0 for variable, defValue if unknown
*/
inline int frameTime(int defValue = 0) const
{ return getInfo() ? getInfo()->frameTime : defValue; }
/**
* Retrieve the sample rate
* @param defValue Default value to return if format is unknown
* @return Rate in samples/second (audio) or 1e-6 frames/second (video),
* 0 for unknown, defValue if unknown format
*/
inline int sampleRate(int defValue = 0) const
{ return getInfo() ? getInfo()->sampleRate : defValue; }
/**
* Retrieve the number of channels
* @param defValue Default value to return if format is unknown
* @return Number of channels (typically 1), defValue if unknown format
*/
inline int numChannels(int defValue = 1) const
{ return getInfo() ? getInfo()->numChannels : defValue; }
protected:
/**
* Called whenever the value changed (except in constructors).
*/
virtual void changed();
private:
mutable const FormatInfo* m_parsed;
};
/**
* A generic data handling object
*/
class YATE_API DataNode : public RefObject
{
friend class DataEndpoint;
YNOCOPY(DataNode); // no automatic copies please
public:
/**
* Flags associated with the DataBlocks forwarded between nodes
*/
enum DataFlags {
DataStart = 0x0001,
DataEnd = 0x0002,
DataMark = 0x0004,
DataSilent = 0x0008,
DataMissed = 0x0010,
DataError = 0x0020,
DataPrivate = 0x0100
};
/**
* Construct a DataNode
* @param format Description of the data format, default none
*/
inline explicit DataNode(const char* format = 0)
: m_format(format), m_timestamp(0)
{ }
/**
* Get the computing cost of converting the data to the format asked
* @param format Name of the format to check for
* @return -1 if unsupported, 0 for native format else cost in KIPS
*/
virtual int costFormat(const DataFormat& format)
{ return -1; }
/**
* Change the format used to transfer data
* @param format Name of the format to set for data
* @return True if the format changed successfully, false if not changed
*/
virtual bool setFormat(const DataFormat& format)
{ return false; }
/**
* Get the description of the format currently in use
* @return Pointer to the data format
*/
inline const DataFormat& getFormat() const
{ return m_format; }
/**
* Get the current position in the data stream
* @return Timestamp of current data position
*/
inline unsigned long timeStamp() const
{ return m_timestamp; }
/**
* Check if this data node is still valid
* @return True if still valid, false if node should be removed
*/
virtual bool valid() const
{ return true; }
/**
* Modify node parameters
* @param params The list of parameters to change
* @return True if processed
*/
virtual bool control(NamedList& params)
{ return false; }
/**
* Get the internal representation of an invalid or unknown timestamp
* @return Invalid timestamp - unsigned long conversion of -1
*/
inline static unsigned long invalidStamp()
{ return (unsigned long)-1; }
/**
* Owner attach and detach notification.
* This method is called with @ref DataEndpoint::commonMutex() held
* @param added True if a new owner was added, false if it was removed
*/
virtual void attached(bool added)
{ }
protected:
DataFormat m_format;
unsigned long m_timestamp;
};
class DataSource;
class DataTranslator;
class TranslatorFactory;
class ThreadedSourcePrivate;
/**
* A data consumer
*/
class YATE_API DataConsumer : public DataNode
{
friend class DataSource;
public:
/**
* Consumer constructor
* @param format Name of the data format, default "slin" (Signed Linear)
*/
inline explicit DataConsumer(const char* format = "slin")
: DataNode(format),
m_source(0), m_override(0),
m_regularTsDelta(0), m_overrideTsDelta(0), m_lastTsTime(0)
{ }
/**
* Destruct notification - complains loudly if still attached to a source
*/
virtual void destroyed();
/**
* Get a pointer to a derived class given that class name
* @param name Name of the class we are asking for
* @return Pointer to the requested class or NULL if this object doesn't implement it
*/
virtual void* getObject(const String& name) const;
/**
* Consumes the data sent to it from a source
* @param data The raw data block to process
* @param tStamp Timestamp of data - typically samples
* @param flags Indicator flags associated with the data block
* @return Number of samples actually consumed,
* use invalidStamp() to indicate that all data was consumed,
* return zero for consumers that become invalid
*/
virtual unsigned long Consume(const DataBlock& data, unsigned long tStamp, unsigned long flags) = 0;
/**
* Get the data source of this object if it's connected
* @return A pointer to the DataSource object or NULL
*/
inline DataSource* getConnSource() const
{ return m_source; }
/**
* Get the override data source of this object if it's connected
* @return A pointer to the DataSource object or NULL
*/
inline DataSource* getOverSource() const
{ return m_override; }
/**
* Get the data source of a translator object
* @return A pointer to the DataSource object or NULL
*/
virtual DataSource* getTransSource() const
{ return 0; }
protected:
/**
* Synchronize the consumer with a source
* @param source Data source to copy the timestamp from
* @return True if we could synchronize with the source
*/
virtual bool synchronize(DataSource* source);
private:
unsigned long Consume(const DataBlock& data, unsigned long tStamp,
unsigned long flags, DataSource* source);
DataSource* m_source;
DataSource* m_override;
long m_regularTsDelta;
long m_overrideTsDelta;
u_int64_t m_lastTsTime;
};
/**
* A data source
*/
class YATE_API DataSource : public DataNode, public Mutex
{
friend class DataTranslator;
YNOCOPY(DataSource); // no automatic copies please
public:
/**
* Source constructor
* @param format Name of the data format, default "slin" (Signed Linear)
*/
inline explicit DataSource(const char* format = "slin")
: DataNode(format), Mutex(false,"DataSource"),
m_nextStamp(invalidStamp()), m_translator(0) { }
/**
* Source's destruct notification - detaches all consumers
*/
virtual void destroyed();
/**
* Get a pointer to a derived class given that class name
* @param name Name of the class we are asking for
* @return Pointer to the requested class or NULL if this object doesn't implement it
*/
virtual void* getObject(const String& name) const;
/**
* Check if this data source is still valid
* @return True if still valid, false if node should be removed
*/
virtual bool valid() const;
/**
* Modify source parameters, calls translator if one is set
* @param params The list of parameters to change
* @return True if processed
*/
virtual bool control(NamedList& params);
/**
* Forwards the data to its consumers
* @param data The raw data block to forward
* @param tStamp Timestamp of data - typically samples
* @param flags Indicator flags associated with the data block
* @return Number of samples actually forwarded to all consumers
*/
unsigned long Forward(const DataBlock& data, unsigned long tStamp = invalidStamp(),
unsigned long flags = 0);
/**
* Attach a data consumer
* @param consumer Data consumer to attach
* @param override Attach as temporary source override
* @return True on success, false on failure
*/
bool attach(DataConsumer* consumer, bool override = false);
/**
* Detach a data consumer
* @param consumer Data consumer to detach
* @return True on success, false on failure
*/
bool detach(DataConsumer* consumer);
/**
* Detach all data consumers
*/
void clear();
/**
* Get the master translator object if this source is part of a translator
* @return A pointer to the DataTranslator object or NULL
*/
inline DataTranslator* getTranslator() const
{ return m_translator; }
/**
* Synchronize the source and attached consumers with another timestamp
* @param tStamp New timestamp of data - typically samples
*/
void synchronize(unsigned long tStamp);
/**
* Get the next expected position in the data stream
* @return Timestamp of next expected data position, may be invalid/unknown
*/
inline unsigned long nextStamp() const
{ return m_nextStamp; }
protected:
unsigned long m_nextStamp;
ObjList m_consumers;
private:
inline void setTranslator(DataTranslator* translator) {
Lock mylock(this);
m_translator = translator;
}
bool detachInternal(DataConsumer* consumer);
DataTranslator* m_translator;
};
/**
* A data source with a thread of its own
* @short Data source with own thread
*/
class YATE_API ThreadedSource : public DataSource
{
friend class ThreadedSourcePrivate;
public:
/**
* The destruction notification, checks that the thread is gone
*/
virtual void destroyed();
/**
* Starts the worker thread
* @param name Static name of this thread
* @param prio Thread's priority
* @return True if started, false if an error occured
*/
bool start(const char* name = "ThreadedSource", Thread::Priority prio = Thread::Normal);
/**
* Stops and destroys the worker thread if running
*/
void stop();
/**
* Return a pointer to the worker thread
* @return Pointer to running worker thread or NULL
*/
Thread* thread() const;
/**
* Check if the data thread is running
* @return True if the data thread was started and is running
*/
bool running() const;
protected:
/**
* Threaded Source constructor
* @param format Name of the data format, default "slin" (Signed Linear)
*/
inline explicit ThreadedSource(const char* format = "slin")
: DataSource(format), m_thread(0)
{ }
/**
* The worker method. You have to reimplement it as you need
*/
virtual void run() = 0;
/**
* The cleanup after thread method, deletes the source if already
* dereferenced and set for asynchronous deletion
*/
virtual void cleanup();
/**
* Check if the calling thread should keep looping the worker method
* @param runConsumers True to keep running as long consumers are attached
* @return True if the calling thread should remain in the run() method
*/
bool looping(bool runConsumers = false) const;
private:
ThreadedSourcePrivate* m_thread;
};
/**
* The DataTranslator holds a translator (codec) capable of unidirectional
* conversion of data from one type to another.
* @short An unidirectional data translator (codec)
*/
class YATE_API DataTranslator : public DataConsumer
{
friend class TranslatorFactory;
public:
/**
* Construct a data translator.
* @param sFormat Name of the source format (data received from the consumer)
* @param dFormat Name of the destination format (data supplied to the source)
*/
DataTranslator(const char* sFormat, const char* dFormat);
/**
* Creates a data translator from an existing source,
* does not increment the source's reference counter.
* @param sFormat Name of the source format (data received from the consumer)
* @param source Optional pointer to a DataSource object
*/
explicit DataTranslator(const char* sFormat, DataSource* source = 0);
/**
* Destroys the translator and its source
*/
~DataTranslator();
/**
* Get a pointer to a derived class given that class name
* @param name Name of the class we are asking for
* @return Pointer to the requested class or NULL if this object doesn't implement it
*/
virtual void* getObject(const String& name) const;
/**
* Check if the data translator has a valid source
* @return True if still valid, false if node should be removed
*/
virtual bool valid() const
{ return m_tsource && m_tsource->valid(); }
/**
* Get the data source of a translator object
* @return A pointer to the DataSource object or NULL
*/
virtual DataSource* getTransSource() const
{ return m_tsource; }
/**
* Get the first translator from a chain
* @return Pointer to the first translator in a chain
*/
DataTranslator* getFirstTranslator();
/**
* Constant version to get the first translator from a chain
* @return Pointer to the first translator in a chain
*/
const DataTranslator* getFirstTranslator() const;
/**
* Get a list of formats supported for a given output format.
* @param dFormat Name of destination format
* @param maxCost Maximum cost of candidates to consider, -1 to accept all
* @param maxLen Maximum length of codec chains to consider, 0 to accept all
* @param lst Initial list, will append to it if not empty
* @return List of source format names, must be freed by the caller
*/
static ObjList* srcFormats(const DataFormat& dFormat = "slin", int maxCost = -1, unsigned int maxLen = 0, ObjList* lst = 0);
/**
* Get a list of formats supported for a given input format
* @param sFormat Name of source format
* @param maxCost Maximum cost of candidates to consider, -1 to accept all
* @param maxLen Maximum length of codec chains to consider, 0 to accept all
* @param lst Initial list, will append to it if not empty
* @return List of destination format names, must be freed by the caller
*/
static ObjList* destFormats(const DataFormat& sFormat = "slin", int maxCost = -1, unsigned int maxLen = 0, ObjList* lst = 0);