设置 AVAudioEngine 输入和输出设备

Posted

技术标签:

【中文标题】设置 AVAudioEngine 输入和输出设备【英文标题】:Set AVAudioEngine Input and Output Devices 【发布时间】:2015-05-01 02:55:51 【问题描述】:

我一直在使用 Apple 闪亮的新 AVFoundation 库,但到目前为止,我无法设置 AVAudioEngine 使用的输入或输出设备(例如 USB 声卡),但我可以'似乎在文档中找不到任何东西说它甚至是可能的。

有人有这方面的经验吗?

【问题讨论】:

从长远来看,我尝试将AVAudioEnginemainMixerNode 转换为实际有效的AVAudioIONode(出于某种原因?) - 这是一个开始。 【参考方案1】:

好的,在第十次重新阅读文档后,我注意到 AVAudioEngine 有成员 inputNode 和 outputNode(不知道我是怎么错过的!)。

以下代码似乎可以完成这项工作:

AudioDeviceID inputDeviceID = 53; // get this using AudioObjectGetPropertyData
AVAudioEngine *engine = [[AVAudioEngine alloc] init];
AudioUnit audioUnit = [[engine inputNode] audioUnit];

OSStatus error = AudioUnitSetProperty(audioUnit,
                                      kAudioOutputUnitProperty_CurrentDevice,
                                      kAudioUnitScope_Global,
                                      0,
                                      &inputDeviceID,
                                      sizeof(inputDeviceID));

我从 CAPlayThrough 示例中借用了非 AVFoundation C 代码。

【讨论】:

当我尝试对输出节点执行此操作时,我收到错误 required condition is false: numChannelsAggDevice >= numChannelsSubDevice 您是使用AudioObjectGetPropertyData 获得正确的设备ID,还是只使用53?您的输入设备有多少个通道? 我得到了正确的设备ID,返回状态为0,但是设备没有输出。 对不起,如果我说的很明显,但是您是否将 [engine inputNode] 更改为 [engine outputNode](假设您正在设置输出设备)? Tbh,这太荒谬了,Apple 文档和选择设备的功能有多糟糕......我已经阅读了几天,OMG。【参考方案2】:

这是一个完整的(虽然有些粗糙)功能,它将播放一些音频以进行测试(当然,如果您没有在那里安装 GarageBand,请选择不同的文件)。为避免对设备 ID 进行硬编码,它会切换到您可以在“系统偏好设置”中设置的警报(“音效”)设备。

AVAudioEngine *engine = [[AVAudioEngine alloc] init];
AudioUnit outputUnit = engine.outputNode.audioUnit;

OSStatus err = noErr;
AudioDeviceID outputDeviceID;
UInt32 propertySize;

AudioObjectPropertyAddress propertyAddress = 
    kAudioHardwarePropertyDefaultSystemOutputDevice,
    kAudioObjectPropertyScopeGlobal,
    kAudioObjectPropertyElementMaster ;
propertySize = sizeof(outputDeviceID);
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &outputDeviceID);
if (err)  NSLog(@"AudioHardwareGetProperty: %d", (int)err); return; 

err = AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &outputDeviceID, sizeof(outputDeviceID));
if (err)  NSLog(@"AudioUnitSetProperty: %d", (int)err); return; 

NSURL *url = [NSURL URLWithString:@"/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Versions/A/Resources/Libraries/WaveNoise/Liquid.wav"];
NSError *error = nil;
AVAudioFile *file = [[AVAudioFile alloc] initForReading:url error:&error];
if (file == nil)  NSLog(@"AVAudioFile error: %@", error); return; 

AVAudioPlayerNode *player = [[AVAudioPlayerNode alloc] init];
[engine attachNode:player];
[engine connect:player to:engine.outputNode format:nil];

NSLog(@"engine: %@", engine);

if (![engine startAndReturnError:&error]) 
    NSLog(@"engine failed to start: %@", error);
    return;


[player scheduleFile:file atTime:[AVAudioTime timeWithHostTime:mach_absolute_time()] completionHandler:^
    NSLog(@"complete");
];
[player play];

【讨论】:

这很好,将格式传递给[engine connect] 时出错 - 传递nil 就可以了

以上是关于设置 AVAudioEngine 输入和输出设备的主要内容,如果未能解决你的问题,请参考以下文章

使用 AVAudioEngine 进行电平测量

Swift AVAudioEngine:更改MacOS的音频输入设备

iOS8 AVAudioEngine 如何将麦克风输入路由到(底部)扬声器输出?

AVAudioEngine 离线渲染:仅在连接耳机时静音输出

获取设备音频输出

swift AVAudioEngine 和 AVAudioSinkNode sampleRate 转换