mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
247 lines
8.5 KiB
247 lines
8.5 KiB
/*
|
|
* Copyright (C) 2002-2003 Fhg Fokus
|
|
*
|
|
* This file is part of SEMS, a free SIP media server.
|
|
*
|
|
* SEMS 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 released under
|
|
* the GPL with the additional exemption that compiling, linking,
|
|
* and/or using OpenSSL is allowed.
|
|
*
|
|
* For a license to use the SEMS software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* SEMS 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
|
|
*/
|
|
/** @file AmMediaProcessor.h */
|
|
#ifndef _AmMediaProcessor_h_
|
|
#define _AmMediaProcessor_h_
|
|
|
|
#include "AmEventQueue.h"
|
|
#include "amci/amci.h" // AUDIO_BUFFER_SIZE
|
|
|
|
#include <set>
|
|
using std::set;
|
|
#include <map>
|
|
|
|
struct SchedRequest;
|
|
|
|
/** Interface for basic media session processing.
|
|
*
|
|
* Media processor stores set of objects implementing this interface and
|
|
* periodically triggers media processing on each of them.
|
|
*
|
|
* First it calls readStreams() method on all managed media sessions to read
|
|
* from all streams first and then calls writeStreams() to send data out in all
|
|
* these sessions.
|
|
*
|
|
* Once audio processing of all media sessions is done, media processor walks
|
|
* through them once more and calls processDtmfEvents() on them to handle DTMF
|
|
* events detected when reading data from media streams.
|
|
*/
|
|
|
|
class AmMediaSession
|
|
{
|
|
private:
|
|
AmCondition processing_media;
|
|
|
|
public:
|
|
AmMediaSession(): processing_media(false) { }
|
|
virtual ~AmMediaSession() { }
|
|
|
|
/** Read from all media streams.
|
|
*
|
|
* To preserve current media processing scheme it is needed to read from all
|
|
* streams first and then write to them. This can be important for example
|
|
* in case of conferences where we need to have media from all streams ready
|
|
* for mixing them.
|
|
*
|
|
* So the AmMediaProcessorThread first calls readStreams on all sessions and
|
|
* then writeStreams on all sessions.
|
|
*
|
|
* \param ts timestamp for which the processing is currently running
|
|
*
|
|
* \param buffer multi-purpose space given from outside (AmMediaProcessorThread)
|
|
*
|
|
* Buffer given as parametr is usable for anything, originally was intended for data
|
|
* read from one stream before putting to another stream.
|
|
*
|
|
* The reason for having this buffer as parameter is that buffer size for
|
|
* audio processing is quite large (2K here) and thus allocating it on stack
|
|
* on some architectures may be problematic.
|
|
*
|
|
* On other hand having the buffer dynamically allocated for each media
|
|
* session would significantly increase memory consumption per call.
|
|
*
|
|
* So for now it seems to be the simplest way just to give the buffer as
|
|
* parameter from AmMediaProcessorThread and reuse it in all sessions handled
|
|
* by this thread (processing is done sequentially one session after another). */
|
|
virtual int readStreams(unsigned long long ts, unsigned char *buffer) = 0;
|
|
|
|
/** Write to all media streams.
|
|
*
|
|
* For the meaning of parameters see description of readStreams() method. */
|
|
virtual int writeStreams(unsigned long long ts, unsigned char *buffer) = 0;
|
|
|
|
/** Handle events in DTMF event queue.
|
|
*
|
|
* DTMF events should be detected from RTP stream when reading data (see
|
|
* readStreams()) and put into an event queue for later processing to avoid
|
|
* blocking of audio processing for too long time.
|
|
*
|
|
* This DTMF event queue should be processed then, within this method, which
|
|
* is triggered by AmMediaProcessorThread once reading/writing from media
|
|
* streams is finished. */
|
|
virtual void processDtmfEvents() = 0;
|
|
|
|
/** Reset all media processing elements.
|
|
*
|
|
* Called as part of cleanup when removing session from media processor upon
|
|
* an processing error (either readStreams() or writeStreams() returning
|
|
* error). */
|
|
virtual void clearAudio() = 0;
|
|
|
|
/** Reset timeouts of all RTP streams related to this media session.
|
|
*
|
|
* Called during initialization when session starts to be processed by media
|
|
* processor. */
|
|
virtual void clearRTPTimeout() = 0;
|
|
|
|
/** Callback function called when a session is added to media processor.
|
|
*
|
|
* Default implementation sets internal variable usable for detection if the
|
|
* object is in use by AmMediaProcessorThread. */
|
|
virtual void onMediaProcessingStarted() { processing_media.set(true); }
|
|
|
|
/* Callback function called when a session is removed from media processor.
|
|
*
|
|
* Default implementation sets internal variable usable for detection if the
|
|
* object is in use by AmMediaProcessorThread. */
|
|
virtual void onMediaProcessingTerminated() { processing_media.set(false); }
|
|
|
|
/** Indicates if the object is used by media processor.
|
|
*
|
|
* Returns value of internal variable for distinguishing if the object is
|
|
* already added into media processor. It should be avoided to insert one
|
|
* session into media processor multiple times.
|
|
*
|
|
* Note that using default implementation of onMediaProcessingStarted and
|
|
* onMediaProcessingTerminated is required for proper function. */
|
|
virtual bool isProcessingMedia() { return processing_media.get(); }
|
|
|
|
/** Indicates if the object is used by media processor.
|
|
*
|
|
* Seems to be duplicate to isProcessingMedia(). It was kept to reduce
|
|
* number of changes in existing code. */
|
|
virtual bool isDetached() { return !isProcessingMedia(); }
|
|
};
|
|
|
|
/**
|
|
* \brief Media processing thread
|
|
*
|
|
* This class implements a media processing thread.
|
|
* It processes the media and triggers the sending of RTP
|
|
* of all sessions added to it.
|
|
*/
|
|
class AmMediaProcessorThread :
|
|
public AmThread,
|
|
public AmEventHandler
|
|
{
|
|
AmEventQueue events;
|
|
unsigned char buffer[AUDIO_BUFFER_SIZE];
|
|
set<AmMediaSession*> sessions;
|
|
|
|
void processAudio(unsigned long long ts);
|
|
/**
|
|
* Process pending DTMF events
|
|
*/
|
|
void processDtmfEvents();
|
|
|
|
// AmThread interface
|
|
void run();
|
|
void on_stop();
|
|
const char *identify() { return "media processor"; }
|
|
|
|
// AmEventHandler interface
|
|
void process(AmEvent* e);
|
|
public:
|
|
AmMediaProcessorThread();
|
|
~AmMediaProcessorThread();
|
|
|
|
inline void postRequest(SchedRequest* sr);
|
|
|
|
unsigned int getLoad();
|
|
};
|
|
|
|
/**
|
|
* \brief Media processing thread manager
|
|
*
|
|
* This class implements the manager that assigns and removes
|
|
* the Sessions to the various \ref MediaProcessorThreads,
|
|
* according to their call group. This class contains the API
|
|
* for the MediaProcessor.
|
|
*/
|
|
class AmMediaProcessor
|
|
{
|
|
static AmMediaProcessor* _instance;
|
|
|
|
unsigned int num_threads;
|
|
AmMediaProcessorThread** threads;
|
|
|
|
std::map<string, unsigned int> callgroup2thread;
|
|
std::multimap<string, AmMediaSession*> callgroupmembers;
|
|
std::map<AmMediaSession*, string> session2callgroup;
|
|
AmMutex group_mut;
|
|
|
|
AmMediaProcessor();
|
|
~AmMediaProcessor();
|
|
|
|
void removeFromProcessor(AmMediaSession* s, unsigned int r_type);
|
|
public:
|
|
/**
|
|
* InsertSession : inserts the session to the processor
|
|
* RemoveSession : remove the session from the processor
|
|
* SoftRemoveSession : remove the session from the processor but leave it attached
|
|
* ClearSession : remove the session from processor and clear audio
|
|
*/
|
|
enum { InsertSession, RemoveSession, SoftRemoveSession, ClearSession };
|
|
|
|
static AmMediaProcessor* instance();
|
|
|
|
void init();
|
|
/** Add session s to processor */
|
|
void addSession(AmMediaSession* s, const string& callgroup);
|
|
/** Remove session s from processor */
|
|
void removeSession(AmMediaSession* s);
|
|
/** Remove session s from processor and clear its audio */
|
|
void clearSession(AmMediaSession* s);
|
|
/** Remove session s from processor but don't signal that to the session */
|
|
void softRemoveSession(AmMediaSession* s);
|
|
/** Change the callgroup of a session (use with caution) */
|
|
void changeCallgroup(AmMediaSession* s,
|
|
const string& new_callgroup);
|
|
|
|
void stop();
|
|
static void dispose();
|
|
};
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|