You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS VoIP应用中接近传感器触发导致Audio Unit回调inNumberFrames异常求助

解决Linphone SDK iOS应用中接近传感器导致Audio Unit帧大小变化的问题

我之前也碰到过类似的Audio Unit和接近传感器交互的坑,结合你描述的情况,给你几个具体的排查和解决方向:

1. 监听路由变化,重新锁定帧大小参数

接近传感器触发时,系统会自动切换音频路由(扬声器→听筒),哪怕你没手动切换设备,系统也可能隐性重置Audio Unit的参数。你可以在路由变化时重新强制设置帧相关属性:

首先注册路由变化通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleAudioRouteChange:)
                                             name:AVAudioSessionRouteChangeNotification
                                           object:[AVAudioSession sharedInstance]];

然后在回调里重新设置参数:

- (void)handleAudioRouteChange:(NSNotification *)notification {
    AVAudioSession *session = [AVAudioSession sharedInstance];
    NSError *error;
    
    // 重新设置偏好的buffer时长(对应256帧,按44.1kHz采样率计算)
    NSTimeInterval targetDuration = 256.0 / 44100.0;
    [session setPreferredIOBufferDuration:targetDuration error:&error];
    
    // 重新设置Audio Unit的最大帧切片和固定帧切片
    UInt32 framesPerSlice = 256;
    AudioUnitSetProperty(card->io_unit, 
                         kAudioUnitProperty_MaximumFramesPerSlice, 
                         kAudioUnitScope_Global, 
                         0, 
                         &framesPerSlice, 
                         sizeof(framesPerSlice));
    
    // 尝试设置固定帧切片(部分Audio Unit支持)
    AudioUnitSetProperty(card->io_unit, 
                         kAudioUnitProperty_FramesPerSlice, 
                         kAudioUnitScope_Global, 
                         0, 
                         &framesPerSlice, 
                         sizeof(framesPerSlice));
}

2. 在渲染回调内部适配帧大小变化

如果系统还是强制改变inNumberFrames,可以在回调里把大帧拆分成Linphone需要的256帧块处理,避免破坏缓冲策略:

static OSStatus au_write_cb ( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData ) {
    LinphoneAudioCard *card = (LinphoneAudioCard *)inRefCon;
    const UInt32 targetFrames = 256;
    UInt32 remainingFrames = inNumberFrames;
    int16_t *sourceBuffer = (int16_t *)ioData->mBuffers[0].mData;
    
    while (remainingFrames > 0) {
        UInt32 processFrames = MIN(remainingFrames, targetFrames);
        // 截取对应帧的数据,喂给Linphone的音频输入逻辑
        linphone_audio_card_write(card, sourceBuffer, processFrames);
        
        sourceBuffer += processFrames;
        remainingFrames -= processFrames;
    }
    
    return noErr;
}

3. 检查Linphone SDK的音频配置

Linphone本身有自己的音频缓冲管理,你可以尝试强制设置SDK的音频缓冲大小:

// 设置Linphone的音频缓冲大小(单位毫秒,对应256帧≈5.8ms)
linphone_core_set_audio_buffer_size(lc, 6);

另外可以查看Linphone的LinphoneAudioConfiguration相关API,有没有强制固定输入帧大小的选项。

4. 对比Speakerbox的细节差异

苹果Speakerbox Demo能保持帧大小稳定,大概率是它在路由变化时做了参数重置,或者Audio Session的配置更严谨:

  • 确认你的Audio Session Category设置正确:VoIP应用必须用AVAudioSessionCategoryPlayAndRecord,并且要添加AVAudioSessionCategoryOptionAllowBluetooth和AVAudioSessionCategoryOptionDefaultToSpeaker选项;
  • 检查Speakerbox的setupAudioSession方法,它是否在初始化时就严格锁定了buffer时长,并且在路由变化时重新确认参数;
  • 注意Speakerbox是否禁用了音频会话的自动配置,比如没有设置AVAudioSessionCategoryOptionMixWithOthers这类可能导致参数波动的选项。

内容的提问来源于stack exchange,提问作者steven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:52:17