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: 23052 $
00029  * $Author: rjongbloed $
00030  * $Date: 2009-07-03 13:57:32 +0000 (Fri, 03 Jul 2009) $
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 
00057 
00067 class OpalBaseMixer
00068 {
00069   public:
00070     OpalBaseMixer(
00071       bool pushThread,    
00072       unsigned periodMS,  
00073       unsigned periodTS   
00074     );
00075 
00076     virtual ~OpalBaseMixer();
00077 
00078     typedef PString Key_T;
00079 
00082     virtual bool AddStream(
00083       const Key_T & key   
00084     );
00085 
00088     virtual void RemoveStream(
00089       const Key_T & key   
00090     );
00091 
00094     virtual void RemoveAllStreams();
00095 
00101     virtual bool WriteStream(
00102       const Key_T & key,          
00103       const RTP_DataFrame & input 
00104     );
00105 
00115     virtual RTP_DataFrame * ReadMixed();
00116     virtual bool ReadMixed(RTP_DataFrame & mixed);
00117 
00128     virtual bool OnMixed(
00129       RTP_DataFrame * & mixed   
00130     );
00131 
00135     void StartPushThread();
00136 
00141     void StopPushThread(bool lock = true);
00142 
00145     unsigned GetPeriodTS() const { return m_periodTS; }
00146 
00147   protected:
00148     struct Stream {
00149       virtual ~Stream() { }
00150       virtual void QueuePacket(const RTP_DataFrame & rtp) = 0;
00151       queue<RTP_DataFrame> m_queue;
00152     };
00153     typedef std::map<Key_T, Stream *> StreamMap_T;
00154 
00155     virtual Stream * CreateStream() = 0;
00156     virtual bool MixStreams(RTP_DataFrame & frame) = 0;
00157     virtual size_t GetOutputSize() const = 0;
00158 
00159     virtual bool OnPush();
00160     void PushThreadMain();
00161 
00162     bool      m_pushThread;      // true if to use a thread to push data out
00163     unsigned  m_periodMS;        // Mixing interval in milliseconds
00164     unsigned  m_periodTS;        // Mixing interval in timestamp units
00165 
00166     StreamMap_T     m_inputStreams;     // Map of key to stream for input RTP frame queues
00167     unsigned        m_outputTimestamp;  // RTP timestamp for output data
00168     RTP_DataFrame * m_pushFrame;        // Cached frame for pushing RTP
00169     PThread *       m_workerThread;     // reader thread handle
00170     bool            m_threadRunning;    // used to stop reader thread
00171     PMutex          m_mutex;            // mutex for list of streams and thread handle
00172 };
00173 
00175 
00184 class OpalAudioMixer : public OpalBaseMixer
00185 {
00186   public:
00187     OpalAudioMixer(
00188       bool stereo = false,    
00189       unsigned sampleRate = OpalMediaFormat::AudioClockRate, 
00190       bool pushThread = true, 
00191       unsigned period = 10    
00192     );
00193 
00194     ~OpalAudioMixer() { StopPushThread(); }
00195 
00198     virtual void RemoveStream(
00199       const Key_T & key   
00200     );
00201 
00204     virtual void RemoveAllStreams();
00205 
00208     bool IsStereo() const { return m_stereo; }
00209 
00212     unsigned GetSampleRate() const { return m_sampleRate; }
00213 
00220     bool SetSampleRate(
00221       unsigned rate   
00222     );
00223 
00230     bool SetJitterBufferSize(
00231       const Key_T & key,       
00232       unsigned minJitterDelay, 
00233       unsigned maxJitterDelay  
00234     );
00235 
00236   protected:
00237     struct AudioStream : public Stream
00238     {
00239       AudioStream(OpalAudioMixer & mixer);
00240       ~AudioStream();
00241 
00242       virtual void QueuePacket(const RTP_DataFrame & rtp);
00243       const short * GetAudioDataPtr();
00244 
00245       OpalAudioMixer   & m_mixer;
00246       OpalJitterBuffer * m_jitter;
00247       unsigned           m_nextTimestamp;
00248       PShortArray        m_cacheSamples;
00249       size_t             m_samplesUsed;
00250     };
00251 
00252     virtual Stream * CreateStream();
00253     virtual bool MixStreams(RTP_DataFrame & frame);
00254     virtual size_t GetOutputSize() const;
00255 
00256     void PreMixStreams();
00257     void MixStereo(RTP_DataFrame & frame);
00258     void MixAdditive(RTP_DataFrame & frame, const short * audioToSubtract);
00259 
00260   protected:
00261     bool     m_stereo;
00262     unsigned m_sampleRate;
00263 
00264     AudioStream    * m_left;
00265     AudioStream    * m_right;
00266     std::vector<int> m_mixedAudio;
00267 };
00268 
00269 
00271 
00272 #if OPAL_VIDEO
00273 
00280 class OpalVideoMixer : public OpalBaseMixer
00281 {
00282   public:
00283     enum Styles {
00284       eSideBySideLetterbox, 
00288       eSideBySideScaled,    
00292       eStackedPillarbox,    
00296       eStackedScaled,       
00300       eGrid,                
00302     };
00303 
00304     OpalVideoMixer(
00305       Styles style,           
00306       unsigned width,         
00307       unsigned height,        
00308       unsigned rate = 15,     
00309       bool pushThread = true  
00310     );
00311 
00312     ~OpalVideoMixer() { StopPushThread(); }
00313 
00316     unsigned GetFrameWidth() const { return m_width; }
00317 
00320     unsigned GetFrameHeight() const { return m_height; }
00321 
00324     unsigned GetFrameRate() const { return 1000/m_periodMS; }
00325 
00329     bool SetFrameRate(
00330       unsigned rate   // New frames per second.
00331     );
00332 
00336     bool SetFrameSize(
00337       unsigned width,   
00338       unsigned height   
00339     );
00340 
00341   protected:
00342     struct VideoStream : public Stream
00343     {
00344       VideoStream(OpalVideoMixer & mixer);
00345       virtual void QueuePacket(const RTP_DataFrame & rtp);
00346       void InsertVideoFrame(unsigned x, unsigned y, unsigned w, unsigned h);
00347 
00348       OpalVideoMixer     & m_mixer;
00349     };
00350 
00351     friend struct VideoStream;
00352 
00353     virtual Stream * CreateStream();
00354     virtual bool MixStreams(RTP_DataFrame & frame);
00355     virtual size_t GetOutputSize() const;
00356 
00357   protected:
00358     Styles     m_style;
00359     unsigned   m_width, m_height;
00360 
00361     PBYTEArray m_frameStore;
00362 };
00363 
00364 #endif // OPAL_VIDEO
00365 
00366 
00368 
00369 class OpalMixerConnection;
00370 class OpalMixerNode;
00371 
00372 
00373 struct OpalMixerNodeInfo
00374 {
00375   OpalMixerNodeInfo()
00376     : m_listenOnly(false)
00377     , m_sampleRate(OpalMediaFormat::AudioClockRate)
00378 #if OPAL_VIDEO
00379     , m_audioOnly(false)
00380     , m_style(OpalVideoMixer::eGrid)
00381     , m_width(PVideoFrameInfo::CIFWidth)
00382     , m_height(PVideoFrameInfo::CIFHeight)
00383     , m_rate(15)
00384 #endif
00385   { }
00386 
00387   virtual ~OpalMixerNodeInfo() { }
00388 
00389   virtual OpalMixerNodeInfo * Clone() const { return new OpalMixerNodeInfo(*this); }
00390 
00391   PString  m_name;
00392   bool     m_listenOnly;
00393   unsigned m_sampleRate;
00394 #if OPAL_VIDEO
00395   bool     m_audioOnly;
00396   OpalVideoMixer::Styles m_style;
00397   unsigned m_width;
00398   unsigned m_height;
00399   unsigned m_rate;
00400 #endif
00401 };
00402 
00403 
00408 class OpalMixerEndPoint : public OpalLocalEndPoint
00409 {
00410     PCLASSINFO(OpalMixerEndPoint, OpalLocalEndPoint);
00411   public:
00416     OpalMixerEndPoint(
00417       OpalManager & manager,  
00418       const char * prefix     
00419     );
00420 
00423     ~OpalMixerEndPoint();
00424 
00429     virtual void ShutDown();
00431 
00444     virtual OpalMediaFormatList GetMediaFormats() const;
00445 
00475     virtual PSafePtr<OpalConnection> MakeConnection(
00476       OpalCall & call,           
00477       const PString & party,     
00478       void * userData = NULL,    
00479       unsigned int options = 0,  
00480       OpalConnection::StringOptions * stringOptions  = NULL
00481     );
00482 
00487     virtual PBoolean GarbageCollection();
00489 
00498     PSafePtr<OpalMixerConnection> GetMixerConnectionWithLock(
00499       const PString & token,     
00500       PSafetyMode mode = PSafeReadWrite
00501     ) { return GetConnectionWithLockAs<OpalMixerConnection>(token, mode); }
00502 
00506     virtual OpalMixerConnection * CreateConnection(
00507       PSafePtr<OpalMixerNode> node, 
00508       OpalCall & call,              
00509       void * userData,              
00510       unsigned options,
00511       OpalConnection::StringOptions * stringOptions
00512     );
00513 
00518     PSafePtr<OpalMixerNode> AddNode(
00519       OpalMixerNodeInfo * info 
00520     );
00521 
00526     virtual OpalMixerNode * CreateNode(
00527       OpalMixerNodeInfo * info 
00528     );
00529 
00533     PSafePtr<OpalMixerNode> GetFirstNode(
00534       PSafetyMode mode = PSafeReference 
00535     ) const { return PSafePtr<OpalMixerNode>(m_nodesByUID, mode); }
00536 
00540     PSafePtr<OpalMixerNode> FindNode(
00541       const PString & name,             
00542       PSafetyMode mode = PSafeReference 
00543     );
00544 
00548     void RemoveNode(
00549       OpalMixerNode & node 
00550     );
00552 
00567     void SetAdHocNodeInfo(
00568       const OpalMixerNodeInfo & info
00569     );
00570     void SetAdHocNodeInfo(
00571       OpalMixerNodeInfo * info
00572     );
00573 
00585     OpalMixerNodeInfo * GetAdHocNodeInfo() { return m_adHocNodeInfo; }
00587 
00588   protected:
00589     OpalMixerNodeInfo * m_adHocNodeInfo;
00590 
00591     PSafeDictionary<PGloballyUniqueID, OpalMixerNode> m_nodesByUID;
00592     PDictionary<PString, OpalMixerNode>               m_nodesByName;
00593 
00594   friend class OpalMixerNode;
00595 };
00596 
00597 
00599 
00602 class OpalMixerConnection : public OpalLocalConnection
00603 {
00604     PCLASSINFO(OpalMixerConnection, OpalLocalConnection);
00605   public:
00610     OpalMixerConnection(
00611       PSafePtr<OpalMixerNode> node, 
00612       OpalCall & call,              
00613       OpalMixerEndPoint & endpoint, 
00614       void * userData,              
00615       unsigned options,
00616       OpalConnection::StringOptions * stringOptions
00617     );
00618 
00621     ~OpalMixerConnection();
00623 
00643     virtual void OnReleased();
00644 
00651     virtual OpalMediaFormatList GetMediaFormats() const;
00652 
00667     virtual OpalMediaStream * CreateMediaStream(
00668       const OpalMediaFormat & mediaFormat, 
00669       unsigned sessionID,                  
00670       PBoolean isSource                    
00671     );
00672 
00673     virtual void ApplyStringOptions(OpalConnection::StringOptions & stringOptions);
00675 
00680     void SetListenOnly(
00681       bool listenOnly   
00682     );
00683 
00686     bool GetListenOnly() const { return m_listenOnly; }
00687 
00690     PSafePtr<OpalMixerNode> GetNode() const { return m_node; }
00692 
00693   protected:
00694     OpalMixerEndPoint     & m_endpoint;
00695     PSafePtr<OpalMixerNode> m_node;
00696     bool                    m_listenOnly;
00697 };
00698 
00699 
00703 class OpalMixerMediaStream : public OpalMediaStream
00704 {
00705     PCLASSINFO(OpalMixerMediaStream, OpalMediaStream);
00706   public:
00711     OpalMixerMediaStream(
00712       OpalMixerConnection & conn,          
00713       const OpalMediaFormat & mediaFormat, 
00714       unsigned sessionID,                  
00715       bool isSource,                       
00716       PSafePtr<OpalMixerNode> node,        
00717       bool listenOnly                      
00718     );
00719 
00722     ~OpalMixerMediaStream();
00724 
00729     virtual PBoolean Open();
00730 
00733     virtual PBoolean Close();
00734 
00740     virtual PBoolean WritePacket(
00741       RTP_DataFrame & packet
00742     );
00743 
00747     virtual PBoolean IsSynchronous() const;
00748 
00758     virtual PBoolean RequiresPatchThread(
00759       OpalMediaStream * sinkStream  
00760     ) const;
00762 
00767     PSafePtr<OpalMixerNode> GetNode() { return m_node; }
00769 
00770   protected:
00771     PSafePtr<OpalMixerNode> m_node;
00772 #if OPAL_VIDEO
00773     bool m_video;
00774 #endif
00775 };
00776 
00777 
00781 class OpalMixerNode : public PSafeObject
00782 {
00783     PCLASSINFO(OpalMixerNode, PSafeObject);
00784   public:
00789     OpalMixerNode(
00790       OpalMixerEndPoint & endpoint,   
00791       OpalMixerNodeInfo * info        
00792     );
00793 
00796     ~OpalMixerNode();
00797 
00802     void ShutDown();
00804 
00811     void PrintOn(
00812       ostream & strm    
00813     ) const;
00815 
00820     void AttachConnection(
00821       OpalMixerConnection * connection  
00822     );
00823 
00826     void DetachConnection(
00827       OpalMixerConnection * connection  
00828     );
00829 
00832     bool AttachStream(
00833       OpalMixerMediaStream * stream     
00834     );
00835 
00838     void DetachStream(
00839       OpalMixerMediaStream * stream     
00840     );
00841 
00844     bool WriteAudio(
00845       const OpalBaseMixer::Key_T & key, 
00846       const RTP_DataFrame & input       
00847     ) { return m_audioMixer.WriteStream(key, input); }
00848 
00849 #if OPAL_VIDEO
00850 
00852     bool WriteVideo(
00853       const OpalBaseMixer::Key_T & key, 
00854       const RTP_DataFrame & input       
00855     ) { return m_videoMixer.WriteStream(key, input); }
00856 #endif // OPAL_VIDEO
00857 
00858 
00863     const PGloballyUniqueID & GetGUID() const { return m_guid; }
00864 
00867     const PStringList & GetNames() const { return m_names; }
00868 
00871     void AddName(
00872       const PString & name
00873     );
00874 
00877     void RemoveName(
00878       const PString & name
00879     );
00880 
00886     PINDEX GetConnectionCount() const { return m_connections.GetSize(); }
00887 
00890     PSafePtr<OpalMixerConnection> GetFirstConnection(
00891       PSafetyMode mode = PSafeReference
00892     ) const { return PSafePtr<OpalMixerConnection>(m_connections, mode); }
00893 
00896     const OpalMixerNodeInfo & GetNodeInfo() { return *m_info; }
00897 
00900     const PTime & GetCreationTime() const { return m_creationTime; }
00902 
00903   protected:
00904     OpalMixerEndPoint & m_endpoint;
00905     PGloballyUniqueID   m_guid;
00906     PStringList         m_names;
00907     OpalMixerNodeInfo * m_info;
00908     PTime               m_creationTime;
00909 
00910     PSafeList<OpalMixerConnection> m_connections;
00911 
00912     struct MediaMixer
00913     {
00914       MediaMixer();
00915 
00916       PSafeList<OpalMixerMediaStream> m_outputStreams;
00917     };
00918 
00919     struct AudioMixer : public OpalAudioMixer, public MediaMixer
00920     {
00921       AudioMixer(const OpalMixerNodeInfo & info);
00922       ~AudioMixer();
00923 
00924       virtual bool OnPush();
00925 
00926       struct CachedAudio {
00927         CachedAudio();
00928         ~CachedAudio();
00929         enum { Collecting, Collected, Completed } m_state;
00930         RTP_DataFrame    m_raw;
00931         RTP_DataFrame    m_encoded;
00932         OpalTranscoder * m_transcoder;
00933       };
00934       std::map<PString, CachedAudio> m_cache;
00935 
00936       void PushOne(
00937         OpalMixerMediaStream & stream,
00938         CachedAudio & cache,
00939         const short * audioToSubtract
00940       );
00941 #ifdef OPAL_MIXER_AUDIO_DEBUG
00942       class PAudioMixerDebug * m_audioDebug;
00943 #endif
00944     };
00945     AudioMixer m_audioMixer;
00946 
00947 #if OPAL_VIDEO
00948     struct VideoMixer : public OpalVideoMixer, public MediaMixer
00949     {
00950       VideoMixer(const OpalMixerNodeInfo & info);
00951       ~VideoMixer();
00952 
00953       virtual bool OnMixed(RTP_DataFrame * & output);
00954 
00955       PDictionary<OpalMediaFormat, OpalTranscoder> m_transcoders;
00956     };
00957     VideoMixer m_videoMixer;
00958 #endif // OPAL_VIDEO
00959 };
00960 
00961 
00962 #endif // OPAL_OPAL_OPAL_MIXER
00963 
00964 

Generated on Mon Aug 3 20:50:24 2009 for OPAL by  doxygen 1.5.1