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 11 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
 #include "cmErr.h"
4
 #include "cmErr.h"
5
 #include "cmMem.h"
5
 #include "cmMem.h"
6
 #include "cmMallocDebug.h"
6
 #include "cmMallocDebug.h"
7
+#include "cmTime.h"
7
 #include "cmAudioPort.h"
8
 #include "cmAudioPort.h"
8
 #include "cmApBuf.h"
9
 #include "cmApBuf.h"
9
 #include "cmThread.h"
10
 #include "cmThread.h"
64
 
65
 
65
 typedef struct
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
 } cmApIO;
80
 } cmApIO;
78
 
81
 
169
 
172
 
170
   n += (n % dspFrameCnt); // force buffer size to be a multiple of dspFrameCnt
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
   for(i=0; i<chCnt; ++i )
186
   for(i=0; i<chCnt; ++i )
181
     _cmApChInitialize( ioPtr->chArray + i, n, meterBufN );
187
     _cmApChInitialize( ioPtr->chArray + i, n, meterBufN );
277
   return kOkAbRC;
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
 cmAbRC_t cmApBufUpdate(
304
 cmAbRC_t cmApBufUpdate(
281
   cmApAudioPacket_t*  inPktArray, 
305
   cmApAudioPacket_t*  inPktArray, 
282
   unsigned           inPktCnt, 
306
   unsigned           inPktCnt, 
293
       cmApAudioPacket_t*  pp  = inPktArray + i;           
317
       cmApAudioPacket_t*  pp  = inPktArray + i;           
294
       cmApIO*             ip  = _cmApBuf.devArray[pp->devIdx].ioArray + kInApIdx; // dest io recd
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
       // for each source packet channel and enabled dest channel
324
       // for each source packet channel and enabled dest channel
297
       for(j=0; j<pp->chCnt; ++j)
325
       for(j=0; j<pp->chCnt; ++j)
298
       {
326
       {
369
       cmApAudioPacket_t* pp = outPktArray + i;           
397
       cmApAudioPacket_t* pp = outPktArray + i;           
370
       cmApIO*            op = _cmApBuf.devArray[pp->devIdx].ioArray + kOutApIdx; // dest io recd
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
       // for each dest packet channel and enabled source channel
404
       // for each dest packet channel and enabled source channel
374
       for(j=0; j<pp->chCnt; ++j)
405
       for(j=0; j<pp->chCnt; ++j)
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
   cmApBufGet( iDevIdx, kInApFl, iBufArray, iBufChCnt );
692
   cmApBufGet( iDevIdx, kInApFl, iBufArray, iBufChCnt );
643
   cmApBufGet( oDevIdx, kOutApFl,oBufArray, oBufChCnt );
693
   cmApBufGet( oDevIdx, kOutApFl,oBufArray, oBufChCnt );
651
     unsigned      minChCnt = cmMin(iBufChCnt,oBufChCnt);  
701
     unsigned      minChCnt = cmMin(iBufChCnt,oBufChCnt);  
652
     unsigned      frmCnt   = cmMin(ip->dspFrameCnt,op->dspFrameCnt);
702
     unsigned      frmCnt   = cmMin(ip->dspFrameCnt,op->dspFrameCnt);
653
     unsigned      byteCnt  = frmCnt * sizeof(cmApSample_t);
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
     for(i=0; i<minChCnt; ++i)
708
     for(i=0; i<minChCnt; ++i)
656
     {
709
     {
681
     const cmApIO* op  = _cmApBuf.devArray[oDevIdx].ioArray + kOutApIdx;
734
     const cmApIO* op  = _cmApBuf.devArray[oDevIdx].ioArray + kOutApIdx;
682
     unsigned byteCnt  = op->dspFrameCnt * sizeof(cmApSample_t);
735
     unsigned byteCnt  = op->dspFrameCnt * sizeof(cmApSample_t);
683
 
736
 
737
+    _cmApBufCalcTimeStamp(op->srate, &op->timeStamp, op->ioFrameCnt, oTimeStampPtr );
738
+
684
     for(; i<oBufChCnt; ++i)
739
     for(; i<oBufChCnt; ++i)
685
       if( oBufArray[i] != NULL )
740
       if( oBufArray[i] != NULL )
686
         memset( oBufArray[i], 0, byteCnt );
741
         memset( oBufArray[i], 0, byteCnt );
703
     {
758
     {
704
       cmApCh* cp = ioPtr->chArray + i;
759
       cmApCh* cp = ioPtr->chArray + i;
705
       cp->oi     = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
760
       cp->oi     = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
706
-      //cp->fn    -= ioPtr->dspFrameCnt;
707
       cmThUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
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
   if( flags & kOutApFl )
770
   if( flags & kOutApFl )
718
     {
774
     {
719
       cmApCh* cp = ioPtr->chArray + i;
775
       cmApCh* cp = ioPtr->chArray + i;
720
       cp->ii     = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
776
       cp->ii     = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
721
-      //cp->fn    += ioPtr->dspFrameCnt;
722
       cmThUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
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
     unsigned outFramesPerCycle    ///< maximum number of outgoing sample frames in an audio port cycle
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
   cmAbRC_t cmApBufPrimeOutput( unsigned devIdx, unsigned audioCycleCnt );
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
   /// This function is called asynchronously by the audio device driver to transfer incoming samples to the
73
   /// This function is called asynchronously by the audio device driver to transfer incoming samples to the
71
   /// the buffer and to send outgoing samples to the DAC. This function is 
74
   /// the buffer and to send outgoing samples to the DAC. This function is 
72
   /// intended to be called from the audio port callback function (\see cmApCallbackPtr_t).
75
   /// intended to be called from the audio port callback function (\see cmApCallbackPtr_t).
204
   /// 2) The client is required to use this function to implement pass-through internally.
207
   /// 2) The client is required to use this function to implement pass-through internally.
205
   /// 3) This function just returns audio information it does not
208
   /// 3) This function just returns audio information it does not
206
   /// change any cmApBuf() internal states.
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
   /// The application calls this function each time it completes processing of a bufArray[]
215
   /// The application calls this function each time it completes processing of a bufArray[]
210
   /// returned from cmApBufGet(). 'flags' can be set to either or both kInApFl and kOutApFl.
216
   /// returned from cmApBufGet(). 'flags' can be set to either or both kInApFl and kOutApFl.

Loading…
Cancel
Save