CoreAudio提供了一系列的C接口来和底层音频设备打交道,本文先介绍如果通过C接口来获取系统音频设备列表。
1. 定义PropertyAddress
首先定义PropertyAddress,CoreAudio所有的接口访问都需要定义PropertyAddress,用于确定需要访问的属性,这是一个结构体主要包含3个成员:
1. mSelector,需要访问的属性名称,比如下面的kAudioHardwarePropertyDevices表示设备列表;
2. mScope,设备所属的域,其实就是设备属性,包括:Global(全局)、Input(输入)、Output(输出);
3. mElement,限定设备范围,一般使用kAudioObjectPropertyElementMain | kAudioObjectPropertyElementMaster (deprecated);
AudioObjectPropertyAddress addr = {
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
2. 确定返回数据大小
UInt32 size = sizeof(UInt32);
UInt32 count;
OSStatus status;
status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &size);
3. 分配内存并读取数据
count = size / sizeof(AudioDeviceID);
AudioDeviceID *ids = malloc(size);
status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, ids);
这里我们获取到的ids,就是系统的所有音频设备ID列表,再通过音频设备ID就可以获取到所有的音频设备信息。
4. 遍历获取设备详细信息
int i = 0;
CFStringRef cf_name = NULL;
CFStringRef cf_uid = NULL;
for (i = 0; i < count; i++) {
// 获取Input Streams,如果有Input Stream,说明这是一个输入设备
AudioObjectPropertyAddress propertyAddress = {
kAudioDevicePropertyStreams,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain,
};
UInt32 dataSize = sizeof(UInt32);
OSStatus status = AudioObjectGetPropertyDataSize(ids[i], &propertyAddress, 0, NULL, &dataSize);
if (noErr != status) {
NSLog(@"Error: %i", status);
}
UInt32 streamCount = dataSize / sizeof(AudioStreamID);
if (streamCount > 0) {
size = sizeof(CFStringRef);
propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
status = AudioObjectGetPropertyData(ids[i], &propertyAddress, 0, NULL, &size, &cf_name);
if (noErr == status) {
NSLog(@"Find input device: %@", (__bridge NSString *)cf_name);
}
}
// 获取Output Streams,如果有Output Stream说明是输出设备
propertyAddress.mScope = kAudioDevicePropertyScopeOutput;
propertyAddress.mSelector = kAudioDevicePropertyStreams;
dataSize = sizeof(UInt32);
status = AudioObjectGetPropertyDataSize(ids[i], &propertyAddress, 0, NULL, &dataSize);
if (noErr != status) {
NSLog(@"Error: %i", status);
}
streamCount = dataSize / sizeof(AudioStreamID);
if (streamCount > 0) {
size = sizeof(CFStringRef);
propertyAddress.mSelector = kAudioDevicePropertyDeviceNameCFString;
status = AudioObjectGetPropertyData(ids[i], &propertyAddress, 0, NULL, &size, &cf_name);
if (noErr == status) {
NSLog(@"Find output device: %@", (__bridge NSString *)cf_name);
}
}
}