OPAL  Version 3.10.4
opalmixer.h
Go to the documentation of this file.
1 /*
2  * opalmixer.h
3  *
4  * OPAL media mixers
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (C) 2007 Post Increment
10  *
11  * The contents of this file are subject to the Mozilla Public License
12  * Version 1.0 (the "License"); you may not use this file except in
13  * compliance with the License. You may obtain a copy of the License at
14  * http://www.mozilla.org/MPL/
15  *
16  * Software distributed under the License is distributed on an "AS IS"
17  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
18  * the License for the specific language governing rights and limitations
19  * under the License.
20  *
21  * The Original Code is Open Phone Abstraction Library.
22  *
23  * The Initial Developer of the Original Code is Post Increment
24  *
25  * Contributor(s): Craig Southeren (craigs@postincrement.com)
26  * Robert Jongbloed (robertj@voxlucida.com.au)
27  *
28  * $Revision: 26969 $
29  * $Author: rjongbloed $
30  * $Date: 2012-02-10 18:45:16 -0600 (Fri, 10 Feb 2012) $
31  */
32 
33 
34 #ifndef OPAL_OPAL_OPALMIXER_H
35 #define OPAL_OPAL_OPALMIXER_H
36 
37 #ifndef _PTLIB_H
38 #include <ptlib.h>
39 #endif
40 
41 #include <opal/buildopts.h>
42 
43 #include <queue>
44 
45 #include <opal/localep.h>
46 #include <codec/vidcodec.h>
47 
48 
49 class RTP_DataFrame;
50 class OpalJitterBuffer;
51 
52 
53 //#define OPAL_MIXER_AUDIO_DEBUG 1
54 
55 
56 #define OPAL_OPT_LISTEN_ONLY "Listen-Only"
57 
58 
60 
71 {
72  public:
74  bool pushThread,
75  unsigned periodMS,
76  unsigned periodTS
77  );
78 
79  virtual ~OpalBaseMixer();
80 
81  typedef PString Key_T;
82 
85  virtual bool AddStream(
86  const Key_T & key
87  );
88 
91  virtual void RemoveStream(
92  const Key_T & key
93  );
94 
97  virtual void RemoveAllStreams();
98 
104  virtual bool WriteStream(
105  const Key_T & key,
106  const RTP_DataFrame & input
107  );
108 
118  virtual RTP_DataFrame * ReadMixed();
119  virtual bool ReadMixed(RTP_DataFrame & mixed);
120 
131  virtual bool OnMixed(
132  RTP_DataFrame * & mixed
133  );
134 
138  void StartPushThread();
139 
144  void StopPushThread(bool lock = true);
145 
148  unsigned GetPeriodTS() const { return m_periodTS; }
149 
150  protected:
151  struct Stream {
152  virtual ~Stream() { }
153  virtual void QueuePacket(const RTP_DataFrame & rtp) = 0;
154  queue<RTP_DataFrame> m_queue;
155  };
156  typedef std::map<Key_T, Stream *> StreamMap_T;
157 
158  virtual Stream * CreateStream() = 0;
159  virtual bool MixStreams(RTP_DataFrame & frame) = 0;
160  virtual size_t GetOutputSize() const = 0;
161 
162  virtual bool OnPush();
163  void PushThreadMain();
164 
165  bool m_pushThread; // true if to use a thread to push data out
166  unsigned m_periodMS; // Mixing interval in milliseconds
167  unsigned m_periodTS; // Mixing interval in timestamp units
168 
169  StreamMap_T m_inputStreams; // Map of key to stream for input RTP frame queues
170  unsigned m_outputTimestamp; // RTP timestamp for output data
171  RTP_DataFrame * m_pushFrame; // Cached frame for pushing RTP
172  PThread * m_workerThread; // reader thread handle
173  bool m_threadRunning; // used to stop reader thread
174  PMutex m_mutex; // mutex for list of streams and thread handle
175 };
176 
178 
188 {
189  public:
191  bool stereo = false,
192  unsigned sampleRate = OpalMediaFormat::AudioClockRate,
193  bool pushThread = true,
194  unsigned period = 10
195  );
196 
198 
201  virtual void RemoveStream(
202  const Key_T & key
203  );
204 
207  virtual void RemoveAllStreams();
208 
211  bool IsStereo() const { return m_stereo; }
212 
215  unsigned GetSampleRate() const { return m_sampleRate; }
216 
223  bool SetSampleRate(
224  unsigned rate
225  );
226 
233  bool SetJitterBufferSize(
234  const Key_T & key,
235  unsigned minJitterDelay,
236  unsigned maxJitterDelay
237  );
238 
239  protected:
240  struct AudioStream : public Stream
241  {
242  AudioStream(OpalAudioMixer & mixer);
243  ~AudioStream();
244 
245  virtual void QueuePacket(const RTP_DataFrame & rtp);
246  const short * GetAudioDataPtr();
247 
250  unsigned m_nextTimestamp;
251  PShortArray m_cacheSamples;
253  };
254 
255  virtual Stream * CreateStream();
256  virtual bool MixStreams(RTP_DataFrame & frame);
257  virtual size_t GetOutputSize() const;
258 
259  void PreMixStreams();
260  void MixStereo(RTP_DataFrame & frame);
261  void MixAdditive(RTP_DataFrame & frame, const short * audioToSubtract);
262 
263  protected:
264  bool m_stereo;
265  unsigned m_sampleRate;
266 
269  std::vector<int> m_mixedAudio;
270 };
271 
272 
274 
275 #if OPAL_VIDEO
276 
284 {
285  public:
286  enum Styles {
305  };
306 
308  Styles style,
309  unsigned width,
310  unsigned height,
311  unsigned rate = 15,
312  bool pushThread = true
313  );
314 
316 
319  unsigned GetFrameWidth() const { return m_width; }
320 
323  unsigned GetFrameHeight() const { return m_height; }
324 
327  unsigned GetFrameRate() const { return 1000/m_periodMS; }
328 
332  bool SetFrameRate(
333  unsigned rate // New frames per second.
334  );
335 
339  bool SetFrameSize(
340  unsigned width,
341  unsigned height
342  );
343 
344  protected:
345  struct VideoStream : public Stream
346  {
347  VideoStream(OpalVideoMixer & mixer);
348  virtual void QueuePacket(const RTP_DataFrame & rtp);
349  void InsertVideoFrame(unsigned x, unsigned y, unsigned w, unsigned h);
350 
352  };
353 
354  friend struct VideoStream;
355 
356  virtual Stream * CreateStream();
357  virtual bool MixStreams(RTP_DataFrame & frame);
358  virtual size_t GetOutputSize() const;
359 
360  protected:
362  unsigned m_width, m_height;
364 
365  PBYTEArray m_frameStore;
367 };
368 
369 #endif // OPAL_VIDEO
370 
371 
373 
374 
380 {
381  OpalMixerNodeInfo(const char * name = NULL)
382  : m_name(name)
383  , m_listenOnly(false)
384  , m_sampleRate(OpalMediaFormat::AudioClockRate)
385 #if OPAL_VIDEO
386  , m_audioOnly(false)
387  , m_style(OpalVideoMixer::eGrid)
388  , m_width(PVideoFrameInfo::CIFWidth)
389  , m_height(PVideoFrameInfo::CIFHeight)
390  , m_rate(15)
391 #endif
392  , m_mediaPassThru(false)
393  { }
394 
395  virtual ~OpalMixerNodeInfo() { }
396 
397  virtual OpalMixerNodeInfo * Clone() const { return new OpalMixerNodeInfo(*this); }
398 
399  PString m_name;
401  unsigned m_sampleRate;
402 #if OPAL_VIDEO
403  bool m_audioOnly;
405  unsigned m_width;
406  unsigned m_height;
407  unsigned m_rate;
408 #endif
411 };
412 
413 
415 
416 class OpalMixerNode;
417 
418 
423 class OpalMixerNodeManager : public PObject
424 {
425  PCLASSINFO(OpalMixerNodeManager, PObject);
426  public:
432 
436  virtual ~OpalMixerNodeManager();
437 
440  virtual void ShutDown();
441 
447  virtual PBoolean GarbageCollection();
449 
458  virtual OpalMixerNode * CreateNode(
459  OpalMixerNodeInfo * info
460  );
461 
467  virtual PSafePtr<OpalMixerNode> AddNode(
468  OpalMixerNodeInfo * info
469  );
470 
473  void AddNode(OpalMixerNode * node);
474 
478  PSafePtr<OpalMixerNode> GetFirstNode(
479  PSafetyMode mode = PSafeReference
480  ) const { return PSafePtr<OpalMixerNode>(m_nodesByUID, mode); }
481 
485  virtual PSafePtr<OpalMixerNode> FindNode(
486  const PString & name,
487  PSafetyMode mode = PSafeReference
488  );
489 
494  virtual void RemoveNode(
495  OpalMixerNode & node
496  );
497 
500  void AddNodeName(
501  PString name,
502  OpalMixerNode * node
503  );
504 
507  void RemoveNodeName(
508  PString name
509  );
510 
514  void RemoveNodeNames(
515  PStringList names
516  );
518 
519  protected:
520  PSafeDictionary<PGloballyUniqueID, OpalMixerNode> m_nodesByUID;
521  PDictionary<PString, OpalMixerNode> m_nodesByName;
522 };
523 
524 
526 
527 class OpalMixerConnection;
528 
534 {
536  public:
542  OpalManager & manager,
543  const char * prefix
544  );
545 
549 
554  virtual void ShutDown();
556 
569  virtual OpalMediaFormatList GetMediaFormats() const;
570 
600  virtual PSafePtr<OpalConnection> MakeConnection(
601  OpalCall & call,
602  const PString & party,
603  void * userData = NULL,
604  unsigned options = 0,
605  OpalConnection::StringOptions * stringOptions = NULL
606  );
607 
612  virtual PBoolean GarbageCollection();
614 
623  PSafePtr<OpalMixerConnection> GetMixerConnectionWithLock(
624  const PString & token,
625  PSafetyMode mode = PSafeReadWrite
626  ) { return GetConnectionWithLockAs<OpalMixerConnection>(token, mode); }
627 
632  PSafePtr<OpalMixerNode> node,
633  OpalCall & call,
634  void * userData,
635  unsigned options,
636  OpalConnection::StringOptions * stringOptions
637  );
639 
647  PSafePtr<OpalMixerNode> AddNode(
648  OpalMixerNodeInfo * info
649  );
650 
657  virtual OpalMixerNode * CreateNode(
658  OpalMixerNodeInfo * info
659  );
660 
664  PSafePtr<OpalMixerNode> GetFirstNode(
665  PSafetyMode mode = PSafeReference
666  ) const { return m_nodeManager.GetFirstNode(mode); }
667 
671  PSafePtr<OpalMixerNode> FindNode(
672  const PString & name,
673  PSafetyMode mode = PSafeReference
674  ) { return m_nodeManager.FindNode(name, mode); }
675 
681  OpalMixerNode & node
682  ) { m_nodeManager.RemoveNode(node); }
684 
699  void SetAdHocNodeInfo(
700  const OpalMixerNodeInfo & info
701  );
702  void SetAdHocNodeInfo(
703  OpalMixerNodeInfo * info
704  );
705 
718 
724 
725  protected:
728 };
729 
730 
732 
736 {
738  public:
744  PSafePtr<OpalMixerNode> node,
745  OpalCall & call,
747  void * userData,
748  unsigned options = 0,
749  OpalConnection::StringOptions * stringOptions = NULL
750  );
751 
756 
776  virtual void OnReleased();
777 
784  virtual OpalMediaFormatList GetMediaFormats() const;
785 
801  const OpalMediaFormat & mediaFormat,
802  unsigned sessionID,
803  PBoolean isSource
804  );
805 
808  virtual void OnStartMediaPatch(
809  OpalMediaPatch & patch
810  );
811 
813  virtual void OnApplyStringOptions();
814 
821  virtual PBoolean SendUserInputString(
822  const PString & value
823  );
824 
841  virtual PBoolean SendUserInputTone(
842  char tone,
843  unsigned duration = 0
844  );
846 
851  void SetListenOnly(
852  bool listenOnly
853  );
854 
857  bool GetListenOnly() const { return m_listenOnly; }
858 
861  PSafePtr<OpalMixerNode> GetNode() const { return m_node; }
863 
864  protected:
866  PSafePtr<OpalMixerNode> m_node;
868 };
869 
870 
875 {
877  public:
883  OpalConnection & conn,
884  const OpalMediaFormat & mediaFormat,
885  unsigned sessionID,
886  bool isSource,
887  PSafePtr<OpalMixerNode> node,
888  bool listenOnly
889  );
890 
895 
900  virtual PBoolean Open();
901 
904  virtual PBoolean Close();
905 
911  virtual PBoolean WritePacket(
912  RTP_DataFrame & packet
913  );
914 
918  virtual PBoolean IsSynchronous() const;
919 
930  virtual PBoolean RequiresPatchThread() const;
931 
939  virtual bool EnableJitterBuffer(bool enab = true) const;
941 
946  PSafePtr<OpalMixerNode> GetNode() { return m_node; }
948 
949  protected:
950  PSafePtr<OpalMixerNode> m_node;
952 #if OPAL_VIDEO
953  bool m_video;
954 #endif
955 };
956 
957 
961 class OpalMixerNode : public PSafeObject
962 {
963  PCLASSINFO(OpalMixerNode, PSafeObject);
964  public:
970  OpalMixerNodeManager & manager,
971  OpalMixerNodeInfo * info
972  );
974  OpalMixerEndPoint & endpoint,
975  OpalMixerNodeInfo * info
976  );
977 
980  ~OpalMixerNode();
981 
986  void ShutDown();
988 
995  void PrintOn(
996  ostream & strm
997  ) const;
999 
1004  void AttachConnection(
1005  OpalConnection * connection
1006  );
1007 
1010  void DetachConnection(
1011  OpalConnection * connection
1012  );
1013 
1016  bool AttachStream(
1017  OpalMixerMediaStream * stream
1018  );
1019 
1022  void DetachStream(
1023  OpalMixerMediaStream * stream
1024  );
1025 
1028  void UseMediaPassThrough(
1029  unsigned sessionID,
1030  OpalConnection * connection = NULL
1031  );
1032 
1040  const OpalBaseMixer::Key_T & key,
1041  unsigned minJitterDelay,
1042  unsigned maxJitterDelay
1043  ) { return m_audioMixer.SetJitterBufferSize(key, minJitterDelay, maxJitterDelay); }
1044 
1048  const OpalBaseMixer::Key_T & key,
1049  const RTP_DataFrame & input
1050  ) { return m_audioMixer.WriteStream(key, input); }
1051 
1052 #if OPAL_VIDEO
1053 
1056  const OpalBaseMixer::Key_T & key,
1057  const RTP_DataFrame & input
1058  ) { return m_videoMixer.WriteStream(key, input); }
1059 #endif // OPAL_VIDEO
1060 
1063  virtual void BroadcastUserInput(
1064  const OpalConnection * connection,
1065  const PString & value
1066  );
1068 
1073  const PGloballyUniqueID & GetGUID() const { return m_guid; }
1074 
1077  const PStringList & GetNames() const { return m_names; }
1078 
1081  void AddName(
1082  const PString & name
1083  );
1084 
1087  void RemoveName(
1088  const PString & name
1089  );
1090 
1096  PINDEX GetConnectionCount() const { return m_connections.GetSize(); }
1097 
1100  template <class Subclass>
1101  PSafePtr<Subclass> GetFirstConnectionAs(
1102  PSafetyMode mode = PSafeReference
1103  ) const { return PSafePtr<Subclass>(m_connections, mode); }
1104 
1107  PSafePtr<OpalConnection> GetFirstConnection(
1108  PSafetyMode mode = PSafeReference
1109  ) const { return GetFirstConnectionAs<OpalConnection>(mode); }
1110 
1113  const OpalMixerNodeInfo & GetNodeInfo() { return *m_info; }
1114 
1117  const PTime & GetCreationTime() const { return m_creationTime; }
1119 
1120  protected:
1121  void Construct();
1122 
1124  PGloballyUniqueID m_guid;
1125  PStringList m_names;
1128 
1129  PSafeList<OpalConnection> m_connections;
1130 
1131  struct MediaMixer
1132  {
1133  MediaMixer();
1134 
1135  PSafeList<OpalMixerMediaStream> m_outputStreams;
1136  };
1137 
1138  struct AudioMixer : public OpalAudioMixer, public MediaMixer
1139  {
1140  AudioMixer(const OpalMixerNodeInfo & info);
1141  ~AudioMixer();
1142 
1143  virtual bool OnPush();
1144 
1145  struct CachedAudio {
1146  CachedAudio();
1147  ~CachedAudio();
1152  };
1153  std::map<PString, CachedAudio> m_cache;
1154 
1155  void PushOne(
1156  PSafePtr<OpalMixerMediaStream> & stream,
1157  CachedAudio & cache,
1158  const short * audioToSubtract
1159  );
1160 #ifdef OPAL_MIXER_AUDIO_DEBUG
1161  class PAudioMixerDebug * m_audioDebug;
1162 #endif
1163  };
1165 
1166 #if OPAL_VIDEO
1167  struct VideoMixer : public OpalVideoMixer, public MediaMixer
1168  {
1169  VideoMixer(const OpalMixerNodeInfo & info);
1170  ~VideoMixer();
1171 
1172  virtual bool OnMixed(RTP_DataFrame * & output);
1173 
1174  PDictionary<PString, OpalTranscoder> m_transcoders;
1175  };
1177 #endif // OPAL_VIDEO
1178 };
1179 
1180 
1181 #endif // OPAL_OPAL_OPAL_MIXER
1182 
1183