|
@@ -2,6 +2,7 @@
|
2
|
2
|
#include "cmPrefix.h"
|
3
|
3
|
#include "cmGlobal.h"
|
4
|
4
|
#include "cmRpt.h"
|
|
5
|
+#include "cmTime.h"
|
5
|
6
|
#include "cmAudioPort.h"
|
6
|
7
|
#include "cmMem.h"
|
7
|
8
|
#include "cmTime.h"
|
|
@@ -598,7 +599,6 @@ void _cmApStateRecover( snd_pcm_t* pcmH, cmApDevRecd_t* drp, bool inputFl )
|
598
|
599
|
// set smpPtr to NULL to write a buffer of silence
|
599
|
600
|
int _cmApWriteBuf( const cmApDevRecd_t* drp, snd_pcm_t* pcmH, const cmApSample_t* sp, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
|
600
|
601
|
{
|
601
|
|
-
|
602
|
602
|
int err = 0;
|
603
|
603
|
unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
|
604
|
604
|
unsigned smpCnt = chCnt * frmCnt;
|
|
@@ -774,13 +774,14 @@ void _cmApStaticAsyncHandler( snd_async_handler_t* ahandler )
|
774
|
774
|
pkt.flags = kInterleavedApFl | kFloatApFl;
|
775
|
775
|
pkt.audioBytesPtr = b;
|
776
|
776
|
pkt.userCbPtr = drp->userCbPtr;
|
777
|
|
-
|
|
777
|
+
|
778
|
778
|
recdCb(drp,inputFl,0);
|
779
|
779
|
|
780
|
780
|
_cmApStateRecover( pcmH, drp, inputFl );
|
781
|
781
|
|
782
|
782
|
while( (avail = snd_pcm_avail_update(pcmH)) >= (snd_pcm_sframes_t)frmCnt )
|
783
|
783
|
{
|
|
784
|
+
|
784
|
785
|
// Handle inpuut
|
785
|
786
|
if( inputFl )
|
786
|
787
|
{
|
|
@@ -853,6 +854,7 @@ bool _cmApThreadFunc(void* param)
|
853
|
854
|
unsigned short revents = 0;
|
854
|
855
|
int err;
|
855
|
856
|
cmApAudioPacket_t pkt;
|
|
857
|
+ snd_pcm_uframes_t avail_frames;
|
856
|
858
|
|
857
|
859
|
inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
|
858
|
860
|
|
|
@@ -867,6 +869,35 @@ bool _cmApThreadFunc(void* param)
|
867
|
869
|
|
868
|
870
|
inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
|
869
|
871
|
|
|
872
|
+ // get the timestamp for this buffer
|
|
873
|
+ if((err = snd_pcm_htimestamp(pcmH,&avail_frames,&pkt.timeStamp)) != 0 )
|
|
874
|
+ {
|
|
875
|
+ _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Get timestamp error.");
|
|
876
|
+ pkt.timeStamp.tv_sec = 0;
|
|
877
|
+ pkt.timeStamp.tv_nsec = 0;
|
|
878
|
+ }
|
|
879
|
+
|
|
880
|
+ // Note that based on experimenting with the timestamp and the current
|
|
881
|
+ // clock_gettime(CLOCK_MONOTONIC) time it appears that the time stamp
|
|
882
|
+ // marks the end of the current buffer - so in fact the time stamp should
|
|
883
|
+ // be backed up by the availble sample count period to get the time of the
|
|
884
|
+ // first sample in the buffer
|
|
885
|
+ /*
|
|
886
|
+ unsigned avail_nano_secs = (unsigned)(avail_frames * (1000000000.0/drp->srate));
|
|
887
|
+ if( pkt.timeStamp.tv_nsec > avail_nano_secs )
|
|
888
|
+ pkt.timeStamp.tv_nsec -= avail_nano_secs;
|
|
889
|
+ else
|
|
890
|
+ {
|
|
891
|
+ pkt.timeStamp.tv_sec -= 1;
|
|
892
|
+ pkt.timeStamp.tv_nsec = 1000000000 - avail_nano_secs;
|
|
893
|
+ }
|
|
894
|
+ */
|
|
895
|
+
|
|
896
|
+ //printf("AUDI: %ld %ld\n",pkt.timeStamp.tv_sec,pkt.timeStamp.tv_nsec);
|
|
897
|
+ //cmTimeSpec_t t;
|
|
898
|
+ //clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t);
|
|
899
|
+ //printf("AUDI: %ld %ld\n",t.tv_sec,t.tv_nsec);
|
|
900
|
+
|
870
|
901
|
|
871
|
902
|
switch( snd_pcm_state(pcmH) )
|
872
|
903
|
{
|
|
@@ -910,6 +941,22 @@ bool _cmApThreadFunc(void* param)
|
910
|
941
|
|
911
|
942
|
if( !inputFl && (revents & POLLOUT) )
|
912
|
943
|
{
|
|
944
|
+
|
|
945
|
+ /*
|
|
946
|
+ unsigned srate = 96;
|
|
947
|
+ cmTimeSpec_t t1;
|
|
948
|
+ static cmTimeSpec_t t0 = {0,0};
|
|
949
|
+ clock_gettime(CLOCK_MONOTONIC,&t1);
|
|
950
|
+
|
|
951
|
+ // time since the time-stamp was generated
|
|
952
|
+ unsigned smp = (srate * (t1.tv_nsec - pkt.timeStamp.tv_nsec)) / 1000000;
|
|
953
|
+
|
|
954
|
+ // time since the last output buffer was sent
|
|
955
|
+ unsigned dsmp = (srate * (t1.tv_nsec - t0.tv_nsec)) / 1000000;
|
|
956
|
+ printf("%i %ld %i : %ld %ld -> %ld %ld\n",smp,avail_frames,dsmp,pkt.timeStamp.tv_sec,pkt.timeStamp.tv_nsec,t1.tv_sec,t1.tv_nsec);
|
|
957
|
+ t0 = t1;
|
|
958
|
+ */
|
|
959
|
+
|
913
|
960
|
// callback to fill the buffer
|
914
|
961
|
drp->cbPtr(NULL,0,&pkt,1);
|
915
|
962
|
|
|
@@ -1062,6 +1109,9 @@ bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle,
|
1062
|
1109
|
if((err = snd_pcm_sw_params_set_avail_min(pcmH,swParams,periodFrameCnt)) < 0 )
|
1063
|
1110
|
retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the avail. min. setting.");
|
1064
|
1111
|
|
|
1112
|
+ if((err = snd_pcm_sw_params_set_tstamp_mode(pcmH,swParams,SND_PCM_TSTAMP_MMAP)) < 0 )
|
|
1113
|
+ retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the time samp mode.");
|
|
1114
|
+
|
1065
|
1115
|
if((err = snd_pcm_sw_params(pcmH,swParams)) < 0 )
|
1066
|
1116
|
retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error applying sw params.");
|
1067
|
1117
|
}
|
|
@@ -1589,6 +1639,13 @@ cmApRC_t cmApAlsaDeviceStop( unsigned devIdx )
|
1589
|
1639
|
if((err = snd_pcm_drop(drp->oPcmH)) < 0 )
|
1590
|
1640
|
retFl = _cmApDevSetupError(p,err,false,drp,"Output stop failed.");
|
1591
|
1641
|
|
|
1642
|
+ if( p->asyncFl == false )
|
|
1643
|
+ if( cmThreadPause(p->thH,kPauseThFl) != kOkThRC )
|
|
1644
|
+ {
|
|
1645
|
+ _cmApOsError(p,0,"Audio thread pause failed.");
|
|
1646
|
+ retFl = false;
|
|
1647
|
+ }
|
|
1648
|
+
|
1592
|
1649
|
return retFl ? kOkApRC : kSysErrApRC;
|
1593
|
1650
|
}
|
1594
|
1651
|
|