Browse Source

cmApBuf.h/c : Added code to handle audio timestamps.

cmApBufUpdate() sets an input/output timestamp on each device according to the audio packet timestamp.
cmApBufGetIO() returns the timestamp associated with each returned buffer.
Added cmApBufOnPortEnable() to zero the timestamp when a port is enabled.
This implementation of the audio timestamping processes is a hack because
only the first timestamp is stored (after a call to cmApBufOnPortEnable())
and all subsequent timestamps are generated by incrementing this value according
to the incoming/outgoing sample count.
master
kevin 10 years ago
parent
commit
40a649dfc1
2 changed files with 85 additions and 24 deletions
  1. 77
    22
      cmApBuf.c
  2. 8
    2
      cmApBuf.h

+ 77
- 22
cmApBuf.c View File

@@ -4,6 +4,7 @@
4 4
 #include "cmErr.h"
5 5
 #include "cmMem.h"
6 6
 #include "cmMallocDebug.h"
7
+#include "cmTime.h"
7 8
 #include "cmAudioPort.h"
8 9
 #include "cmApBuf.h"
9 10
 #include "cmThread.h"
@@ -64,15 +65,17 @@ typedef struct
64 65
 
65 66
 typedef struct
66 67
 {
67
-  unsigned    chCnt;
68
-  cmApCh*     chArray;
68
+  unsigned     chCnt;
69
+  cmApCh*      chArray;
69 70
 
70
-  unsigned    n;     // length of b[] (multiple of dspFrameCnt)  bufCnt*framesPerCycle
71
-  double      srate; // device sample rate;
71
+  unsigned     n;     // length of b[] (multiple of dspFrameCnt)  bufCnt*framesPerCycle
72
+  double       srate; // device sample rate;
72 73
 
73
-  unsigned    faultCnt;
74
-  unsigned    framesPerCycle;
75
-  unsigned    dspFrameCnt;
74
+  unsigned     faultCnt;
75
+  unsigned     framesPerCycle;
76
+  unsigned     dspFrameCnt;
77
+  cmTimeSpec_t timeStamp;    // base (starting) time stamp for this device
78
+  unsigned     ioFrameCnt;   // count of frames input or output for this device
76 79
 
77 80
 } cmApIO;
78 81
 
@@ -169,13 +172,16 @@ void _cmApIoInitialize( cmApIO* ioPtr, double srate, unsigned framesPerCycle, un
169 172
 
170 173
   n += (n % dspFrameCnt); // force buffer size to be a multiple of dspFrameCnt
171 174
   
172
-  ioPtr->chArray        = chCnt==0 ? NULL : cmMemAllocZ( cmApCh, chCnt );
173
-  ioPtr->chCnt          = chCnt;
174
-  ioPtr->n              = n;
175
-  ioPtr->faultCnt       = 0;
176
-  ioPtr->framesPerCycle = framesPerCycle;
177
-  ioPtr->srate          = srate;
178
-  ioPtr->dspFrameCnt    = dspFrameCnt;
175
+  ioPtr->chArray           = chCnt==0 ? NULL : cmMemAllocZ( cmApCh, chCnt );
176
+  ioPtr->chCnt             = chCnt;
177
+  ioPtr->n                 = n;
178
+  ioPtr->faultCnt          = 0;
179
+  ioPtr->framesPerCycle    = framesPerCycle;
180
+  ioPtr->srate             = srate;
181
+  ioPtr->dspFrameCnt       = dspFrameCnt;
182
+  ioPtr->timeStamp.tv_sec  = 0;
183
+  ioPtr->timeStamp.tv_nsec = 0;
184
+  ioPtr->ioFrameCnt        = 0;
179 185
 
180 186
   for(i=0; i<chCnt; ++i )
181 187
     _cmApChInitialize( ioPtr->chArray + i, n, meterBufN );
@@ -277,6 +283,24 @@ cmAbRC_t cmApBufPrimeOutput( unsigned devIdx, unsigned audioCycleCnt )
277 283
   return kOkAbRC;
278 284
 }
279 285
 
