libcw/cwAudioDeviceTest.cpp
kpl 5a62d884dd Standardized filesys and mem namespaces.
Removed use of global variable in cwAudioBuf.
2019-12-27 21:51:28 -05:00

276 lines
8.8 KiB
C++

#include "cwCommon.h"
#include "cwLog.h"
#include "cwCommonImpl.h"
#include "cwMem.h"
#include "cwTime.h"
#include "cwTextBuf.h"
#include "cwAudioDevice.h"
#include "cwAudioBuf.h"
#include "cwAudioDeviceAlsa.h"
#include "cwAudioDeviceTest.h"
namespace cw
{
namespace audio
{
namespace device
{
/// [cmAudioPortExample]
// See test() below for the main point of entry.
// Data structure used to hold the parameters for cpApPortTest()
// and the user defined data record passed to the host from the
// audio port callback functions.
typedef struct
{
unsigned bufCnt; // 2=double buffering 3=triple buffering
unsigned chIdx; // first test channel
//unsigned chCnt; // count of channels to test
unsigned framesPerCycle; // DSP frames per cycle
unsigned bufFrmCnt; // count of DSP frames used by the audio buffer (bufCnt * framesPerCycle)
unsigned bufSmpCnt; // count of samples used by the audio buffer (chCnt * bufFrmCnt)
unsigned inDevIdx; // input device index
unsigned outDevIdx; // output device index
double srate; // audio sample rate
unsigned meterMs; // audio meter buffer length
unsigned iCbCnt; // count the callback
unsigned oCbCnt;
buf::handle_t audioBufH;
} cmApPortTestRecd;
// print the usage message for cmAudioPortTest.c
void _cmApPrintUsage()
{
char msg[] =
"cmApPortTest() command switches\n"
"-r <srate> -c <chcnt> -b <bufcnt> -f <frmcnt> -i <idevidx> -o <odevidx> -t -p -h \n"
"\n"
"-r <srate> = sample rate\n"
"-a <chidx> = first channel\n"
"-c <chcnt> = audio channels\n"
"-b <bufcnt> = count of buffers\n"
"-f <frmcnt> = count of samples per buffer\n"
"-i <idevidx> = input device index\n"
"-o <odevidx> = output device index\n"
"-p = print report but do not start audio devices\n"
"-h = print this usage message\n";
cwLogInfo(msg);
}
// Get a command line option. Note that if 'boolFl' is set to 'true' then the function simply
// returns '1'. This is used to handle arguments whose presense indicates a positive boolean
// flag. For example -h (help) indicates that the usage data should be printed - it needs no other argument.
int _cmApGetOpt( int argc, const char* argv[], const char* label, int defaultVal, bool boolFl=false )
{
int i = 0;
for(; i<argc; ++i)
if( strcmp(label,argv[i]) == 0 )
{
if(boolFl)
return 1;
if( i == (argc-1) )
return defaultVal;
return atoi(argv[i+1]);
}
return defaultVal;
}
unsigned _cmGlobalInDevIdx = 0;
unsigned _cmGlobalOutDevIdx = 0;
void _cmApPortCb2( void* arg, audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt )
{
cmApPortTestRecd* p = static_cast<cmApPortTestRecd*>(arg);
for(unsigned i=0; i<inPktCnt; ++i)
static_cast<cmApPortTestRecd*>(inPktArray[i].cbArg)->iCbCnt++;
for(unsigned i=0; i<outPktCnt; ++i)
static_cast<cmApPortTestRecd*>(outPktArray[i].cbArg)->oCbCnt++;
buf::inputToOutput( p->audioBufH, _cmGlobalInDevIdx, _cmGlobalOutDevIdx );
buf::update( p->audioBufH, inPktArray, inPktCnt, outPktArray, outPktCnt );
}
}
}
}
// Audio Port testing function
cw::rc_t cw::audio::device::test( int argc, const char** argv )
{
cmApPortTestRecd r;
unsigned i;
rc_t rc;
driver_t* drv = nullptr;
handle_t h;
alsa::handle_t alsaH;
bool runFl = true;
if( _cmApGetOpt(argc,argv,"-h",0,true) )
_cmApPrintUsage();
runFl = _cmApGetOpt(argc,argv,"-p",0,true)?false:true;
r.srate = _cmApGetOpt(argc,argv,"-r",44100);
//r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
//r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3);
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512);
//r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
//r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
//r.logCnt = 100;
r.meterMs = 50;
r.inDevIdx = _cmGlobalInDevIdx = _cmApGetOpt(argc,argv,"-i",0);
r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",0);
r.iCbCnt = 0;
r.oCbCnt = 0;
//cwLogInfo("Program cfg: %s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f",runFl?"exec":"rpt",r.inDevIdx,r.outDevIdx,r.chIdx,r.chCnt,r.bufCnt,r.framesPerCycle,r.srate);
// initialize the audio device interface
if((rc = create(h)) != kOkRC )
{
cwLogInfo("Initialize failed.");
goto errLabel;
}
// initialize the ALSA device driver interface
if((rc = alsa::create(alsaH, drv )) != kOkRC )
{
cwLogInfo("ALSA initialize failed.");
goto errLabel;
}
// register the ALSA device driver with the audio interface
if((rc = registerDriver( h, drv )) != kOkRC )
{
cwLogInfo("ALSA driver registration failed.");
goto errLabel;
}
// report the current audio device configuration
for(i=0; i<deviceCount(h); ++i)
{
cwLogInfo("%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%8.1f %s",i,deviceChannelCount(h,i,true),deviceFramesPerCycle(h,i,true),deviceChannelCount(h,i,false),deviceFramesPerCycle(h,i,false),deviceSampleRate(h,i),deviceLabel(h,i));
}
// report the current audio devices using the audio port interface function
//report(h);
if( runFl )
{
// initialize the audio bufer
buf::create( r.audioBufH, deviceCount(h), r.meterMs );
// setup the buffer for the output device
buf::setup( r.audioBufH, r.outDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.outDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.outDevIdx,false), r.framesPerCycle );
// setup the buffer for the input device
//if( r.inDevIdx != r.outDevIdx )
buf::setup( r.audioBufH, r.inDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.inDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.inDevIdx,false), r.framesPerCycle );
// setup an output device
if(deviceSetup(h, r.outDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
cwLogInfo("Out device setup failed.");
else
// setup an input device
if( deviceSetup(h, r.inDevIdx,r.srate,r.framesPerCycle,_cmApPortCb2,&r) != kOkRC )
cwLogInfo("In device setup failed.");
else
// start the input device
if( deviceStart(h, r.inDevIdx) != kOkRC )
cwLogInfo("In device start failed.");
else
// start the output device
if( deviceStart(h, r.outDevIdx) != kOkRC )
cwLogInfo("Out Device start failed.");
else
cwLogInfo("Setup complete!");
cwLogInfo("q=quit O/o output tone, I/i input tone, P/p pass M/m meter s=buf report");
// turn on the meters
buf::enableMeter(r.audioBufH, r.outDevIdx,-1,buf::kOutFl | buf::kEnableFl);
char c;
while((c=getchar()) != 'q')
{
deviceRealTimeReport(h, r.outDevIdx );
switch(c)
{
case 'i':
case 'I':
buf::enableTone(r.audioBufH, r.inDevIdx,-1,buf::kInFl | (c=='I'?buf::kEnableFl:0));
break;
case 'o':
case 'O':
buf::enableTone(r.audioBufH, r.outDevIdx,-1,buf::kOutFl | (c=='O'?buf::kEnableFl:0));
break;
case 'p':
case 'P':
buf::enablePass(r.audioBufH, r.outDevIdx,-1,buf::kOutFl | (c=='P'?buf::kEnableFl:0));
break;
case 'M':
case 'm':
buf::enableMeter( r.audioBufH, r.inDevIdx, -1, buf::kInFl | (c=='M'?buf::kEnableFl:0));
buf::enableMeter( r.audioBufH, r.outDevIdx, -1, buf::kOutFl | (c=='M'?buf::kEnableFl:0));
break;
case 's':
buf::report(r.audioBufH);
break;
}
}
// stop the input device
if( deviceIsStarted(h,r.inDevIdx) )
if( deviceStop(h,r.inDevIdx) != kOkRC )
cwLogInfo("In device stop failed.");
// stop the output device
if( deviceIsStarted(h,r.outDevIdx) )
if( deviceStop(h,r.outDevIdx) != kOkRC )
cwLogInfo("Out device stop failed.");
}
errLabel:
// release the ALSA driver
rc_t rc0 = alsa::destroy(alsaH);
// release any resources held by the audio port interface
rc_t rc1 = destroy(h);
rc_t rc2 = buf::destroy(r.audioBufH);
//cmApNrtFree();
//cmApFileFree();
// report the count of audio buffer callbacks
cwLogInfo("cb count: i:%i o:%i", r.iCbCnt, r.oCbCnt );
return rcSelect(rc,rc0,rc1,rc2);
}
/// [cmAudioPortExample]