在 AUHAL 上设置采样率
Posted
技术标签:
【中文标题】在 AUHAL 上设置采样率【英文标题】:Setting sample rate on AUHAL 【发布时间】:2013-08-10 05:31:29 【问题描述】:我正在使用 Audio Unit Framework 在 mac os x 上开发一个 VOIP 应用程序。 在我的程序中,我设置了一个输入 AUHAL 并使用默认的流格式(44.1kHz,32bit/channel)从麦克风捕获音频。在这种情况下,我的程序运行良好。
代码如下:
//The default setting in my program
CheckError(AudioUnitGetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, //the value is 0
inputBus, //the value is 1
&m_audCapUnitOutputStreamFormat,
&propertySize),
"Couldn't get OutputSample ASBD from input unit") ;
//the inOutputSampleRate is 44100.0
m_audCapUnitOutputStreamFormat.mSampleRate = inOutputSampleRate ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&m_audCapUnitOutputStreamFormat,
propertySize),
"Couldn't set OutputSample ASBD on input unit");
//
由于我正在开发一个 VOIP 应用程序,默认格式(44.1kHz,32bits/Channel)不适合我的程序,所以我想将采样率更改为 8kHz。 我写了这段代码来改变我程序中的格式:
//......
inOutputFormat.mSampleRate = 8000. ;
inOutputFormat.mFormatID = kAudioFormatLinearPCM ;
inOutputFormat.mChannelsPerFrame = 2 ;
inOutputFormat.mBitsPerChannel = 16 ;
inOutputFormat.mBytesPerFrame = 2 ;
inOutputFormat.mBytesPerPacket = 2 ;
inOutputFormat.mFramesPerPacket = 1 ;
inOutputFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical ;
inOutputFormat.mReserved = 0 ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&inOutputFormat,
ui32PropSize),
"Couldn't set AUHAL Unit Output Format") ;
//.......
在这种情况下,程序可以正常工作,直到我的程序在回调函数中调用AudioUnitRender
;它无法使用错误代码-10876
调用AudioUnitRender
,这意味着
kAudioUnitErr_NoConnection
在文档中。错误代码让我非常困惑,所以我用谷歌搜索了它,但找不到任何有用的信息。有人能告诉我错误的真正含义吗?
这还没完,我又被这段代码改了格式:
//.....
inOutputFormat.mSampleRate = 8000. ;
inOutputFormat.mFormatID = kAudioFormatLinearPCM ;
inOutputFormat.mChannelsPerFrame = 2 ;
inOutputFormat.mBitsPerChannel = 32 ;
inOutputFormat.mBytesPerFrame = 4 ;
inOutputFormat.mBytesPerPacket = 4 ;
inOutputFormat.mFramesPerPacket = 1 ;
inOutputFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical ;
inOutputFormat.mReserved = 0 ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&inOutputFormat,
ui32PropSize),
"Couldn't set AUHAL Unit Output Format") ;
//........
在这种情况下,程序再次调用AudioUnitRender
失败并返回另一个错误代码-10863(kAudioUnitErr_CannotDoInCurrentContext)
。我用谷歌搜索,但我发现
something useful。看了那里的资料,我猜我在AUHAL上设置的采样率或格式可能是硬件不支持的。
所以我写了一些代码来检查默认输入设备上的可用采样率:
//..........
UInt32 propertySize = sizeof(AudioDeviceID) ;
Boolean isWritable = false ;
CheckError(AudioDeviceGetPropertyInfo(inDeviceID, //the inDeviceID is the default input device
0,
true,
kAudioDevicePropertyAvailableNominalSampleRates,
&propertySize,
&isWritable),
"Get the Available Sample Rate Count Failed") ;
m_valueCount = propertySize / sizeof(AudioValueRange) ;
printf("Available %d Sample Rate\n",m_valueCount) ;
CheckError(AudioDeviceGetProperty(inDeviceID,
0,
false,
kAudioDevicePropertyAvailableNominalSampleRates,
&propertySize,
m_valueTabe),
"Get the Available Sample Rate Count Failed") ;
for(UInt32 i = 0 ; i < m_valueCount ; ++i)
printf("Available Sample Rate value : %ld\n",(long)m_valueTabe[i].mMinimum) ;
//..............
然后我发现可用的采样率是 8000、16000、32000、44100、48000、88200 和 96000。
8000的采样率是我刚才设置的,但是调用AudioUnitRender
得到一个错误码,我只想说,为什么?
我google了这么多,也看了很多文档,但我无法得到答案,有人能解决我遇到的这个问题吗?
换句话说;如何在仅输入的 AUHAL 上更改采样率或格式?
【问题讨论】:
【参考方案1】:昨天我终于自己解决了这个问题。
这是我的解决方案:
-
首先,我使用
AudioDeviceGetProperty
在我的默认输入设备上获取可用格式列表,然后我发现可用格式列表包含:8khz, 16khz, 32khz, 44.1khz, 48khz, 88.2khz,96khz
(我只是在这里列出了采样率字段,但还有其他
列表中的字段)。
然后我选择在第一步中获得的可用格式之一。以我的程序为例,我选择格式(8khz,32bits/Channel)
并使用AudioDeviceSetProperty
将其设置在默认设备上而不是AUHAL上,这是我的程序在AUHAL上设置格式后正常工作的关键(输出范围,输入总线)。
最后一步,我使用AudioUnitSetProperty
设置我想要的格式,程序运行正常。
通过这个问题和解决方案,我想如果我想在仅输入的AUHAL上设置格式,格式必须是匹配或 可以转换为输入设备正在使用的可用格式。所以我需要做的是首先在输入设备上设置格式,然后在仅输入的AUHAL上设置格式。
【讨论】:
【参考方案2】:根据我的经验,使用 44.1kHz 和 16 位音频以外的设置会导致各种奇怪的错误。一些通用的建议可能会让你走上正确的道路:
试试诺卡因 (https://github.com/alexbw/novocaine)。它确实消除了使用 AudioUnits 的痛苦。 尝试让您的应用程序以 44.1kHz 运行,然后自己对音频进行下采样。 您设置的比特率可能与所需的采样率不兼容。【讨论】:
感谢您的回复,不过我昨天已经自己解决了这个问题,您可以在我的回答中看到。【参考方案3】:你的回答对我很有帮助。但是,AudioDeviceGetProperty 的使用已被贬低。 以下清单可能有助于使事情保持最新。例如,采样率设置为 32 kHz。
// Get the available sample rates of the default input device.
defaultDeviceProperty.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
CheckError (AudioObjectGetPropertyDataSize(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
&propertySize),
"Couldn't get sample rate count");
int m_valueCount = propertySize / sizeof(AudioValueRange) ;
printf("Available %d Sample Rates\n",m_valueCount) ;
AudioValueRange m_valueTabe[m_valueCount];
CheckError (AudioObjectGetPropertyData(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
&propertySize,
m_valueTabe),
"Couldn't get available sample rates");
for(UInt32 i = 0 ; i < m_valueCount ; ++i)
printf("Available Sample Rate value : %f\n", m_valueTabe[i].mMinimum) ;
// Set the sample rate to one of the available values.
AudioValueRange inputSampleRate;
inputSampleRate.mMinimum = 32000;
inputSampleRate.mMaximum = 32000;
defaultDeviceProperty.mSelector = kAudioDevicePropertyNominalSampleRate;
CheckError (AudioObjectSetPropertyData(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
sizeof(inputSampleRate),
&inputSampleRate),
"Couldn't get available sample rates");
【讨论】:
哇,经过一天的尝试解决这个问题,您建议通过kAudioDevicePropertyNominalSampleRate
属性传递最小 AudioValueRange(不是 Float64
值)解决了给我!万分感谢!以上是关于在 AUHAL 上设置采样率的主要内容,如果未能解决你的问题,请参考以下文章