OPAL Version 3.10.2
|
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: 25300 $ 00029 * $Author: rjongbloed $ 00030 * $Date: 2011-03-09 13:22:53 -0600 (Wed, 09 Mar 2011) $ 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" ///< String option for listen only mixer connection 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 bool m_listenOnly; 00952 #if OPAL_VIDEO 00953 bool m_video; 00954 #endif 00955 }; 00956 00957 00961 class OpalMixerNode : public PSafeObject 00962 { 00963 PCLASSINFO(OpalMixerNode, PSafeObject); 00964 public: 00969 OpalMixerNode( 00970 OpalMixerNodeManager & manager, 00971 OpalMixerNodeInfo * info 00972 ); 00973 OpalMixerNode( 00974 OpalMixerEndPoint & endpoint, 00975 OpalMixerNodeInfo * info 00976 ); 00977 00980 ~OpalMixerNode(); 00981 00986 void ShutDown(); 00988 00995 void PrintOn( 00996 ostream & strm 00997 ) const; 00999 01004 void AttachConnection( 01005 OpalConnection * connection 01006 ); 01007 01010 void DetachConnection( 01011 OpalConnection * connection 01012 ); 01013 01016 bool AttachStream( 01017 OpalMixerMediaStream * stream 01018 ); 01019 01022 void DetachStream( 01023 OpalMixerMediaStream * stream 01024 ); 01025 01028 void UseMediaPassThrough( 01029 unsigned sessionID, 01030 OpalConnection * connection = NULL 01031 ); 01032 01039 bool SetJitterBufferSize( 01040 const OpalBaseMixer::Key_T & key, 01041 unsigned minJitterDelay, 01042 unsigned maxJitterDelay 01043 ) { return m_audioMixer.SetJitterBufferSize(key, minJitterDelay, maxJitterDelay); } 01044 01047 bool WriteAudio( 01048 const OpalBaseMixer::Key_T & key, 01049 const RTP_DataFrame & input 01050 ) { return m_audioMixer.WriteStream(key, input); } 01051 01052 #if OPAL_VIDEO 01053 01055 bool WriteVideo( 01056 const OpalBaseMixer::Key_T & key, 01057 const RTP_DataFrame & input 01058 ) { return m_videoMixer.WriteStream(key, input); } 01059 #endif // OPAL_VIDEO 01060 01063 virtual void BroadcastUserInput( 01064 const OpalConnection * connection, 01065 const PString & value 01066 ); 01068 01073 const PGloballyUniqueID & GetGUID() const { return m_guid; } 01074 01077 const PStringList & GetNames() const { return m_names; } 01078 01081 void AddName( 01082 const PString & name 01083 ); 01084 01087 void RemoveName( 01088 const PString & name 01089 ); 01090 01096 PINDEX GetConnectionCount() const { return m_connections.GetSize(); } 01097 01100 template <class Subclass> 01101 PSafePtr<Subclass> GetFirstConnectionAs( 01102 PSafetyMode mode = PSafeReference 01103 ) const { return PSafePtr<Subclass>(m_connections, mode); } 01104 01107 PSafePtr<OpalConnection> GetFirstConnection( 01108 PSafetyMode mode = PSafeReference 01109 ) const { return GetFirstConnectionAs<OpalConnection>(mode); } 01110 01113 const OpalMixerNodeInfo & GetNodeInfo() { return *m_info; } 01114 01117 const PTime & GetCreationTime() const { return m_creationTime; } 01119 01120 protected: 01121 void Construct(); 01122 01123 OpalMixerNodeManager & m_manager; 01124 PGloballyUniqueID m_guid; 01125 PStringList m_names; 01126 OpalMixerNodeInfo * m_info; 01127 PTime m_creationTime; 01128 01129 PSafeList<OpalConnection> m_connections; 01130 01131 struct MediaMixer 01132 { 01133 MediaMixer(); 01134 01135 PSafeList<OpalMixerMediaStream> m_outputStreams; 01136 }; 01137 01138 struct AudioMixer : public OpalAudioMixer, public MediaMixer 01139 { 01140 AudioMixer(const OpalMixerNodeInfo & info); 01141 ~AudioMixer(); 01142 01143 virtual bool OnPush(); 01144 01145 struct CachedAudio { 01146 CachedAudio(); 01147 ~CachedAudio(); 01148 enum { Collecting, Collected, Completed } m_state; 01149 RTP_DataFrame m_raw; 01150 RTP_DataFrame m_encoded; 01151 OpalTranscoder * m_transcoder; 01152 }; 01153 std::map<PString, CachedAudio> m_cache; 01154 01155 void PushOne( 01156 OpalMixerMediaStream & stream, 01157 CachedAudio & cache, 01158 const short * audioToSubtract 01159 ); 01160 #ifdef OPAL_MIXER_AUDIO_DEBUG 01161 class PAudioMixerDebug * m_audioDebug; 01162 #endif 01163 }; 01164 AudioMixer m_audioMixer; 01165 01166 #if OPAL_VIDEO 01167 struct VideoMixer : public OpalVideoMixer, public MediaMixer 01168 { 01169 VideoMixer(const OpalMixerNodeInfo & info); 01170 ~VideoMixer(); 01171 01172 virtual bool OnMixed(RTP_DataFrame * & output); 01173 01174 PDictionary<PString, OpalTranscoder> m_transcoders; 01175 }; 01176 VideoMixer m_videoMixer; 01177 #endif // OPAL_VIDEO 01178 }; 01179 01180 01181 #endif // OPAL_OPAL_OPAL_MIXER 01182 01183