连接节点上的 AVAudioEngine 崩溃

Posted

技术标签:

【中文标题】连接节点上的 AVAudioEngine 崩溃【英文标题】:AVAudioEngine crash on connect node 【发布时间】:2018-10-15 21:30:01 【问题描述】:

我已经用自己的方法设置了我的 AVAudioEngine,如下所示:

AVAudiosession* session = [AVAudioSession sharedInstance];
[session setPreferredSampleRate:[session sampleRate] error:nil];
[session setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
[session setActive:YES error:nil];

audioEngine_ = [[AVAudioEngine alloc] init];

//tap the outputNode to create the singleton
[audioEngine_ outputNode];
NSError* error;
[audioEngine_ startAndReturnError:&error];

启动它没有错误。我有另一种方法可以从我从应用程序间音频乐器收到的 AudioComponentDescription 附加 AVAudioUnitMIDIInstrument。我的连接方法如下所示:

-(void)connectInstrument:(AudioComponentDescription)desc   
    instNode_ = nil;
    instNode_ = [[AVAudioUnitMIDIInstrument alloc] initWithAudioComponentDescription:desc];

    [audioEngine_ attachNode:instNode_];

    //Crashes here
    [audioEngine_ connect:instNode_ to:[audioEngine_ outputNode] format:nil];

    [audioEngine_ startAndReturnError:nil];

    NSLog(@"done connecting");

崩溃没有给我任何有用的信息。我明白了:

提供给 CFRunLoopRunSpecific 的无效模式“kCFRunLoopCommonModes” - 中断 _CFRunLoopError_RunCalledWithInvalidMode 以进行调试。此消息每次执行只会出现一次。

* 由于未捕获的异常“NSRangeException”而终止应用程序,原因:“* -[__NSArrayM objectAtIndexedSubscript:]: index 0 beyond bounds for empty array”

如果我进行测试并尝试创建一个新的混合器节点并附加/连接它,则不会发生崩溃。

我有更多相关信息 如果我这样做:

AVAudioFormat* instFormat = [instUnit_ outputFormatForBus:0];

我得到同样的错误: -[__NSArrayM objectAtIndexedSubscript:]:空数组的索引 0 超出范围 几乎就好像没有为任何输出总线设置 AVAudioFormat ,也没有任何输入总线(我也检查了 inputFormatForBus )。这很奇怪,因为如果我这样做:

AudioStreamBasicDescription f1;
UInt32 outsize = sizeof(f1);
AudioUnitGetProperty(instNode_.audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &f1, &outsize);

那么 f1 是一个有效的 AudioStreamBasicDescription,显示标准的 44.1khz 采样率、32 位浮点数、2 个通道。所以有一种输出流格式,但它似乎没有附加到 AVAudioUnitMIDIInstrument 实例的任何输出总线上。

编辑 - 更多信息 即使我只是尝试访问 instUnite_.name,我也会得到 NSRangeException。我现在想知道这是否与我获取组件描述的方式有关。我正在尝试使用跨应用音频(我已经完成了所有正确的权利、功能和应用 ID 设置)。这就是我发现应用间音频组件的方式:

NSMutableArray* units = [[NSMutableArray alloc] init];
AudioComponentDescription searchDesc =  kAudioUnitType_RemoteInstrument, 0, 0, 0, 0 ;

NSArray* componentArray = [[AVAudioUnitComponentManager sharedAudioUnitComponentManager] componentsMatchingDescription:searchDesc];

for(AVAudioUnitComponent* component in componentArray) 
    AudioComponentDescription description = component.audioComponentDescription;

    InterAppAudioUnit* unit = [[InterAppAudioUnit alloc] init];
    unit.componentDescription = description;
    unit.icon = AudioComponentGetIcon(component.audioComponent, 44.0f);
    unit.name = component.name;
    unit.avComponent = component;

    [units addObject:unit];


_units = units;
[self.tableView reloadData];

这一切都在呈现的 UITableViewController 中。单击一个后,我只需执行:

[self connectInstrument:unit.componentDescription];

如果我改为为本地单元手动构建组件描述,则 AVAudioUnit 会很好地实例化,不会崩溃。

【问题讨论】:

它不是零。我查过了。 什么是instUnit 对不起,应该更清楚了,它是一个 AVAudioUnitMIDIInstrument* 类型的成员变量 【参考方案1】:

我找到了答案。 AVAudioUnit 对象内部的 AUAudioUnit 对象在创建时没有输出总线。我不确定为什么。您可以通过以下方式修复它:

AUAudioUnit* auInst = instUnit_.AUAudioUnit;
NSMutableArray<AUAudioUnitBus*>* busArray = [[NSMutableArray alloc] init];
AVAudioFormat* outFormat = [[self->audioEngine_ outputNode] outputFormatForBus:0];
AUAudioUnitBus* bus = [[AUAudioUnitBus alloc] initWithFormat:outFormat error:&err];
[busArrays addObject:bus];
[[auInst outputBusses] replaceBusses:busArray];

【讨论】:

以上是关于连接节点上的 AVAudioEngine 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

通话过程中拔下耳机时 AVAudioEngine 崩溃

AVAudioEngine inputNode installTap 重启录音时崩溃

AVAudioEngine.start() 中的崩溃,即使它包含在 do/catch 中

如何阻止一个节点上的死锁使整个集群崩溃?

AVAudioEngine 调度样本准确的参数变化

在 Windows 中,停止 postgres 服务会导致节点崩溃并显示“错误:由于管理员命令而终止连接”