# opalmixer.h

Go to the documentation of this file.

    00001 /*
    00002  * opalmixer.h
    00003  *
    00004  * OPAL audio mixer
    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): ______________________________________.
    00026  *
    00027  * $Revision: 21004 $
    00028  * $Author: rjongbloed $
    00029  * $Date: 2008-09-16 07:08:56 +0000 (Tue, 16 Sep 2008) $
    00030  */
    00031
    00032
    00033 #ifndef _OPALMIXER_H
    00034 #define _OPALMIXER_H
    00035
    00036 #ifndef _PTLIB_H
    00037 #include <ptlib.h>
    00038 #endif
    00039
    00040 #include <opal/buildopts.h>
    00041
    00042 #include <queue>
    00043
    00044 #include <ptlib/psync.h>
    00045 #include <ptclib/delaychan.h>
    00046
    00047 #include <rtp/rtp.h>
    00048 #include <codec/opalwavfile.h>
    00049
    00050 template <typename Locker_T = PSyncNULL>
    00051 class PMemBuffer
    00052 {
    00053   public:
    00054     struct Common {
    00055       Common(size_t size)
    00056         : base(size)
    00057       {
    00058         refCount = 1;
    00059       }
    00060
    00061       Common(BYTE * ptr, size_t size)
    00062         : base(ptr, size)
    00063       {
    00064         refCount = 1;
    00065       }
    00066
    00067       mutable int refCount;
    00068       mutable Locker_T mutex;
    00069       mutable PBYTEArray base;
    00070     };
    00071
    00072     Common * common;
    00073
    00074   protected:
    00075     BYTE * data;
    00076     PINDEX dataLen;
    00077
    00078   public:
    00079     PMemBuffer()
    00080     {
    00081       common  = NULL;
    00082       data    = NULL;
    00083       dataLen = 0;
    00084     }
    00085
    00086     PMemBuffer(PINDEX size)
    00087     {
    00088       common = new Common(size);
    00089       data    = common->base.GetPointer();
    00090       dataLen = size;
    00091     }
    00092
    00093     PMemBuffer(BYTE * ptr, size_t size)
    00094     {
    00095       common = new Common(ptr, size);
    00096       data    = common->base.GetPointer();
    00097       dataLen = size;
    00098     }
    00099
    00100     PMemBuffer(const PBYTEArray & obj)
    00101     {
    00102       common = new Common(obj.GetPointer(), obj.GetSize());
    00103       data    = common->base.GetPointer();
    00104       dataLen = obj.GetSize();
    00105     }
    00106
    00107     PMemBuffer(const PMemBuffer & obj)
    00108     {
    00109       PWaitAndSignal m(obj.common->mutex);
    00110       common = obj.common;
    00111       ++common->refCount;
    00112       data    = obj.data;
    00113       dataLen = obj.dataLen;
    00114     }
    00115
    00116     ~PMemBuffer()
    00117     {
    00118       if (common != NULL) {
    00119         common->mutex.Wait();
    00120         PBoolean last = common->refCount == 1;
    00121         if (last) {
    00122           common->mutex.Signal();
    00123           delete common;
    00124         }
    00125         else {
    00126           --common->refCount;
    00127           common->mutex.Signal();
    00128         }
    00129         common = NULL;
    00130         data    = NULL;
    00131         dataLen = 0;
    00132       }
    00133     }
    00134
    00135     PMemBuffer & operator = (const PMemBuffer & obj)
    00136     {
    00137       if (&obj == this)
    00138         return *this;
    00139
    00140       if (common != NULL) {
    00141         common->mutex.Wait();
    00142         PBoolean last = common->refCount == 1;
    00143         if (last) {
    00144           common->mutex.Signal();
    00145           delete common;
    00146         }
    00147         else
    00148         {
    00149           --common->refCount;
    00150           common->mutex.Signal();
    00151         }
    00152         common = NULL;
    00153         data    = NULL;
    00154         dataLen = 0;
    00155       }
    00156       {
    00157         PWaitAndSignal m(obj.common->mutex);
    00158         common = obj.common;
    00159         ++common->refCount;
    00160         data    = obj.data;
    00161         dataLen = obj.dataLen;
    00162       }
    00163
    00164       return *this;
    00165     }
    00166
    00167     void MakeUnique()
    00168     {
    00169       PWaitAndSignal m(common->mutex);
    00170       if (common->refCount == 1)
    00171         return;
    00172
    00173       Common * newCommon = new Common(common->base.GetPointer(), common->base.GetSize());
    00174       data = newCommon->base.GetPointer() + (data - common->base.GetPointer());
    00175       --common->refCount;
    00176       common = newCommon;
    00177     }
    00178
    00179     // set absolute base of data
    00180     // length is unchanged
    00181     void SetBase(PINDEX offs)
    00182     {
    00183       PWaitAndSignal m(common->mutex);
    00184       data = common->base.GetPointer() + offs;
    00185       if (offs + dataLen > common->base.GetSize())
    00186         dataLen = common->base.GetSize() - offs;
    00187     }
    00188
    00189     // adjust base of data relative to current base
    00190     // length is unchanged
    00191     void Rebase(PINDEX offs)
    00192     {
    00193       PWaitAndSignal m(common->mutex);
    00194       SetBase(offs + data - common->base.GetPointer());
    00195     }
    00196
    00197     // set the sbsolute length of the data
    00198     void SetSize(PINDEX size)
    00199     {
    00200       if (common == NULL) {
    00201         common = new Common(size);
    00202         data    = common->base.GetPointer();
    00203         dataLen = size;
    00204       }
    00205       else {
    00206         PWaitAndSignal m(common->mutex);
    00207         if (size < dataLen)
    00208           dataLen = size;
    00209         else {
    00210           PINDEX offs = data - common->base.GetPointer();
    00211           if (offs + size < common->base.GetSize())
    00212             dataLen = size;
    00213           else
    00214             dataLen = common->base.GetSize() - offs;
    00215         }
    00216       }
    00217     }
    00218
    00219     BYTE * GetPointerAndLock()
    00220     {
    00221       PAssert(common != NULL, "NULL pointer");
    00222       common->mutex.Wait();
    00223       return data;
    00224     }
    00225
    00226     inline const BYTE * GetPointerAndLock() const
    00227     {
    00228       PAssert(common != NULL, "NULL pointer");
    00229       common->mutex.Wait();
    00230       return data;
    00231     }
    00232
    00233     inline PINDEX GetSize() const
    00234     { return dataLen; }
    00235
    00236     inline void Lock() const
    00237     {
    00238       common->mutex.Wait();
    00239     }
    00240
    00241     inline void Unlock() const
    00242     {
    00243       common->mutex.Signal();
    00244     }
    00245
    00246     inline PSync & GetMutex()
    00247     {
    00248       return common->mutex;
    00249     }
    00250 };
    00251
    00253
    00255 //
    00256 //  the mixer operates by re-buffering the input streams into 10ms chunks
    00257 //  each with an associated timestamp. A main mixer thread then reads from each
    00258 //  stream at regular intervals, mixes the audio and creates the output
    00259 //
    00260 //  There are several complications:
    00261 //
    00262 //    1) the timestamps must be used so that breaks in the input audio are
    00263 //       dealt with correctly
    00264 //
    00265 //    2) Using a single worker thread to read all of the streams doesn't work because
    00266 //       it tends to get starved of CPU time and the output either gets behind or has
    00267 //       breaks in it. To avoid this, the creation of the output data is triggered
    00268 //       by whatever thread (write or read) occurs after each 10ms interval
    00269 //
    00270
    00272 //
    00273 //  define a class that encapsulates an audio stream for the purposes of the mixer
    00274 //
    00275
    00276 class OpalAudioMixerStream {
    00277   public:
    00278     class StreamFrame : public PMemBuffer<PMutex> {
    00279       public:
    00280         DWORD timestamp;
    00281         unsigned channelNumber;
    00282         StreamFrame()
    00283         { }
    00284
    00285         StreamFrame(const RTP_DataFrame & rtp);
    00286     };
    00287     typedef std::queue<StreamFrame> StreamFrameQueue_T;
    00288
    00289     PMutex mutex;
    00290     StreamFrameQueue_T frameQueue;
    00291     StreamFrame frameCache;
    00292     DWORD cacheTimeStamp;
    00293
    00294     PBoolean active;
    00295     PBoolean first;
    00296     unsigned channelNumber;
    00297
    00298     OpalAudioMixerStream();
    00299     void WriteFrame(const StreamFrame & frame);
    00300     void FillSilence(StreamFrame & retFrame, PINDEX ms);
    00301     void PopFrame(StreamFrame & retFrame, PINDEX ms);
    00302     PBoolean ReadFrame(StreamFrame & retFrame, PINDEX ms);
    00303 };
    00304
    00306 //
    00307 //  Define the audio mixer. This class extracts audio from a list of
    00308 //  OpalAudioMixerStream instances
    00309 //
    00310
    00311 class OpalAudioMixer
    00312 {
    00313   public:
    00314     typedef std::string Key_T;
    00315     typedef std::map<Key_T, OpalAudioMixerStream *> StreamInfoMap_T;
    00316     typedef std::map<Key_T, OpalAudioMixerStream::StreamFrame> MixerPCMMap_T;
    00317
    00318     class MixerFrame
    00319     {
    00320       public:
    00321         MixerPCMMap_T channelData;
    00322
    00323         DWORD timeStamp;
    00324         PINDEX frameLengthSamples;
    00325         mutable PIntArray mixedData;
    00326         mutable PMutex mutex;
    00327
    00328         MixerFrame(PINDEX _frameLength);
    00329         void CreateMixedData() const;
    00330         PBoolean GetMixedFrame(OpalAudioMixerStream::StreamFrame & frame) const;
    00331         PBoolean GetStereoFrame(OpalAudioMixerStream::StreamFrame & frame) const;
    00332         PBoolean GetChannelFrame(Key_T key, OpalAudioMixerStream::StreamFrame & frame) const;
    00333     };
    00334
    00335   protected:
    00336     PINDEX frameLengthMs;
    00337
    00338     PMutex mutex;
    00339     StreamInfoMap_T streamInfoMap;
    00340     unsigned channelNumber;
    00341
    00342     PBoolean realTime;
    00343     PBoolean pushThread;
    00344     PThread * thread;
    00345     PBoolean threadRunning;
    00346
    00347     PBoolean audioStarted;
    00348     PBoolean firstRead;
    00349
    00350     PTime timeOfNextRead;
    00351     DWORD outputTimestamp;
    00352
    00353   public:
    00354     OpalAudioMixer(PBoolean realTime = PTrue, PBoolean _pushThread = PTrue);
    00355     virtual ~OpalAudioMixer() { }
    00356     virtual PBoolean OnWriteAudio(const MixerFrame &);
    00357     PBoolean AddStream(const Key_T & key, OpalAudioMixerStream * stream);
    00358     void RemoveStream(const Key_T & key);
    00359     void RemoveAllStreams();
    00360     void StartThread();
    00361     void ThreadMain();
    00362     void ReadRoutine();
    00363     void WriteMixedFrame();
    00364     PBoolean Write(const Key_T & key, const RTP_DataFrame & rtp);
    00365 };
    00366
    00367 #endif // _OPAL_MIXER
    00368