286
+void cmApBufOnPortEnable( unsigned devIdx, bool enableFl )
287
+{
288
+  if( devIdx == cmInvalidIdx || enableFl==false)
289
+    return;
290
+   
291
+  cmApIO*  iop = _cmApBuf.devArray[devIdx].ioArray + kOutApIdx;
292
+  iop->timeStamp.tv_sec = 0;
293
+  iop->timeStamp.tv_nsec = 0;
294
+  iop->ioFrameCnt = 0;
295
+
296
+  iop = _cmApBuf.devArray[devIdx].ioArray + kInApIdx;
297
+  iop->timeStamp.tv_sec = 0;
298
+  iop->timeStamp.tv_nsec = 0;
299
+  iop->ioFrameCnt = 0;
300
+
301
+
302
+}
303
+
280 304
 cmAbRC_t cmApBufUpdate(
281 305
   cmApAudioPacket_t*  inPktArray, 
282 306
   unsigned           inPktCnt, 
@@ -293,6 +317,10 @@ cmAbRC_t cmApBufUpdate(
293 317
       cmApAudioPacket_t*  pp  = inPktArray + i;           
294 318
       cmApIO*             ip  = _cmApBuf.devArray[pp->devIdx].ioArray + kInApIdx; // dest io recd
295 319
 
320
+      // if the base time stamp has not yet been set - then set it
321
+      if( ip->timeStamp.tv_sec==0 && ip->timeStamp.tv_nsec==0 )
322
+        ip->timeStamp = pp->timeStamp;
323
+
296 324
       // for each source packet channel and enabled dest channel
297 325
       for(j=0; j<pp->chCnt; ++j)
298 326
       {
@@ -369,6 +397,9 @@ cmAbRC_t cmApBufUpdate(
369 397
       cmApAudioPacket_t* pp = outPktArray + i;           
370 398
       cmApIO*            op = _cmApBuf.devArray[pp->devIdx].ioArray + kOutApIdx; // dest io recd
371 399
 
400
+      // if the base timestamp has not yet been set then set it.
401
+      if( op->timeStamp.tv_sec==0 && op->timeStamp.tv_nsec==0 )
402
+        op->timeStamp = pp->timeStamp;
372 403
 
373 404
       // for each dest packet channel and enabled source channel
374 405
       for(j=0; j<pp->chCnt; ++j)
@@ -637,7 +668,26 @@ void cmApBufGet( unsigned devIdx, unsigned flags, cmApSample_t* bufArray[], unsi
637 668
   
638 669
 }
639 670
 
640
-void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufChCnt, unsigned oDevIdx, cmApSample_t* oBufArray[], unsigned oBufChCnt )
671
+void _cmApBufCalcTimeStamp( double srate, const cmTimeSpec_t* baseTimeStamp, unsigned frmCnt, cmTimeSpec_t* retTimeStamp )
672
+{
673
+  if( retTimeStamp==NULL )
674
+    return;
675
+
676
+  double   secs         = frmCnt / srate;
677
+  unsigned int_secs     = floor(secs);
678
+  double   frac_secs    = secs - int_secs;
679
+
680
+  retTimeStamp->tv_nsec = floor(baseTimeStamp->tv_nsec + frac_secs * 1000000000);
681
+  retTimeStamp->tv_sec  = baseTimeStamp->tv_sec  + int_secs;
682
+
683
+  if( retTimeStamp->tv_nsec > 1000000000 )
684
+  {
685
+    retTimeStamp->tv_nsec -= 1000000000;
686
+    retTimeStamp->tv_sec  += 1;
687
+  }
688
+}
689
+
690
+void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufChCnt, cmTimeSpec_t* iTimeStampPtr, unsigned oDevIdx, cmApSample_t* oBufArray[], unsigned oBufChCnt, cmTimeSpec_t* oTimeStampPtr )
641 691
 {
642 692
   cmApBufGet( iDevIdx, kInApFl, iBufArray, iBufChCnt );
643 693
   cmApBufGet( oDevIdx, kOutApFl,oBufArray, oBufChCnt );
@@ -651,6 +701,9 @@ void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufC
651 701
     unsigned      minChCnt = cmMin(iBufChCnt,oBufChCnt);  
652 702
     unsigned      frmCnt   = cmMin(ip->dspFrameCnt,op->dspFrameCnt);
653 703
     unsigned      byteCnt  = frmCnt * sizeof(cmApSample_t);
704
+    
705
+    _cmApBufCalcTimeStamp(ip->srate, &ip->timeStamp, ip->ioFrameCnt, iTimeStampPtr );
706
+    _cmApBufCalcTimeStamp(op->srate, &op->timeStamp, op->ioFrameCnt, oTimeStampPtr );
654 707
 
655 708
     for(i=0; i<minChCnt; ++i)
656 709
     {
@@ -681,6 +734,8 @@ void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufC
681 734
     const cmApIO* op  = _cmApBuf.devArray[oDevIdx].ioArray + kOutApIdx;
682 735
     unsigned byteCnt  = op->dspFrameCnt * sizeof(cmApSample_t);
683 736
 
737
+    _cmApBufCalcTimeStamp(op->srate, &op->timeStamp, op->ioFrameCnt, oTimeStampPtr );
738
+
684 739
     for(; i<oBufChCnt; ++i)
685 740
       if( oBufArray[i] != NULL )
686 741
         memset( oBufArray[i], 0, byteCnt );
@@ -703,12 +758,13 @@ void cmApBufAdvance( unsigned devIdx, unsigned flags )
703 758
     {
704 759
       cmApCh* cp = ioPtr->chArray + i;
705 760
       cp->oi     = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
706
-      //cp->fn    -= ioPtr->dspFrameCnt;
707 761
       cmThUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
708 762
     }
709 763
 
710
-    //ioPtr->oi     = (ioPtr->oi + ioPtr->dspFrameCnt) % ioPtr->n;
711
-    //ioPtr->fn    -= ioPtr->dspFrameCnt;
764
+    // count the number of samples input from this device
765
+    if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
766
+      cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
767
+
712 768
   }
713 769
   
714 770
   if( flags & kOutApFl )
@@ -718,13 +774,12 @@ void cmApBufAdvance( unsigned devIdx, unsigned flags )
718 774
     {
719 775
       cmApCh* cp = ioPtr->chArray + i;
720 776
       cp->ii     = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
721
-      //cp->fn    += ioPtr->dspFrameCnt;
722 777
       cmThUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
723 778
     }
724 779
 
725
-
726
-    //ioPtr->ii     = (ioPtr->ii + ioPtr->dspFrameCnt) % ioPtr->n;
727
-    //ioPtr->fn    += ioPtr->dspFrameCnt;
780
+    // count the number of samples output from this device
781
+    if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
782
+      cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
728 783
   }
729 784
 }
730 785
 

+ 8
- 2
cmApBuf.h View File

@@ -64,9 +64,12 @@ extern "C" {
64 64
     unsigned outFramesPerCycle    ///< maximum number of outgoing sample frames in an audio port cycle
65 65
                          );
66 66
 
67
-  // Prime the buffer with 'audioCycleCnt' * outFramesPerCycle samples ready to be played
67
+  /// Prime the buffer with 'audioCycleCnt' * outFramesPerCycle samples ready to be played
68 68
   cmAbRC_t cmApBufPrimeOutput( unsigned devIdx, unsigned audioCycleCnt );
69 69
 
70
+  /// Notify the audio buffer that a device is being enabled or disabled.
71
+  void     cmApBufOnPortEnable( unsigned devIdx, bool enabelFl );
72
+
70 73
   /// This function is called asynchronously by the audio device driver to transfer incoming samples to the
71 74
   /// the buffer and to send outgoing samples to the DAC. This function is 
72 75
   /// intended to be called from the audio port callback function (\see cmApCallbackPtr_t).
@@ -204,7 +207,10 @@ extern "C" {
204 207
   /// 2) The client is required to use this function to implement pass-through internally.
205 208
   /// 3) This function just returns audio information it does not
206 209
   /// change any cmApBuf() internal states.
207
-  void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufChCnt, unsigned oDevIdx, cmApSample_t* oBufArray[], unsigned oBufChCnt );
210
+  /// 4) The timestamp pointers are optional.
211
+  void cmApBufGetIO(   unsigned iDevIdx, cmApSample_t* iBufArray[], unsigned iBufChCnt, cmTimeSpec_t* iTimeStampPtr, 
212
+                       unsigned oDevIdx, cmApSample_t* oBufArray[], unsigned oBufChCnt, cmTimeSpec_t* oTimeStampPtr );
213
+
208 214
 
209 215
   /// The application calls this function each time it completes processing of a bufArray[]
210 216
   /// returned from cmApBufGet(). 'flags' can be set to either or both kInApFl and kOutApFl.

Loading…
Cancel
Save