ASIO 获取音频参数init_asio_static_data函数
2022-02-07
118
0
要打开音频设备,总得先获取参数吧。
比如UAC设备,在打开MIC时,系统会通过特定类请求设置采样率,这样固件会源源不断地通过此采样率获取音频数据,然后通过USB要同步传输将数据发送给主机。
在ASIO中,获取ASIO设备的参数有几个函数,详情可见:ASIO 函数功能介绍 。
ASIO的测试用例是通过init_asio_static_data()函数来初始化ASIO设备,然后打开设备进行MIC数据采样的,其主要流程如下:
- 通过ASIOGetChannels获取通道数
- 通过ASIOGetBufferSize获取数据缓冲区大小
- 通过ASIOGetSampleRate获取ASIO设备支持的采样率
- 如果采样率过大或过小,则通过ASIOSetSampleRate设置工作时的采样率为44100。
- 通过ASIOOutputReady判断输出通道是否准备好
当然,获取的这些数据是需要保存在内存中,以供在实际获取音频数据时的使用,所以这些参数包存在DriverInfo结构体中。
// internal data storage
typedef struct DriverInfo
{
// ASIOInit()
ASIODriverInfo driverInfo;
// ASIOGetChannels()
long inputChannels;
long outputChannels;
// ASIOGetBufferSize()
long minSize;
long maxSize;
long preferredSize;
long granularity;
// ASIOGetSampleRate()
ASIOSampleRate sampleRate;
// ASIOOutputReady()
bool postOutput;
// ASIOGetLatencies ()
long inputLatency;
long outputLatency;
// ASIOCreateBuffers ()
long inputBuffers; // becomes number of actual created input buffers
long outputBuffers; // becomes number of actual created output buffers
ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
// ASIOGetChannelInfo()
ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
// The above two arrays share the same indexing, as the data in them are linked together
// Information from ASIOGetSamplePosition()
// data is converted to double floats for easier use, however 64 bit integer can be used, too
double nanoSeconds;
double samples;
double tcSamples; // time code samples
// bufferSwitchTimeInfo()
ASIOTime tInfo; // time info state
unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
// Signal the end of processing in this example
bool stopped;
} DriverInfo;
代码流程如下:
long init_asio_static_data (DriverInfo *asioDriverInfo)
{ // collect the informational data of the driver
// get the number of available channels
if(ASIOGetChannels(&asioDriverInfo->inputChannels, &asioDriverInfo->outputChannels) == ASE_OK)
{
printf ("ASIOGetChannels (inputs: %d, outputs: %d);\n", asioDriverInfo->inputChannels, asioDriverInfo->outputChannels);
// get the usable buffer sizes
if(ASIOGetBufferSize(&asioDriverInfo->minSize, &asioDriverInfo->maxSize, &asioDriverInfo->preferredSize, &asioDriverInfo->granularity) == ASE_OK)
{
printf ("ASIOGetBufferSize (min: %d, max: %d, preferred: %d, granularity: %d);\n",
asioDriverInfo->minSize, asioDriverInfo->maxSize,
asioDriverInfo->preferredSize, asioDriverInfo->granularity);
// get the currently selected sample rate
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
{
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
if (asioDriverInfo->sampleRate <= 0.0 || asioDriverInfo->sampleRate > 96000.0)
{
// Driver does not store it's internal sample rate, so set it to a know one.
// Usually you should check beforehand, that the selected sample rate is valid
// with ASIOCanSampleRate().
if(ASIOSetSampleRate(44100.0) == ASE_OK)
{
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
else
return -6;
}
else
return -5;
}
// check wether the driver requires the ASIOOutputReady() optimization
// (can be used by the driver to reduce output latency by one block)
if(ASIOOutputReady() == ASE_OK)
asioDriverInfo->postOutput = true;
else
asioDriverInfo->postOutput = false;
printf ("ASIOOutputReady(); - %s\n", asioDriverInfo->postOutput ? "Supported" : "Not supported");
return 0;
}
return -3;
}
return -2;
}
return -1;
}
运行结果如下:
asioVersion: 0
driverVersion: 1
Name: Sample ASIO
ErrorMessage: No ASIO Driver Error
ASIOGetChannels (inputs: 16, outputs: 16);
ASIOGetBufferSize (min: 256, max: 256, preferred: 256, granularity: 0);
ASIOGetSampleRate (sampleRate: 44100.000000);
ASIOOutputReady(); - Not supported
获取通道数量ASIOGetChannels
ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels)
{
if(!theAsioDriver)
{
*numInputChannels = *numOutputChannels = 0;
return ASE_NotPresent;
}
return theAsioDriver->getChannels(numInputChannels, numOutputChannels);
}
由COM实始化:
ASIOError AsioSample::getChannels (long *numInputChannels, long *numOutputChannels)
{
*numInputChannels = kNumInputs;
*numOutputChannels = kNumOutputs;
return ASE_OK;
}
enum
{
kBlockFrames = 256,
kNumInputs = 16,
kNumOutputs = 16
};
获取缓冲区参数ASIOGetBufferSize
ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity)
{
if(!theAsioDriver)
{
*minSize = *maxSize = *preferredSize = *granularity = 0;
return ASE_NotPresent;
}
return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity);
}
由COM初始化
ASIOError AsioSample::getBufferSize (long *minSize, long *maxSize,
long *preferredSize, long *granularity)
{
*minSize = *maxSize = *preferredSize = blockFrames; // allow this size only
*granularity = 0;
return ASE_OK;
}
颗粒度granularity=0,而blockFrames=256,由构造函数实现
AsioSample::AsioSample (LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown("ASIOSAMPLE", pUnk, phr)
{
blockFrames = kBlockFrames;
inputLatency = blockFrames; // typically
outputLatency = blockFrames * 2;
}
enum
{
kBlockFrames = 256,
kNumInputs = 16,
kNumOutputs = 16
};
获取采样率ASIOGetSampleRate
ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->getSampleRate(currentRate);
}
而COM初始化为
ASIOError AsioSample::getSampleRate (ASIOSampleRate *sampleRate)
{
*sampleRate = this->sampleRate;
return ASE_OK;
}
构造函数将将采样率设为:
AsioSample::AsioSample (LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown("ASIOSAMPLE", pUnk, phr)
{
...
sampleRate = 44100.
}
模拟仿真判断,使用ASIOOutputReady判断
ASIOError ASIOOutputReady(void)
{
if(!theAsioDriver)
return ASE_NotPresent;
return theAsioDriver->outputReady();
}
ASIOError AsioSample::outputReady ()
{
return ASE_NotPresent;
}
enum {
ASE_OK = 0, // This value will be returned whenever the call succeeded
ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls
ASE_NotPresent = -1000, // hardware input or output is not present or available
ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function)
ASE_InvalidParameter, // input parameter invalid
ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode
ASE_SPNotAdvancing, // hardware is not running when sample position is inquired
ASE_NoClock, // sample clock or rate cannot be determined or is not present
ASE_NoMemory // not enough memory for completing the request
};
这里表示的是软件模拟的,即硬件输出输入不存在,故处于测试态。所以执行
asioDriverInfo->postOutput = false;
并输出:
ASIOOutputReady(); - Not supported