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: 27149 $ 29 * $Author: rjongbloed $ 30 * $Date: 2012-03-07 18:32:36 -0600 (Wed, 07 Mar 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 #include <ptclib/threadpool.h> 48 49 50 class RTP_DataFrame; 51 class OpalJitterBuffer; 52 class OpalMixerConnection; 53 54 55 //#define OPAL_MIXER_AUDIO_DEBUG 1 56 57 58 #define OPAL_OPT_LISTEN_ONLY "Listen-Only" ///< String option for listen only mixer connection 59 60 61 /////////////////////////////////////////////////////////////////////////////// 62 63 /** Class base for a media mixer. 64 65 The mixer operates by re-buffering the input media into chunks each with an 66 associated timestamp. A main mixer thread then reads from each stream at 67 regular intervals, mixes the media and creates the output buffer. 68 69 Note the timestamps of the input media are extremely important as they are 70 used so that breaks or too fast data in the input media is dealt with correctly. 71 */ 72 class OpalBaseMixer 73 { 74 public: 75 OpalBaseMixer( 76 bool pushThread, ///< Indicate if the push thread should be started 77 unsigned periodMS, ///< The output buffer time in milliseconds 78 unsigned periodTS ///< The output buffer time in RTP timestamp units 79 ); 80 81 virtual ~OpalBaseMixer(); 82 83 typedef PString Key_T; 84 85 /**Add a stream to mixer using the specified key. 86 */ 87 virtual bool AddStream( 88 const Key_T & key ///< key for mixer stream 89 ); 90 91 /** Remove an input stream from mixer. 92 */ 93 virtual void RemoveStream( 94 const Key_T & key ///< key for mixer stream 95 ); 96 97 /** Remove all input streams from mixer. 98 */ 99 virtual void RemoveAllStreams(); 100 101 /**Write an RTP data frame to mixer. 102 A copy of the RTP data frame is created. This function is generally 103 quite fast as the actual mixing is done in a different thread so 104 minimal interference with the normal media stream processing occurs. 105 */ 106 virtual bool WriteStream( 107 const Key_T & key, ///< key for mixer stream 108 const RTP_DataFrame & input ///< Input RTP data for media 109 ); 110 111 /**Read media from mixer. 112 A pull model system would call this function to get the mixed media 113 from the mixer. Note the stream indicated by the streamToIgnore key is 114 not included in the mixing operation, allowing for example, the member 115 of a conference to not hear themselves. 116 117 Note this function is the function that does all the "heavy lifting" 118 for the mixer. 119 */ 120 virtual RTP_DataFrame * ReadMixed(); 121 virtual bool ReadMixed(RTP_DataFrame & mixed); 122 123 /**Mixed data is now available. 124 For a push model system, this is called with mixed data as returned by 125 ReadMixed(). 126 127 The "mixed" parameter is a reference to a pointer, so if the consumer 128 wishes to take responsibility for deleting the pointer to an RTP data 129 frame, then they can set it to NULL. 130 131 If false is returned then the push thread is exited. 132 */ 133 virtual bool OnMixed( 134 RTP_DataFrame * & mixed ///< Pointer to mixed media. 135 ); 136 137 /**Start the push thread. 138 Normally called internally. 139 */ 140 void StartPushThread(); 141 142 /**Stop the push thread. 143 This will wait for th epush thread to terminate, so care must be taken 144 to avoid deadlocks when calling. 145 */ 146 void StopPushThread(bool lock = true); 147 148 /**Get the period for mixing in RTP timestamp units. 149 */ GetPeriodTS()150 unsigned GetPeriodTS() const { return m_periodTS; } 151 152 protected: 153 struct Stream { ~StreamStream154 virtual ~Stream() { } 155 virtual void QueuePacket(const RTP_DataFrame & rtp) = 0; 156 queue<RTP_DataFrame> m_queue; 157 }; 158 typedef std::map<Key_T, Stream *> StreamMap_T; 159 160 virtual Stream * CreateStream() = 0; 161 virtual bool MixStreams(RTP_DataFrame & frame) = 0; 162 virtual size_t GetOutputSize() const = 0; 163 164 virtual bool OnPush(); 165 void PushThreadMain(); 166 167 bool m_pushThread; // true if to use a thread to push data out 168 unsigned m_periodMS; // Mixing interval in milliseconds 169 unsigned m_periodTS; // Mixing interval in timestamp units 170 171 StreamMap_T m_inputStreams; // Map of key to stream for input RTP frame queues 172 unsigned m_outputTimestamp; // RTP timestamp for output data 173 RTP_DataFrame * m_pushFrame; // Cached frame for pushing RTP 174 PThread * m_workerThread; // reader thread handle 175 bool m_threadRunning; // used to stop reader thread 176 PMutex m_mutex; // mutex for list of streams and thread handle 177 }; 178 179 /////////////////////////////////////////////////////////////////////////////// 180 181 /** Class for an audio mixer. 182 This takes raw PCM-16 data and sums all the input data streams to produce 183 a single PCM-16 sample value. 184 185 For 2 or less channels, they may be mixed as stereo where 16 bit PCM 186 samples are placed in adjacent pairs in the output, rather than summing 187 them. 188 */ 189 class OpalAudioMixer : public OpalBaseMixer 190 { 191 public: 192 OpalAudioMixer( 193 bool stereo = false, ///< Indicate stero or mixed mono mode 194 unsigned sampleRate = OpalMediaFormat::AudioClockRate, ///< Sample rate for audio, default 8kHz 195 bool pushThread = true, ///< Indicate push thread is to be used 196 unsigned period = 10 ///< Period for push/pull of audio from mixer in milliseconds 197 ); 198 ~OpalAudioMixer()199 ~OpalAudioMixer() { StopPushThread(); } 200 201 /** Remove an input stream from mixer. 202 */ 203 virtual void RemoveStream( 204 const Key_T & key ///< key for mixer stream 205 ); 206 207 /** Remove all input streams from mixer. 208 */ 209 virtual void RemoveAllStreams(); 210 211 /**Return flag for mixing stereo audio data. 212 */ IsStereo()213 bool IsStereo() const { return m_stereo; } 214 215 /**Get sample rate for audio. 216 */ GetSampleRate()217 unsigned GetSampleRate() const { return m_sampleRate; } 218 219 /**Set sample rate for audio data. 220 Note that all streams must have the same sample rate. 221 222 Returns false if attempts to set sample rate to something different to 223 existing streams. 224 */ 225 bool SetSampleRate( 226 unsigned rate ///< New rate 227 ); 228 229 /**Sets the size of the jitter buffer to be used by the specified stream 230 in this mixer. A mixer defaults to not having any jitter buffer enabled. 231 232 If either jitter delay parameter is zero, it destroys the jitter buffer 233 attached to this mixer. 234 */ 235 bool SetJitterBufferSize( 236 const Key_T & key, ///< key for mixer stream 237 unsigned minJitterDelay, ///< Minimum jitter buffer delay in RTP timestamp units 238 unsigned maxJitterDelay ///< Maximum jitter buffer delay in RTP timestamp units 239 ); 240 241 protected: 242 struct AudioStream : public Stream 243 { 244 AudioStream(OpalAudioMixer & mixer); 245 ~AudioStream(); 246 247 virtual void QueuePacket(const RTP_DataFrame & rtp); 248 const short * GetAudioDataPtr(); 249 250 OpalAudioMixer & m_mixer; 251 OpalJitterBuffer * m_jitter; 252 unsigned m_nextTimestamp; 253 PShortArray m_cacheSamples; 254 size_t m_samplesUsed; 255 }; 256 257 virtual Stream * CreateStream(); 258 virtual bool MixStreams(RTP_DataFrame & frame); 259 virtual size_t GetOutputSize() const; 260 261 void PreMixStreams(); 262 void MixStereo(RTP_DataFrame & frame); 263 void MixAdditive(RTP_DataFrame & frame, const short * audioToSubtract); 264 265 protected: 266 bool m_stereo; 267 unsigned m_sampleRate; 268 269 AudioStream * m_left; 270 AudioStream * m_right; 271 std::vector<int> m_mixedAudio; 272 }; 273 274 275 /////////////////////////////////////////////////////////////////////////////// 276 277 #if OPAL_VIDEO 278 279 /**Video mixer. 280 This takes raw YUV420P frames with a PluginCodec_Video_FrameHeader in the 281 RTP data frames, scales them and places them in particular positions of the 282 output data frame. A number of different patterns for positioning the sub 283 images are available in the Styles enum. 284 */ 285 class OpalVideoMixer : public OpalBaseMixer 286 { 287 public: 288 enum Styles { 289 eSideBySideLetterbox, /**< Two images side by side with black bars top and bottom. 290 It is expected that the input frames and output are all 291 the same aspect ratio, e.g. 4:3. Works well if inputs 292 are QCIF and output is CIF for example. */ 293 eSideBySideScaled, /**< Two images side by side, scaled to fit halves of output 294 frame. It is expected that the output frame be double 295 the width of the input data to maintain aspect ratio. 296 e.g. for CIF inputs, output would be 704x288. */ 297 eStackedPillarbox, /**< Two images, one on top of the other with black bars down 298 the sides. It is expected that the input frames and output 299 are all the same aspect ratio, e.g. 4:3. Works well if 300 inputs are QCIF and output is CIF for example. */ 301 eStackedScaled, /**< Two images, one on top of the other, scaled to fit halves 302 of output frame. It is expected that the output frame be 303 double the height of the input data to maintain aspect 304 ratio. e.g. for CIF inputs, output would be 352x576. */ 305 eGrid, /**< Standard 2x2, 3x3, 4x4 grid pattern. Size of grid is 306 dependent on the number of video streams. */ 307 }; 308 309 OpalVideoMixer( 310 Styles style, ///< Style for mixing video 311 unsigned width, ///< Width of output frame 312 unsigned height, ///< Height of output frame 313 unsigned rate = 15, ///< Frames per second for output 314 bool pushThread = true ///< A push thread is to be created 315 ); 316 ~OpalVideoMixer()317 ~OpalVideoMixer() { StopPushThread(); } 318 319 /**Get output video frame width. 320 */ GetFrameWidth()321 unsigned GetFrameWidth() const { return m_width; } 322 323 /**Get output video frame height. 324 */ GetFrameHeight()325 unsigned GetFrameHeight() const { return m_height; } 326 327 /**Get output video frame rate (frames per second) 328 */ GetFrameRate()329 unsigned GetFrameRate() const { return 1000/m_periodMS; } 330 331 /**Set output video frame rate. 332 May be dynamically changed at any time. 333 */ 334 bool SetFrameRate( 335 unsigned rate // New frames per second. 336 ); 337 338 /**Set the output video frame width and height. 339 May be dynamically changed at any time. 340 */ 341 bool SetFrameSize( 342 unsigned width, ///< New width 343 unsigned height ///< new height 344 ); 345 346 protected: 347 struct VideoStream : public Stream 348 { 349 VideoStream(OpalVideoMixer & mixer); 350 virtual void QueuePacket(const RTP_DataFrame & rtp); 351 void InsertVideoFrame(unsigned x, unsigned y, unsigned w, unsigned h); 352 353 OpalVideoMixer & m_mixer; 354 }; 355 356 friend struct VideoStream; 357 358 virtual Stream * CreateStream(); 359 virtual bool MixStreams(RTP_DataFrame & frame); 360 virtual size_t GetOutputSize() const; 361 362 protected: 363 Styles m_style; 364 unsigned m_width, m_height; 365 BYTE m_bgFillRed,m_bgFillGreen,m_bgFillBlue; 366 367 PBYTEArray m_frameStore; 368 size_t m_lastStreamCount; 369 }; 370 371 #endif // OPAL_VIDEO 372 373 374 /////////////////////////////////////////////////////////////////////////////// 375 376 377 /**Base class for OpalMixerNode options. 378 The user may derive from this class, making sure they implement the Clone() 379 funciton, to add extra options for use by their OpalMixerNode derived class. 380 */ 381 struct OpalMixerNodeInfo 382 { 383 OpalMixerNodeInfo(const char * name = NULL) m_nameOpalMixerNodeInfo384 : m_name(name) 385 , m_listenOnly(false) 386 , m_sampleRate(OpalMediaFormat::AudioClockRate) 387 #if OPAL_VIDEO 388 , m_audioOnly(false) 389 , m_style(OpalVideoMixer::eGrid) 390 , m_width(PVideoFrameInfo::CIFWidth) 391 , m_height(PVideoFrameInfo::CIFHeight) 392 , m_rate(15) 393 #endif 394 , m_mediaPassThru(false) 395 { } 396 ~OpalMixerNodeInfoOpalMixerNodeInfo397 virtual ~OpalMixerNodeInfo() { } 398 CloneOpalMixerNodeInfo399 virtual OpalMixerNodeInfo * Clone() const { return new OpalMixerNodeInfo(*this); } 400 401 PString m_name; ///< Name for mixer node. 402 bool m_listenOnly; ///< Mixer only transmits data to "listeners" 403 unsigned m_sampleRate; ///< Audio sample rate, usually 8000 404 #if OPAL_VIDEO 405 bool m_audioOnly; ///< No video is to be allowed. 406 OpalVideoMixer::Styles m_style; ///< Method for mixing video 407 unsigned m_width; ///< Width of mixed video 408 unsigned m_height; ///< Height of mixed video 409 unsigned m_rate; ///< Frame rate of mixed video 410 #endif 411 bool m_mediaPassThru; /**< Enable media pass through to optimise mixer node 412 with precisely two attached connections. */ 413 }; 414 415 416 /////////////////////////////////////////////////////////////////////////////// 417 418 class OpalMixerNode; 419 420 421 /** Mixer node manager. 422 This class is a collection of OpalMixerNodes. 423 It provides access to nodes by GUID or name. 424 */ 425 class OpalMixerNodeManager : public PObject 426 { 427 PCLASSINFO(OpalMixerNodeManager, PObject); 428 public: 429 /**@name Construction */ 430 //@{ 431 /**Create a new mixer node manager. 432 */ 433 OpalMixerNodeManager(); 434 435 /**Destroy all mixer nodes. 436 Calls ShutDown. 437 */ 438 virtual ~OpalMixerNodeManager(); 439 440 /**Shuts down, removes and destroys all mixer nodes. 441 */ 442 virtual void ShutDown(); 443 444 /** Execute garbage collection of nodes. 445 Returns true if all garbage has been collected. 446 Default behaviour deletes the objects that have been 447 removed from the m_nodesByUID list. 448 */ 449 virtual PBoolean GarbageCollection(); 450 //@} 451 452 /**@name Operations */ 453 //@{ 454 /**Create a new node. 455 This should create the new instance of the OpalMixerNode as required 456 by the derived class, if any. 457 The info variable should be created on the heap and it is subsequently 458 owned by the node. NULL can be passed if defaults are to be used. 459 */ 460 virtual OpalMixerNode * CreateNode( 461 OpalMixerNodeInfo * info ///< Initial info for node 462 ); 463 464 /**Add a new node. 465 The info variable should be created on the heap and it is subsequently 466 owned by the node. NULL can be passed if defaults are to be used. 467 Calls CreateNode. 468 */ 469 virtual PSafePtr<OpalMixerNode> AddNode( 470 OpalMixerNodeInfo * info ///< Initial info for node 471 ); 472 473 /**Add an existing node. 474 */ 475 void AddNode(OpalMixerNode * node); 476 477 /**Get the first node. 478 The active nodes may be enumerated by the ++ operator on the PSafePtr. 479 */ 480 PSafePtr<OpalMixerNode> GetFirstNode( 481 PSafetyMode mode = PSafeReference ///< Lock mode for returned pointer 482 ) const { return PSafePtr<OpalMixerNode>(m_nodesByUID, mode); } 483 484 /**Find a new node. 485 This will search for the mixer node using GUID and then name. 486 */ 487 virtual PSafePtr<OpalMixerNode> FindNode( 488 const PString & name, ///< GUID or alias name for node 489 PSafetyMode mode = PSafeReference ///< Lock mode for returned pointer 490 ); 491 492 /**Remove a node. 493 Shut down all active connections with node, remove its name 494 associations and delete it. 495 */ 496 virtual void RemoveNode( 497 OpalMixerNode & node 498 ); 499 500 /**Add node name to association list. 501 */ 502 void AddNodeName( 503 PString name, ///< alias name for node 504 OpalMixerNode * node ///< node associated with name 505 ); 506 507 /**Remove node's name from association list. 508 */ 509 void RemoveNodeName( 510 PString name ///< alias name for node 511 ); 512 513 /**Remove list of node names from association list. 514 Commonly used when node destroyed. 515 */ 516 void RemoveNodeNames( 517 PStringList names ///< list of alias names for nodes 518 ); 519 520 /**Queue user input for braodcast 521 */ 522 void QueueUserInput( 523 const PSafePtr<OpalMixerNode> & node, ///< Node to qhich user input is broadcast 524 const OpalMixerConnection * connection, ///< Connection NOT to send to 525 const PString & value ///< String value of indication 526 ); 527 //@} 528 529 protected: 530 PSafeDictionary<PGloballyUniqueID, OpalMixerNode> m_nodesByUID; 531 PDictionary<PString, OpalMixerNode> m_nodesByName; 532 533 struct UserInput { UserInputUserInput534 UserInput( 535 const PSafePtr<OpalMixerNode> & node, 536 const OpalMixerConnection * connection, 537 const PString & value 538 ) : m_node(node) 539 , m_connection(connection) 540 , m_value(value) 541 { } 542 543 PSafePtr<OpalMixerNode> m_node; 544 const OpalMixerConnection * m_connection; 545 PString m_value; 546 547 void Work(); 548 }; 549 PQueuedThreadPool<UserInput> m_userInputPool; 550 }; 551 552 553 /////////////////////////////////////////////////////////////////////////////// 554 555 /** Mixer EndPoint. 556 This class represents an endpoint that mixes media. It can be used as the 557 basis for a Multipoint Conferencing Unit. 558 */ 559 class OpalMixerEndPoint : public OpalLocalEndPoint 560 { 561 PCLASSINFO(OpalMixerEndPoint, OpalLocalEndPoint); 562 public: 563 /**@name Construction */ 564 //@{ 565 /**Create a new endpoint. 566 */ 567 OpalMixerEndPoint( 568 OpalManager & manager, ///< Manager of all endpoints. 569 const char * prefix ///< Prefix for URL style address strings 570 ); 571 572 /**Destroy endpoint. 573 */ 574 ~OpalMixerEndPoint(); 575 576 /**Shut down the endpoint, this is called by the OpalManager just before 577 destroying the object and can be handy to make sure some things are 578 stopped before the vtable gets clobbered. 579 */ 580 virtual void ShutDown(); 581 //@} 582 583 /**@name Overrides from OpalEndPoint */ 584 //@{ 585 /**Get the data formats this endpoint is capable of operating. 586 This provides a list of media data format names that may be used by an 587 OpalMediaStream may be created by a connection from this endpoint. 588 589 Note that a specific connection may not actually support all of the 590 media formats returned here, but should return no more. 591 592 The default behaviour returns the most basic media formats, PCM audio 593 and YUV420P video. 594 */ 595 virtual OpalMediaFormatList GetMediaFormats() const; 596 597 /**Set up a connection to a remote party. 598 This is called from the OpalManager::MakeConnection() function once 599 it has determined that this is the endpoint for the protocol. 600 601 The general form for this party parameter is: 602 603 [proto:][alias@][transport$]address[:port] 604 605 where the various fields will have meanings specific to the endpoint 606 type. For example, with H.323 it could be "h323:Fred@site.com" which 607 indicates a user Fred at gatekeeper size.com. Whereas for the PSTN 608 endpoint it could be "pstn:5551234" which is to call 5551234 on the 609 first available PSTN line. 610 611 The proto field is optional when passed to a specific endpoint. If it 612 is present, however, it must agree with the endpoints protocol name or 613 false is returned. 614 615 This function usually returns almost immediately with the connection 616 continuing to occur in a new background thread. 617 618 If false is returned then the connection could not be established. For 619 example if a PSTN endpoint is used and the assiciated line is engaged 620 then it may return immediately. Returning a non-NULL value does not 621 mean that the connection will succeed, only that an attempt is being 622 made. 623 624 The default behaviour is pure. 625 */ 626 virtual PSafePtr<OpalConnection> MakeConnection( 627 OpalCall & call, ///< Owner of connection 628 const PString & party, ///< Remote party to call 629 void * userData = NULL, ///< Arbitrary data to pass to connection 630 unsigned options = 0, ///< Option bit mask to pass to connection 631 OpalConnection::StringOptions * stringOptions = NULL ///< Options to pass to connection 632 ); 633 634 /** Execute garbage collection for endpoint. 635 Returns true if all garbage has been collected. 636 Default behaviour deletes the objects in the connectionsActive list. 637 */ 638 virtual PBoolean GarbageCollection(); 639 //@} 640 641 /**@name Operations */ 642 //@{ 643 /**Find a connection that uses the specified token. 644 This searches the endpoint for the connection that contains the token 645 as provided by functions such as MakeConnection(). If not then it 646 attempts to use the token as a OpalCall token and find a connection 647 of the same class. 648 */ 649 PSafePtr<OpalMixerConnection> GetMixerConnectionWithLock( 650 const PString & token, ///< Token to identify connection 651 PSafetyMode mode = PSafeReadWrite ///< Lock mode 652 ) { return GetConnectionWithLockAs<OpalMixerConnection>(token, mode); } 653 654 /**Create a connection for the PCSS endpoint. 655 The default implementation is to create a OpalMixerConnection. 656 */ 657 virtual OpalMixerConnection * CreateConnection( 658 PSafePtr<OpalMixerNode> node, ///< Node the connection is in 659 OpalCall & call, ///< Owner of connection 660 void * userData, ///< Arbitrary data to pass to connection 661 unsigned options, ///< Option bit mask to pass to connection 662 OpalConnection::StringOptions * stringOptions ///< Options to pass to connection 663 ); 664 //@} 665 666 /**@name Mixer Operations */ 667 //@{ 668 /**Add a new node. 669 The info variable should be created on the heap and it is subsequently 670 owned by the node. NULL can be passed if defaults are to be used. 671 Calls CreateNode. 672 */ 673 PSafePtr<OpalMixerNode> AddNode( 674 OpalMixerNodeInfo * info ///< Initial info for node 675 ); 676 677 /**Create a new node. 678 This should create the new instance of the OpalMixerNode as required 679 by the derived class, if any. 680 The info variable should be created on the heap and it is subsequently 681 owned by the node. NULL can be passed if defaults are to be used. 682 */ 683 virtual OpalMixerNode * CreateNode( 684 OpalMixerNodeInfo * info ///< Initial info for node 685 ); 686 687 /**Get the first node. 688 The active nodes may be enumerated by the ++ operator on the PSafePtr. 689 */ 690 PSafePtr<OpalMixerNode> GetFirstNode( 691 PSafetyMode mode = PSafeReference ///< Lock mode for returned pointer 692 ) const { return m_nodeManager.GetFirstNode(mode); } 693 694 /**Find an existing node. 695 This will search for the mixer node using GUID and then name. 696 */ 697 PSafePtr<OpalMixerNode> FindNode( 698 const PString & name, ///< GUID or alias name for node 699 PSafetyMode mode = PSafeReference ///< Lock mode for returned pointer 700 ) { return m_nodeManager.FindNode(name, mode); } 701 702 /**Remove a node. 703 Shut down all active connections with node, remove its name 704 associations and delete it. 705 */ RemoveNode(OpalMixerNode & node)706 void RemoveNode( 707 OpalMixerNode & node ///< Initial info for node 708 ) { m_nodeManager.RemoveNode(node); } 709 //@} 710 711 /**@name Member variable access */ 712 //@{ 713 /**Set default ad hoc node information. 714 The pointer is passed to the CreateNode() function, so may be a 715 reference to derived class, which a derived class of OpalMixerNode 716 could use. 717 718 Note if NULL, then ad hoc nodes are not created and incoming 719 connections are refused. A user must ex[icitly call AddNode() to create 720 a name that can be conected to. 721 722 The version that takes a reference will utilise the CLone() function 723 to create a copy of the mixer info. 724 */ 725 void SetAdHocNodeInfo( 726 const OpalMixerNodeInfo & info 727 ); 728 void SetAdHocNodeInfo( 729 OpalMixerNodeInfo * info 730 ); 731 732 /**Get default ad hoc mode information. 733 The pointer returned from this function is passed to the CreateNode() 734 function, so may be a reference to derived class, which a derived class 735 of OpalMixerNode could use. 736 737 Note if NULL, then ad hoc nodes are not created and incoming 738 connections are refused. A user must ex[icitly call AddNode() to create 739 a name that can be conected to. 740 741 Default bahaviour returns member variable m_adHocNodeInfo. 742 */ GetAdHocNodeInfo()743 OpalMixerNodeInfo * GetAdHocNodeInfo() { return m_adHocNodeInfo; } 744 745 /**Get the Node Manager for this endpoint. 746 */ GetNodeManager()747 const OpalMixerNodeManager & GetNodeManager() const { return m_nodeManager; } GetNodeManager()748 OpalMixerNodeManager & GetNodeManager() { return m_nodeManager; } 749 //@} 750 751 protected: 752 OpalMixerNodeInfo * m_adHocNodeInfo; 753 OpalMixerNodeManager m_nodeManager; 754 }; 755 756 757 /////////////////////////////////////////////////////////////////////////////// 758 759 /** Mixer connection. 760 */ 761 class OpalMixerConnection : public OpalLocalConnection 762 { 763 PCLASSINFO(OpalMixerConnection, OpalLocalConnection); 764 public: 765 /**@name Construction */ 766 //@{ 767 /**Create a new connection. 768 */ 769 OpalMixerConnection( 770 PSafePtr<OpalMixerNode> node, ///< Node the connection is in 771 OpalCall & call, ///< Owner calll for connection 772 OpalMixerEndPoint & endpoint, ///< Owner endpoint for connection 773 void * userData, ///< Arbitrary data to pass to connection 774 unsigned options = 0, ///< Option bit map to be passed to connection 775 OpalConnection::StringOptions * stringOptions = NULL ///< Options to be passed to connection 776 ); 777 778 /**Destroy connection. 779 */ 780 ~OpalMixerConnection(); 781 //@} 782 783 /**@name Overrides from OpalConnection */ 784 //@{ 785 /**Clean up the termination of the connection. 786 This function can do any internal cleaning up and waiting on background 787 threads that may be using the connection object. 788 789 Note that there is not a one to one relationship with the 790 OnEstablishedConnection() function. This function may be called without 791 that function being called. For example if SetUpConnection() was used 792 but the call never completed. 793 794 Classes that override this function should make sure they call the 795 ancestor version for correct operation. 796 797 An application will not typically call this function as it is used by 798 the OpalManager during a release of the connection. 799 800 The default behaviour calls the OpalEndPoint function of the same name. 801 */ 802 virtual void OnReleased(); 803 804 /**Get the data formats this connection is capable of operating. 805 This provides a list of media data format names that a 806 OpalMediaStream may be created in within this connection. 807 808 The default behaviour calls GetMediaFormats() on the endpoint. 809 */ 810 virtual OpalMediaFormatList GetMediaFormats() const; 811 812 /**Open a new media stream. 813 This will create a media stream of an appropriate subclass as required 814 by the underlying connection protocol. For instance H.323 would create 815 an OpalRTPStream. 816 817 The sessionID parameter may not be needed by a particular media stream 818 and may be ignored. In the case of an OpalRTPStream it us used. 819 820 Note that media streams may be created internally to the underlying 821 protocol. This function is not the only way a stream can come into 822 existance. 823 824 The default behaviour is pure. 825 */ 826 virtual OpalMediaStream * CreateMediaStream( 827 const OpalMediaFormat & mediaFormat, ///< Media format for stream 828 unsigned sessionID, ///< Session number for stream 829 PBoolean isSource ///< Is a source stream 830 ); 831 832 /**Call back when media stream patch thread starts. 833 */ 834 virtual void OnStartMediaPatch( 835 OpalMediaPatch & patch ///< Patch being started 836 ); 837 838 /// Call back for connection to act on changed string options 839 virtual void OnApplyStringOptions(); 840 841 /**Send a user input indication to the remote endpoint. 842 This is for sending arbitrary strings as user indications. 843 844 The default behaviour is to call SendUserInputTone() for each character 845 in the string. 846 */ 847 virtual PBoolean SendUserInputString( 848 const PString & value ///< String value of indication 849 ); 850 851 /**Send a user input indication to the remote endpoint. 852 This sends DTMF emulation user input. If something more sophisticated 853 than the simple tones that can be sent using the SendUserInput() 854 function. 855 856 A duration of zero indicates that no duration is to be indicated. 857 A non-zero logical channel indicates that the tone is to be syncronised 858 with the logical channel at the rtpTimestamp value specified. 859 860 The tone parameter must be one of "0123456789#*ABCD!" where '!' 861 indicates a hook flash. If tone is a ' ' character then a 862 signalUpdate PDU is sent that updates the last tone indication 863 sent. See the H.245 specifcation for more details on this. 864 865 The default behaviour sends the tone using RFC2833. 866 */ 867 virtual PBoolean SendUserInputTone( 868 char tone, ///< DTMF tone code 869 unsigned duration = 0 ///< Duration of tone in milliseconds 870 ); 871 //@} 872 873 /**@name Operations */ 874 //@{ 875 /**Set this connection to listen only mode. 876 */ 877 void SetListenOnly( 878 bool listenOnly ///< New listen only state. 879 ); 880 881 /**Get flag for this connection is in listen only mode. 882 */ GetListenOnly()883 bool GetListenOnly() const { return m_listenOnly; } 884 885 /**Get the node that this connection is being mxied in. 886 */ GetNode()887 PSafePtr<OpalMixerNode> GetNode() const { return m_node; } 888 //@} 889 890 protected: 891 OpalMixerEndPoint & m_endpoint; 892 PSafePtr<OpalMixerNode> m_node; 893 bool m_listenOnly; 894 }; 895 896 897 /**Mixer media stream. 898 This class represents a media stream that will send/get media from a mixer. 899 */ 900 class OpalMixerMediaStream : public OpalMediaStream 901 { 902 PCLASSINFO(OpalMixerMediaStream, OpalMediaStream); 903 public: 904 /**@name Construction */ 905 //@{ 906 /**Construct a new media stream for mixer. 907 */ 908 OpalMixerMediaStream( 909 OpalConnection & conn, ///< Connection for media stream 910 const OpalMediaFormat & mediaFormat, ///< Media format for stream 911 unsigned sessionID, ///< Session number for stream 912 bool isSource, ///< Is a source stream 913 PSafePtr<OpalMixerNode> node, ///< Mixer node to send data 914 bool listenOnly ///< Effectively initial pause state 915 ); 916 917 /**Destroy stream. 918 */ 919 ~OpalMixerMediaStream(); 920 //@} 921 922 /**@name Overrides of OpalMediaStream class */ 923 //@{ 924 /**Open the media stream using the media format. 925 */ 926 virtual PBoolean Open(); 927 928 /**Write an RTP frame of data to the sink media stream. 929 The default behaviour simply calls WriteData() on the data portion of the 930 RTP_DataFrame and and sets the internal timestamp and marker from the 931 member variables of the media stream class. 932 */ 933 virtual PBoolean WritePacket( 934 RTP_DataFrame & packet 935 ); 936 937 /**Indicate if the media stream is synchronous. 938 Returns true for LID streams. 939 */ 940 virtual PBoolean IsSynchronous() const; 941 942 /**Indicate if the media stream requires a OpalMediaPatch thread (active patch). 943 This is called on the source/sink stream and is passed the sink/source 944 stream that the patch will initially be using. The function could 945 conditionally require the patch thread to execute a thread reading and 946 writing data, or prevent it from doing so as it can do so in hardware 947 in some way. 948 949 The default behaviour returns true if a sink stream. If source stream 950 then threading is from the mixer class. 951 */ 952 virtual PBoolean RequiresPatchThread() const; 953 954 /**Enable jitter buffer for the media stream. 955 Returns true if a jitter buffer is enabled/disabled. Returns false if 956 no jitter buffer exists for the media stream. 957 958 The default behaviour sets the mixer jitter buffer size according 959 to the connection parameters, then returns true. 960 */ 961 virtual bool EnableJitterBuffer(bool enab = true) const; 962 //@} 963 964 /**@name Member variable access */ 965 //@{ 966 /**Get the mixer node for this stream. 967 */ GetNode()968 PSafePtr<OpalMixerNode> GetNode() { return m_node; } 969 //@} 970 971 protected: 972 virtual void InternalClose(); 973 974 PSafePtr<OpalMixerNode> m_node; 975 bool m_listenOnly; 976 #if OPAL_VIDEO 977 bool m_video; 978 #endif 979 }; 980 981 982 /** Mixer node. 983 This class represents a group of connections that are being mixed. 984 */ 985 class OpalMixerNode : public PSafeObject 986 { 987 PCLASSINFO(OpalMixerNode, PSafeObject); 988 public: 989 /**@name Construction */ 990 //@{ 991 /**Create a new node. 992 */ 993 OpalMixerNode( 994 OpalMixerNodeManager & manager, ///< Manager for this node 995 OpalMixerNodeInfo * info ///< Configuration information 996 ); 997 OpalMixerNode( 998 OpalMixerEndPoint & endpoint, ///< Endpoint for this node 999 OpalMixerNodeInfo * info ///< Configuration information 1000 ); 1001 1002 /**Destroy node. 1003 */ 1004 ~OpalMixerNode(); 1005 1006 /**Shut down node. 1007 This clears all attached connections, removes all names and generally 1008 shuts the node down. 1009 */ 1010 void ShutDown(); 1011 //@} 1012 1013 /**@name Overrides from PObject */ 1014 //@{ 1015 /**Standard stream print function. 1016 The PObject class has a << operator defined that invokes this function 1017 polymorphically. 1018 */ 1019 void PrintOn( 1020 ostream & strm ///< Stream to output text representation 1021 ) const; 1022 //@} 1023 1024 /**@name Operations */ 1025 //@{ 1026 /**Attach a connection. 1027 */ 1028 void AttachConnection( 1029 OpalConnection * connection ///< Connection to attach 1030 ); 1031 1032 /**Detach a connection. 1033 */ 1034 void DetachConnection( 1035 OpalConnection * connection ///< Connection to detach 1036 ); 1037 1038 /**Attach a stream for output. 1039 */ 1040 bool AttachStream( 1041 OpalMixerMediaStream * stream ///< Stream to attach 1042 ); 1043 1044 /**Detach a stream for output. 1045 */ 1046 void DetachStream( 1047 OpalMixerMediaStream * stream ///< Stream to detach 1048 ); 1049 1050 /**Use media bypass if applicable. 1051 */ 1052 void UseMediaPassThrough( 1053 unsigned sessionID, ///< Session ID to bypass, 0 indicates all 1054 OpalConnection * connection = NULL ///< Just deleted connection 1055 ); 1056 1057 /**Sets the size of the jitter buffer to be used by the specified stream 1058 in this mixer. A mixer defaults to not having any jitter buffer enabled. 1059 1060 If either jitter delay parameter is zero, it destroys the jitter buffer 1061 attached to this mixer. 1062 */ SetJitterBufferSize(const OpalBaseMixer::Key_T & key,unsigned minJitterDelay,unsigned maxJitterDelay)1063 bool SetJitterBufferSize( 1064 const OpalBaseMixer::Key_T & key, ///< key for mixer stream 1065 unsigned minJitterDelay, ///< Minimum jitter buffer delay in RTP timestamp units 1066 unsigned maxJitterDelay ///< Maximum jitter buffer delay in RTP timestamp units 1067 ) { return m_audioMixer.SetJitterBufferSize(key, minJitterDelay, maxJitterDelay); } 1068 1069 /**Write data to mixer. 1070 */ WriteAudio(const OpalBaseMixer::Key_T & key,const RTP_DataFrame & input)1071 bool WriteAudio( 1072 const OpalBaseMixer::Key_T & key, ///< key for mixer stream 1073 const RTP_DataFrame & input ///< Input RTP data for media 1074 ) { return m_audioMixer.WriteStream(key, input); } 1075 1076 #if OPAL_VIDEO 1077 /**Write data to mixer. 1078 */ WriteVideo(const OpalBaseMixer::Key_T & key,const RTP_DataFrame & input)1079 bool WriteVideo( 1080 const OpalBaseMixer::Key_T & key, ///< key for mixer stream 1081 const RTP_DataFrame & input ///< Input RTP data for media 1082 ) { return m_videoMixer.WriteStream(key, input); } 1083 #endif // OPAL_VIDEO 1084 1085 /**Send a user input indication to all connections. 1086 */ 1087 virtual void BroadcastUserInput( 1088 const OpalConnection * connection, ///< Connection NOT to send to 1089 const PString & value ///< String value of indication 1090 ); 1091 //@} 1092 1093 /**@name Member variable access */ 1094 //@{ 1095 /**Get globally unique identifier for node. 1096 */ GetGUID()1097 const PGloballyUniqueID & GetGUID() const { return m_guid; } 1098 1099 /**Get list of names for this node. 1100 */ GetNames()1101 const PStringList & GetNames() const { return m_names; } 1102 1103 /**Add a name for this node. 1104 */ 1105 void AddName( 1106 const PString & name 1107 ); 1108 1109 /**Remove a name for this node. 1110 */ 1111 void RemoveName( 1112 const PString & name 1113 ); 1114 1115 /**Get count of connections. 1116 Note that as this value can change ata any moent, it is really not 1117 that useful and should definitely not be used for enumeration of the 1118 connections. 1119 */ GetConnectionCount()1120 PINDEX GetConnectionCount() const { return m_connections.GetSize(); } 1121 1122 /**Get first connection in the connections list as type. 1123 */ 1124 template <class Subclass> 1125 PSafePtr<Subclass> GetFirstConnectionAs( 1126 PSafetyMode mode = PSafeReference 1127 ) const { return PSafePtr<Subclass>(m_connections, mode); } 1128 1129 /**Get first connection in the connections list. 1130 */ 1131 PSafePtr<OpalConnection> GetFirstConnection( 1132 PSafetyMode mode = PSafeReference 1133 ) const { return GetFirstConnectionAs<OpalConnection>(mode); } 1134 1135 /**Get the raw audio accumulation buffer. 1136 */ GetNodeInfo()1137 const OpalMixerNodeInfo & GetNodeInfo() { return *m_info; } 1138 1139 /**Get the creation time of the node. 1140 */ GetCreationTime()1141 const PTime & GetCreationTime() const { return m_creationTime; } 1142 //@} 1143 1144 protected: 1145 void Construct(); 1146 1147 OpalMixerNodeManager & m_manager; 1148 PGloballyUniqueID m_guid; 1149 PStringList m_names; 1150 OpalMixerNodeInfo * m_info; 1151 PTime m_creationTime; 1152 1153 PSafeList<OpalConnection> m_connections; 1154 1155 struct MediaMixer 1156 { 1157 MediaMixer(); 1158 1159 PSafeList<OpalMixerMediaStream> m_outputStreams; 1160 }; 1161 1162 struct AudioMixer : public OpalAudioMixer, public MediaMixer 1163 { 1164 AudioMixer(const OpalMixerNodeInfo & info); 1165 ~AudioMixer(); 1166 1167 virtual bool OnPush(); 1168 1169 struct CachedAudio { 1170 CachedAudio(); 1171 ~CachedAudio(); 1172 enum { Collecting, Collected, Completed } m_state; 1173 RTP_DataFrame m_raw; 1174 RTP_DataFrame m_encoded; 1175 OpalTranscoder * m_transcoder; 1176 }; 1177 std::map<PString, CachedAudio> m_cache; 1178 1179 void PushOne( 1180 PSafePtr<OpalMixerMediaStream> & stream, 1181 CachedAudio & cache, 1182 const short * audioToSubtract 1183 ); 1184 #ifdef OPAL_MIXER_AUDIO_DEBUG 1185 class PAudioMixerDebug * m_audioDebug; 1186 #endif 1187 }; 1188 AudioMixer m_audioMixer; 1189 1190 #if OPAL_VIDEO 1191 struct VideoMixer : public OpalVideoMixer, public MediaMixer 1192 { 1193 VideoMixer(const OpalMixerNodeInfo & info); 1194 ~VideoMixer(); 1195 1196 virtual bool OnMixed(RTP_DataFrame * & output); 1197 1198 PDictionary<PString, OpalTranscoder> m_transcoders; 1199 }; 1200 VideoMixer m_videoMixer; 1201 #endif // OPAL_VIDEO 1202 }; 1203 1204 1205 #endif // OPAL_OPAL_OPAL_MIXER 1206 1207 1208 /////////////////////////////////////////////////////////////////////////////// 1209