Macos 如何启用/禁用聚合CoreAudio设备的输入或输出通道?
我已经仔细阅读了这篇文章中的问题和答案: 而且似乎缺少有关解决方案的信息: 我创建了一个包含多个音频设备的聚合设备。调用core audio以接收流数时(使用kAudioDevicePropertyStreams),返回值始终为1。我还尝试了CoreAudio实用程序类中的实现:CAHALAudioDevice::GetIOProcStreamUsage。但我仍然看不到如何访问子流和禁用/启用它们。 需要做什么来实现子流的禁用/启用 编辑 以下是CAHALAudioDevice::GetIOProcStreamUsage以供参考:Macos 如何启用/禁用聚合CoreAudio设备的输入或输出通道?,macos,core-audio,Macos,Core Audio,我已经仔细阅读了这篇文章中的问题和答案: 而且似乎缺少有关解决方案的信息: 我创建了一个包含多个音频设备的聚合设备。调用core audio以接收流数时(使用kAudioDevicePropertyStreams),返回值始终为1。我还尝试了CoreAudio实用程序类中的实现:CAHALAudioDevice::GetIOProcStreamUsage。但我仍然看不到如何访问子流和禁用/启用它们。 需要做什么来实现子流的禁用/启用 编辑 以下是CAHALAudioDevice::GetIOP
void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID
inIOProcID, bool inIsInput, bool* outStreamUsage) const
{
// make an AudioHardwareIOProcStreamUsage the right size
UInt32 theNumberStreams = GetNumberStreams(inIsInput);
UInt32 theSize = SizeOf32(void*) + SizeOf32(UInt32) + (theNumberStreams * SizeOf32(UInt32));
CAAutoFree<AudioHardwareIOProcStreamUsage> theStreamUsage(theSize);
// set it up
theStreamUsage->mIOProc = reinterpret_cast<void*>(inIOProcID);
theStreamUsage->mNumberStreams = theNumberStreams;
// get the property
CAPropertyAddress theAddress(kAudioDevicePropertyIOProcStreamUsage, inIsInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput);
GetPropertyData(theAddress, 0, NULL, theSize, theStreamUsage);
// fill out the return value
for(UInt32 theIndex = 0; theIndex < theNumberStreams; ++theIndex)
{
outStreamUsage[theIndex] = (theStreamUsage->mStreamIsOn[theIndex] != 0);
}
}
void CAHALAudioDevice::GetIOProcStreamUsage(AudioDeviceIOProcID
inIOProcID,bool inIsInput,bool*超出流使用)常数
{
//将音频硬件制作成合适的大小
UInt32 theNumberStreams=GetNumberStreams(inIsInput);
UInt32 theSize=SizeOf32(void*)+SizeOf32(UInt32)+(numberstreams*SizeOf32(UInt32));
CAAutoFree Thestreamsage(theSize);
//设置它
流程->mIOProc=重新解释铸件(inIOProcID);
流程->编号流=编号流;
//取得财产
CAPropertyAddress地址(输入中的kAudioDevicePropertyIOProcStreamUsage?KaudioDevicePropertyScope输入:KaudioDevicePropertyScope输出);
GetPropertyData(地址,0,NULL,大小,流地址);
//填写返回值
对于(UInt32,索引=0;索引mStreamIsOn[theIndex]!=0);
}
}
以下是我的程序使用的函数,以供参考,以实现中描述的结果:
//告诉CoreAudio我们实际想要在设备中使用哪些输入(或输出)流
//@param devID要修改的聚合设备的CoreAudio设备ID
//@param ioProc呈现回调函数(已传递给AudioDeviceCreateIOProcID()的第二个参数)
//@param scope根据要修改的通道类型,选择kAudioObjectPropertyScopeInput或kAudioObjectPropertyScopeOutput
//@param numValidChannels我们希望在聚合设备中实际使用多少个音频通道
//@param rightJustify如果为true,我们希望使用设备中的最后一个(numValidChannels);如果为false,我们希望使用设备中的第一个(numValidChannels)
//@成功返回0,错误返回-1
//@注意此函数不会更改音频渲染回调中音频样本数据的布局;相反,它会导致回调中的某些音频通道变为零输出/未使用。
int SetProcStreamUsage(AudioDeviceID设备ID、void*ioProc、AudioObjectPropertyScope范围、int numvalidChannel、bool rightJustify)
{
const AudioObjectProperty地址大小地址=
{
kAudioDevicePropertyStreamConfiguration,
范围
kAudioObjectPropertyElementMaster
};
Uint32 streamSizesDataSize=0;
OSStatus err=AudioObjectGetPropertyDataSize(devID,&SizeAddress,0,NULL,&StreamSizeDataSize);
如果(错误!=noErr)
{
printf(“SetProcStreamUsage(%u,%i,%i):AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration)失败!\n”,(unsigned int)设备,作用域,右对齐);
返回-1;/(“AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration)失败”);
}
const AudioObjectPropertyAddress usageAddress=
{
kAudioDevicePropertyIOProcStreamUsage,
范围
kAudioObjectPropertyElementMaster
};
Uint32 streamUsageDataSize=0;
err=AudioObjectGetPropertyDataSize(devID,&usageAddress,0,NULL,&streamUsageDataSize);
如果(错误!=noErr)
{
printf(“SetProcStreamUsage(%u,%i,%i):AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage)失败!\n”,(unsigned int)设备,范围,右对齐);
返回-1;/(“AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage)失败”);
}
AudioBufferList*bufList=(AudioBufferList*)malloc(streamSizesDataSize);//使用malloc(),因为对象大小是可变的
if(bufList)
{
int ret;
err=AudioObjectGetPropertyData(devID,&SizeAddress,0,NULL,&StreamSizeDataSize,bufList);
如果(err==noErr)
{
AudioHardwareIOProcStreamUsage*streamUsage=(AudioHardwareIOProcStreamUsage*)malloc(streamUsageDataSize);//使用malloc(),因为对象大小是可变的
如果(流量使用)
{
streamUsage->mIOProc=ioProc;
err=AudioObjectGetPropertyData(设备、usageAddress、0、NULL和streamUsageDataSize、streamUsage);
如果(err==noErr)
{
如果(bufList->mNumberBuffers==streamUsage->mNumberStreams)
{
Int32 numChannelsLeft=numValidChannels;
如果(右对齐)
{
//我们只希望启用与最后(N)个通道对应的流
对于(Int32 i=streamUsage->mNumberStreams-1;i>=0;i--)
{
streamUsage->mStreamIsOn[i]=(numChannelsLeft>0);
numChannelsLeft-=bufList->mBuffers[i].mNumberChannels;
}
}
其他的
{
//我们只希望启用对应于前(N)个通道的流
对于(Uint32 i=0;imNumberStreams;i++)
{
streamUsage->mStreamIsOn[i]=(numChannelsLeft>0);
numChannelsL
// Tell CoreAudio which input (or output) streams we actually want to use in our device
// @param devID the CoreAudio audio device ID of the aggregate device to modify
// @param ioProc the rendering callback-function (as was passed to AudioDeviceCreateIOProcID()'s second argument)
// @param scope either kAudioObjectPropertyScopeInput or kAudioObjectPropertyScopeOutput depending on which type of channels we want to modify
// @param numValidChannels how many audio channels in the aggregate device we want to actually use
// @param rightJustify if true, we want to use the last (numValidChannels) in the device; if false we want to use the first (numValidChannels) in the device
// @returns 0 on success or -1 on error
// @note this function doesn't change the layout of the audio-sample data in the audio-render callback; rather it causes some channels of audio in the callback to become zero'd out/unused.
int SetProcStreamUsage(AudioDeviceID devID, void * ioProc, AudioObjectPropertyScope scope, int numValidChannels, bool rightJustify)
{
const AudioObjectPropertyAddress sizesAddress =
{
kAudioDevicePropertyStreamConfiguration,
scope,
kAudioObjectPropertyElementMaster
};
Uint32 streamSizesDataSize = 0;
OSStatus err = AudioObjectGetPropertyDataSize(devID, &sizesAddress, 0, NULL, &streamSizesDataSize);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration) failed!\n", (unsigned int) devID, scope, rightJustify);
return -1; // ("AudioObjectGetPropertyDataSize(kAudioDevicePropertyStreamConfiguration) failed");
}
const AudioObjectPropertyAddress usageAddress =
{
kAudioDevicePropertyIOProcStreamUsage,
scope,
kAudioObjectPropertyElementMaster
};
Uint32 streamUsageDataSize = 0;
err = AudioObjectGetPropertyDataSize(devID, &usageAddress, 0, NULL, &streamUsageDataSize);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
return -1; // ("AudioObjectGetPropertyDataSize(kAudioDevicePropertyIOProcStreamUsage) failed");
}
AudioBufferList * bufList = (AudioBufferList*) malloc(streamSizesDataSize); // using malloc() because the object-size is variable
if (bufList)
{
int ret;
err = AudioObjectGetPropertyData(devID, &sizesAddress, 0, NULL, &streamSizesDataSize, bufList);
if (err == noErr)
{
AudioHardwareIOProcStreamUsage * streamUsage = (AudioHardwareIOProcStreamUsage *) malloc(streamUsageDataSize); // using malloc() because the object-size is variable
if (streamUsage)
{
streamUsage->mIOProc = ioProc;
err = AudioObjectGetPropertyData(devID, &usageAddress, 0, NULL, &streamUsageDataSize, streamUsage);
if (err == noErr)
{
if (bufList->mNumberBuffers == streamUsage->mNumberStreams)
{
Int32 numChannelsLeft = numValidChannels;
if (rightJustify)
{
// We only want streams corresponding to the last (N) channels to be enabled
for (Int32 i=streamUsage->mNumberStreams-1; i>=0; i--)
{
streamUsage->mStreamIsOn[i] = (numChannelsLeft > 0);
numChannelsLeft -= bufList->mBuffers[i].mNumberChannels;
}
}
else
{
// We only want streams corresponding to the first (N) channels to be enabled
for (Uint32 i=0; i<streamUsage->mNumberStreams; i++)
{
streamUsage->mStreamIsOn[i] = (numChannelsLeft > 0);
numChannelsLeft -= bufList->mBuffers[i].mNumberChannels;
}
}
// Now set the stream-usage per our update, above
err = AudioObjectSetPropertyData(devID, &usageAddress, 0, NULL, streamUsageDataSize, streamUsage);
if (err != noErr)
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed");
}
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): #Buffers (%u) doesn't match #Streams (%u)!\n", (unsigned int) devID, scope, rightJustify, bufList->mNumberBuffers, streamUsage->mNumberStreams);
ret = -1;
}
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectSetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectGetPropertyData(kAudioDevicePropertyIOProcStreamUsage) failed");
}
free(streamUsage);
}
else ret = -1; // out of memory?
}
else
{
printf("SetProcStreamUsage(%u,%i,%i): AudioObjectGetPropertyData(kAudioDevicePropertyStreamConfiguration) failed!\n", (unsigned int) devID, scope, rightJustify);
ret = -1; // ("AudioObjectGetPropertyData(kAudioDevicePropertyStreamConfiguration) failed");
}
free(bufList);
return ret;
}
else return -1; // out of memory?
}