opalmixer.h

Go to the documentation of this file.
00001 /*
00002  * opalmixer.h
00003  *
00004  * OPAL media mixers
00005  *
00006  * Open Phone Abstraction Library (OPAL)
00007  * Formally known as the Open H323 project.
00008  *
00009  * Copyright (C) 2007 Post Increment
00010  *
00011  * The contents of this file are subject to the Mozilla Public License
00012  * Version 1.0 (the "License"); you may not use this file except in
00013  * compliance with the License. You may obtain a copy of the License at
00014  * http://www.mozilla.org/MPL/
00015  *
00016  * Software distributed under the License is distributed on an "AS IS"
00017  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00018  * the License for the specific language governing rights and limitations
00019  * under the License.
00020  *
00021  * The Original Code is Open Phone Abstraction Library.
00022  *
00023  * The Initial Developer of the Original Code is Post Increment
00024  *
00025  * Contributor(s): Craig Southeren (craigs@postincrement.com)
00026  *                 Robert Jongbloed (robertj@voxlucida.com.au)
00027  *
00028  * $Revision: 24856 $
00029  * $Author: rjongbloed $
00030  * $Date: 2010-11-01 22:12:28 -0500 (Mon, 01 Nov 2010) $
00031  */
00032 
00033 
00034 #ifndef OPAL_OPAL_OPALMIXER_H
00035 #define OPAL_OPAL_OPALMIXER_H
00036 
00037 #ifndef _PTLIB_H
00038 #include <ptlib.h>
00039 #endif
00040 
00041 #include <opal/buildopts.h>
00042 
00043 #include <queue>
00044 
00045 #include <opal/localep.h>
00046 #include <codec/vidcodec.h>
00047 
00048 
00049 class RTP_DataFrame;
00050 class OpalJitterBuffer;
00051 
00052 
00053 //#define OPAL_MIXER_AUDIO_DEBUG 1
00054 
00055 
00056 #define OPAL_OPT_LISTEN_ONLY "Listen-Only" 
00057 
00058 
00060 
00070 class OpalBaseMixer
00071 {
00072   public:
00073     OpalBaseMixer(
00074       bool pushThread,    
00075       unsigned periodMS,  
00076       unsigned periodTS   
00077     );
00078 
00079     virtual ~OpalBaseMixer();
00080 
00081     typedef PString Key_T;
00082 
00085     virtual bool AddStream(
00086       const Key_T & key   
00087     );
00088 
00091     virtual void RemoveStream(
00092       const Key_T & key   
00093     );
00094 
00097     virtual void RemoveAllStreams();
00098 
00104     virtual bool WriteStream(
00105       const Key_T & key,          
00106       const RTP_DataFrame & input 
00107     );
00108 
00118     virtual RTP_DataFrame * ReadMixed();
00119     virtual bool ReadMixed(RTP_DataFrame & mixed);
00120 
00131     virtual bool OnMixed(
00132       RTP_DataFrame * & mixed   
00133     );
00134 
00138     void StartPushThread();
00139 
00144     void StopPushThread(bool lock = true);
00145 
00148     unsigned GetPeriodTS() const { return m_periodTS; }
00149 
00150   protected:
00151     struct Stream {
00152       virtual ~Stream() { }
00153       virtual void QueuePacket(const RTP_DataFrame & rtp) = 0;
00154       queue<RTP_DataFrame> m_queue;
00155     };
00156     typedef std::map<Key_T, Stream *> StreamMap_T;
00157 
00158     virtual Stream * CreateStream() = 0;
00159     virtual bool MixStreams(RTP_DataFrame & frame) = 0;
00160     virtual size_t GetOutputSize() const = 0;
00161 
00162     virtual bool OnPush();
00163     void PushThreadMain();
00164 
00165     bool      m_pushThread;      // true if to use a thread to push data out
00166     unsigned  m_periodMS;        // Mixing interval in milliseconds
00167     unsigned  m_periodTS;        // Mixing interval in timestamp units
00168 
00169     StreamMap_T     m_inputStreams;     // Map of key to stream for input RTP frame queues
00170     unsigned        m_outputTimestamp;  // RTP timestamp for output data
00171     RTP_DataFrame * m_pushFrame;        // Cached frame for pushing RTP
00172     PThread *       m_workerThread;     // reader thread handle
00173     bool            m_threadRunning;    // used to stop reader thread
00174     PMutex          m_mutex;            // mutex for list of streams and thread handle
00175 };
00176 
00178 
00187 class OpalAudioMixer : public OpalBaseMixer
00188 {
00189   public:
00190     OpalAudioMixer(
00191       bool stereo = false,    
00192       unsigned sampleRate = OpalMediaFormat::AudioClockRate, 
00193       bool pushThread = true, 
00194       unsigned period = 10    
00195     );
00196 
00197     ~OpalAudioMixer() { StopPushThread(); }
00198 
00201     virtual void RemoveStream(
00202       const Key_T & key   
00203     );
00204 
00207     virtual void RemoveAllStreams();
00208 
00211     bool IsStereo() const { return m_stereo; }
00212 
00215     unsigned GetSampleRate() const { return m_sampleRate; }
00216 
00223     bool SetSampleRate(
00224       unsigned rate   
00225     );
00226 
00233     bool SetJitterBufferSize(
00234       const Key_T & key,       
00235       unsigned minJitterDelay, 
00236       unsigned maxJitterDelay  
00237     );
00238 
00239   protected:
00240     struct AudioStream : public Stream
00241     {
00242       AudioStream(OpalAudioMixer & mixer);
00243       ~AudioStream();
00244 
00245       virtual void QueuePacket(const RTP_DataFrame & rtp);
00246       const short * GetAudioDataPtr();
00247 
00248       OpalAudioMixer   & m_mixer;
00249       OpalJitterBuffer * m_jitter;
00250       unsigned           m_nextTimestamp;
00251       PShortArray        m_cacheSamples;
00252       size_t             m_samplesUsed;
00253     };
00254 
00255     virtual Stream * CreateStream();
00256     virtual bool MixStreams(RTP_DataFrame & frame);
00257     virtual size_t GetOutputSize() const;
00258 
00259     void PreMixStreams();
00260     void MixStereo(RTP_DataFrame & frame);
00261     void MixAdditive(RTP_DataFrame & frame, const short * audioToSubtract);
00262 
00263   protected:
00264     bool     m_stereo;
00265     unsigned m_sampleRate;
00266 
00267     AudioStream    * m_left;
00268     AudioStream    * m_right;
00269     std::vector<int> m_mixedAudio;
00270 };
00271 
00272 
00274 
00275 #if OPAL_VIDEO
00276 
00283 class OpalVideoMixer : public OpalBaseMixer
00284 {
00285   public:
00286     enum Styles {
00287       eSideBySideLetterbox, 
00291       eSideBySideScaled,    
00295       eStackedPillarbox,    
00299       eStackedScaled,       
00303       eGrid,                
00305     };
00306 
00307     OpalVideoMixer(
00308       Styles style,           
00309       unsigned width,         
00310       unsigned height,        
00311       unsigned rate = 15,     
00312       bool pushThread = true  
00313     );
00314 
00315     ~OpalVideoMixer() { StopPushThread(); }
00316 
00319     unsigned GetFrameWidth() const { return m_width; }
00320 
00323     unsigned GetFrameHeight() const { return m_height; }
00324 
00327     unsigned GetFrameRate() const { return 1000/m_periodMS; }
00328 
00332     bool SetFrameRate(
00333       unsigned rate   // New frames per second.
00334     );
00335 
00339     bool SetFrameSize(
00340       unsigned width,   
00341       unsigned height   
00342     );
00343 
00344   protected:
00345     struct VideoStream : public Stream
00346     {
00347       VideoStream(OpalVideoMixer & mixer);
00348       virtual void QueuePacket(const RTP_DataFrame & rtp);
00349       void InsertVideoFrame(unsigned x, unsigned y, unsigned w, unsigned h);
00350 
00351       OpalVideoMixer & m_mixer;
00352     };
00353 
00354     friend struct VideoStream;
00355 
00356     virtual Stream * CreateStream();
00357     virtual bool MixStreams(RTP_DataFrame & frame);
00358     virtual size_t GetOutputSize() const;
00359 
00360   protected:
00361     Styles     m_style;
00362     unsigned   m_width, m_height;
00363     BYTE       m_bgFillRed,m_bgFillGreen,m_bgFillBlue;
00364 
00365     PBYTEArray m_frameStore;
00366     size_t     m_lastStreamCount;
00367 };
00368 
00369 #endif // OPAL_VIDEO
00370 
00371 
00373 
00374 
00379 struct OpalMixerNodeInfo
00380 {
00381   OpalMixerNodeInfo(const char * name = NULL)
00382     : m_name(name)
00383     , m_listenOnly(false)
00384     , m_sampleRate(OpalMediaFormat::AudioClockRate)
00385 #if OPAL_VIDEO
00386     , m_audioOnly(false)
00387     , m_style(OpalVideoMixer::eGrid)
00388     , m_width(PVideoFrameInfo::CIFWidth)
00389     , m_height(PVideoFrameInfo::CIFHeight)
00390     , m_rate(15)
00391 #endif
00392     , m_mediaPassThru(false)
00393   { }
00394 
00395   virtual ~OpalMixerNodeInfo() { }
00396 
00397   virtual OpalMixerNodeInfo * Clone() const { return new OpalMixerNodeInfo(*this); }
00398 
00399   PString  m_name;                
00400   bool     m_listenOnly;          
00401   unsigned m_sampleRate;          
00402 #if OPAL_VIDEO
00403   bool     m_audioOnly;           
00404   OpalVideoMixer::Styles m_style; 
00405   unsigned m_width;               
00406   unsigned m_height;              
00407   unsigned m_rate;                
00408 #endif
00409   bool     m_mediaPassThru;       
00411 };
00412 
00413 
00415 
00416 class OpalMixerNode;
00417 
00418 
00423 class OpalMixerNodeManager : public PObject
00424 {
00425     PCLASSINFO(OpalMixerNodeManager, PObject);
00426   public:
00431     OpalMixerNodeManager();
00432 
00436         virtual ~OpalMixerNodeManager();
00437 
00440     virtual void ShutDown();
00441 
00447     virtual PBoolean GarbageCollection();
00449 
00458     virtual OpalMixerNode * CreateNode(
00459       OpalMixerNodeInfo * info 
00460     );
00461 
00467     virtual PSafePtr<OpalMixerNode> AddNode(
00468       OpalMixerNodeInfo * info 
00469     );
00470 
00473     void AddNode(OpalMixerNode * node);
00474 
00478     PSafePtr<OpalMixerNode> GetFirstNode(
00479       PSafetyMode mode = PSafeReference 
00480     ) const { return PSafePtr<OpalMixerNode>(m_nodesByUID, mode); }
00481 
00485     virtual PSafePtr<OpalMixerNode> FindNode(
00486       const PString & name,             
00487       PSafetyMode mode = PSafeReference 
00488     );
00489 
00494     virtual void RemoveNode(
00495       OpalMixerNode & node
00496     );
00497 
00500     void AddNodeName(
00501       PString name,        
00502       OpalMixerNode * node 
00503     );
00504 
00507     void RemoveNodeName(
00508       PString name        
00509     );
00510 
00514     void RemoveNodeNames(
00515       PStringList names   
00516     );
00518 
00519   protected:
00520     PSafeDictionary<PGloballyUniqueID, OpalMixerNode> m_nodesByUID;
00521     PDictionary<PString, OpalMixerNode>               m_nodesByName;
00522 };
00523 
00524 
00526 
00527 class OpalMixerConnection;
00528 
00533 class OpalMixerEndPoint : public OpalLocalEndPoint
00534 {
00535     PCLASSINFO(OpalMixerEndPoint, OpalLocalEndPoint);
00536   public:
00541     OpalMixerEndPoint(
00542       OpalManager & manager,  
00543       const char * prefix     
00544     );
00545 
00548     ~OpalMixerEndPoint();
00549 
00554     virtual void ShutDown();
00556 
00569     virtual OpalMediaFormatList GetMediaFormats() const;
00570 
00600     virtual PSafePtr<OpalConnection> MakeConnection(
00601       OpalCall & call,           
00602       const PString & party,     
00603       void * userData = NULL,    
00604       unsigned options = 0,      
00605       OpalConnection::StringOptions * stringOptions = NULL 
00606     );
00607 
00612     virtual PBoolean GarbageCollection();
00614 
00623     PSafePtr<OpalMixerConnection> GetMixerConnectionWithLock(
00624       const PString & token,     
00625       PSafetyMode mode = PSafeReadWrite 
00626     ) { return GetConnectionWithLockAs<OpalMixerConnection>(token, mode); }
00627 
00631     virtual OpalMixerConnection * CreateConnection(
00632       PSafePtr<OpalMixerNode> node, 
00633       OpalCall & call,              
00634       void * userData,              
00635       unsigned options,             
00636       OpalConnection::StringOptions * stringOptions 
00637     );
00639 
00647     PSafePtr<OpalMixerNode> AddNode(
00648       OpalMixerNodeInfo * info 
00649     );
00650 
00657     virtual OpalMixerNode * CreateNode(
00658       OpalMixerNodeInfo * info 
00659     );
00660 
00664     PSafePtr<OpalMixerNode> GetFirstNode(
00665       PSafetyMode mode = PSafeReference 
00666     ) const { return m_nodeManager.GetFirstNode(mode); }
00667 
00671     PSafePtr<OpalMixerNode> FindNode(
00672       const PString & name,             
00673       PSafetyMode mode = PSafeReference 
00674     ) { return m_nodeManager.FindNode(name, mode); }
00675 
00680     void RemoveNode(
00681       OpalMixerNode & node 
00682     ) { m_nodeManager.RemoveNode(node); }
00684 
00699     void SetAdHocNodeInfo(
00700       const OpalMixerNodeInfo & info
00701     );
00702     void SetAdHocNodeInfo(
00703       OpalMixerNodeInfo * info
00704     );
00705 
00717     OpalMixerNodeInfo * GetAdHocNodeInfo() { return m_adHocNodeInfo; }
00718 
00721     const OpalMixerNodeManager & GetNodeManager() const { return m_nodeManager; }
00722           OpalMixerNodeManager & GetNodeManager()       { return m_nodeManager; }
00724 
00725   protected:
00726     OpalMixerNodeInfo  * m_adHocNodeInfo;
00727     OpalMixerNodeManager m_nodeManager;
00728 };
00729 
00730 
00732 
00735 class OpalMixerConnection : public OpalLocalConnection
00736 {
00737     PCLASSINFO(OpalMixerConnection, OpalLocalConnection);
00738   public:
00743     OpalMixerConnection(
00744       PSafePtr<OpalMixerNode> node, 
00745       OpalCall & call,              
00746       OpalMixerEndPoint & endpoint, 
00747       void * userData,              
00748       unsigned options = 0,         
00749       OpalConnection::StringOptions * stringOptions = NULL 
00750     );
00751 
00754     ~OpalMixerConnection();
00756 
00776     virtual void OnReleased();
00777 
00784     virtual OpalMediaFormatList GetMediaFormats() const;
00785 
00800     virtual OpalMediaStream * CreateMediaStream(
00801       const OpalMediaFormat & mediaFormat, 
00802       unsigned sessionID,                  
00803       PBoolean isSource                    
00804     );
00805 
00808     virtual void OnStartMediaPatch(
00809       OpalMediaPatch & patch    
00810     );
00811 
00813     virtual void OnApplyStringOptions();
00814 
00821     virtual PBoolean SendUserInputString(
00822       const PString & value                   
00823     );
00824 
00841     virtual PBoolean SendUserInputTone(
00842       char tone,        
00843       unsigned duration = 0  
00844     );
00846 
00851     void SetListenOnly(
00852       bool listenOnly   
00853     );
00854 
00857     bool GetListenOnly() const { return m_listenOnly; }
00858 
00861     PSafePtr<OpalMixerNode> GetNode() const { return m_node; }
00863 
00864   protected:
00865     OpalMixerEndPoint     & m_endpoint;
00866     PSafePtr<OpalMixerNode> m_node;
00867     bool                    m_listenOnly;
00868 };
00869 
00870 
00874 class OpalMixerMediaStream : public OpalMediaStream
00875 {
00876     PCLASSINFO(OpalMixerMediaStream, OpalMediaStream);
00877   public:
00882     OpalMixerMediaStream(
00883       OpalConnection & conn,               
00884       const OpalMediaFormat & mediaFormat, 
00885       unsigned sessionID,                  
00886       bool isSource,                       
00887       PSafePtr<OpalMixerNode> node,        
00888       bool listenOnly                      
00889     );
00890 
00893     ~OpalMixerMediaStream();
00895 
00900     virtual PBoolean Open();
00901 
00904     virtual PBoolean Close();
00905 
00911     virtual PBoolean WritePacket(
00912       RTP_DataFrame & packet
00913     );
00914 
00918     virtual PBoolean IsSynchronous() const;
00919 
00930     virtual PBoolean RequiresPatchThread() const;
00931 
00939     virtual bool EnableJitterBuffer(bool enab = true) const;
00941 
00946     PSafePtr<OpalMixerNode> GetNode() { return m_node; }
00948 
00949   protected:
00950     PSafePtr<OpalMixerNode> m_node;
00951 #if OPAL_VIDEO
00952     bool m_video;
00953 #endif
00954 };
00955 
00956 
00960 class OpalMixerNode : public PSafeObject
00961 {
00962     PCLASSINFO(OpalMixerNode, PSafeObject);
00963   public:
00968     OpalMixerNode(
00969       OpalMixerNodeManager & manager, 
00970       OpalMixerNodeInfo * info        
00971     );
00972     OpalMixerNode(
00973       OpalMixerEndPoint & endpoint,   
00974       OpalMixerNodeInfo * info        
00975     );
00976 
00979     ~OpalMixerNode();
00980 
00985     void ShutDown();
00987 
00994     void PrintOn(
00995       ostream & strm    
00996     ) const;
00998 
01003     void AttachConnection(
01004       OpalConnection * connection  
01005     );
01006 
01009     void DetachConnection(
01010       OpalConnection * connection  
01011     );
01012 
01015     bool AttachStream(
01016       OpalMixerMediaStream * stream     
01017     );
01018 
01021     void DetachStream(
01022       OpalMixerMediaStream * stream     
01023     );
01024 
01027     void UseMediaPassThrough(
01028       unsigned sessionID,                 
01029       OpalConnection * connection = NULL  
01030     );
01031 
01038     bool SetJitterBufferSize(
01039       const OpalBaseMixer::Key_T & key, 
01040       unsigned minJitterDelay,          
01041       unsigned maxJitterDelay           
01042     ) { return m_audioMixer.SetJitterBufferSize(key, minJitterDelay, maxJitterDelay); }
01043 
01046     bool WriteAudio(
01047       const OpalBaseMixer::Key_T & key, 
01048       const RTP_DataFrame & input       
01049     ) { return m_audioMixer.WriteStream(key, input); }
01050 
01051 #if OPAL_VIDEO
01052 
01054     bool WriteVideo(
01055       const OpalBaseMixer::Key_T & key, 
01056       const RTP_DataFrame & input       
01057     ) { return m_videoMixer.WriteStream(key, input); }
01058 #endif // OPAL_VIDEO
01059 
01062     virtual void BroadcastUserInput(
01063       const OpalConnection * connection,      
01064       const PString & value                   
01065     );
01067 
01072     const PGloballyUniqueID & GetGUID() const { return m_guid; }
01073 
01076     const PStringList & GetNames() const { return m_names; }
01077 
01080     void AddName(
01081       const PString & name
01082     );
01083 
01086     void RemoveName(
01087       const PString & name
01088     );
01089 
01095     PINDEX GetConnectionCount() const { return m_connections.GetSize(); }
01096 
01099     template <class Subclass>
01100     PSafePtr<Subclass> GetFirstConnectionAs(
01101       PSafetyMode mode = PSafeReference
01102     ) const { return PSafePtr<Subclass>(m_connections, mode); }
01103 
01106     PSafePtr<OpalConnection> GetFirstConnection(
01107       PSafetyMode mode = PSafeReference
01108     ) const { return GetFirstConnectionAs<OpalConnection>(mode); }
01109 
01112     const OpalMixerNodeInfo & GetNodeInfo() { return *m_info; }
01113 
01116     const PTime & GetCreationTime() const { return m_creationTime; }
01118 
01119   protected:
01120     void Construct();
01121 
01122     OpalMixerNodeManager & m_manager;
01123     PGloballyUniqueID      m_guid;
01124     PStringList            m_names;
01125     OpalMixerNodeInfo    * m_info;
01126     PTime                  m_creationTime;
01127 
01128     PSafeList<OpalConnection> m_connections;
01129 
01130     struct MediaMixer
01131     {
01132       MediaMixer();
01133 
01134       PSafeList<OpalMixerMediaStream> m_outputStreams;
01135     };
01136 
01137     struct AudioMixer : public OpalAudioMixer, public MediaMixer
01138     {
01139       AudioMixer(const OpalMixerNodeInfo & info);
01140       ~AudioMixer();
01141 
01142       virtual bool OnPush();
01143 
01144       struct CachedAudio {
01145         CachedAudio();
01146         ~CachedAudio();
01147         enum { Collecting, Collected, Completed } m_state;
01148         RTP_DataFrame    m_raw;
01149         RTP_DataFrame    m_encoded;
01150         OpalTranscoder * m_transcoder;
01151       };
01152       std::map<PString, CachedAudio> m_cache;
01153 
01154       void PushOne(
01155         OpalMixerMediaStream & stream,
01156         CachedAudio & cache,
01157         const short * audioToSubtract
01158       );
01159 #ifdef OPAL_MIXER_AUDIO_DEBUG
01160       class PAudioMixerDebug * m_audioDebug;
01161 #endif
01162     };
01163     AudioMixer m_audioMixer;
01164 
01165 #if OPAL_VIDEO
01166     struct VideoMixer : public OpalVideoMixer, public MediaMixer
01167     {
01168       VideoMixer(const OpalMixerNodeInfo & info);
01169       ~VideoMixer();
01170 
01171       virtual bool OnMixed(RTP_DataFrame * & output);
01172 
01173       PDictionary<PString, OpalTranscoder> m_transcoders;
01174     };
01175     VideoMixer m_videoMixer;
01176 #endif // OPAL_VIDEO
01177 };
01178 
01179 
01180 #endif // OPAL_OPAL_OPAL_MIXER
01181 
01182 

Generated on Sun Nov 21 20:20:50 2010 for OPAL by  doxygen 1.4.7