音频输出单元启动非常缓慢

3

我有一段播放单声道音频事件的代码(在不同频率下短促哔哔声)。

我创建了一个AudioOutputUnit,首先它会停止,每当需要播放音频时,我就启动它。当我已经播放完所需时长后,我会停止它。

听起来很简单。

但是,在我的iPhone 4S(iOS 5.1)上,调用AudioOutputUnitStart通常需要180毫秒的时间,这太长了。

以下是创建/初始化AudioOutputUnit的代码:

void createAOU()
{
    m_init = false;
    // find the default playback output unit
    AudioComponentDescription defaultOutputDescription;
    defaultOutputDescription.componentType = kAudioUnitType_Output;
    defaultOutputDescription.componentSubType = kAudioUnitSubType_RemoteIO;
    defaultOutputDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
    defaultOutputDescription.componentFlags = 0;
    defaultOutputDescription.componentFlagsMask = 0;

    // Get the default playback output unit
    AudioComponent defaultOutput = AudioComponentFindNext(NULL, &defaultOutputDescription);
    if (defaultOutput == NULL)
        return;

    OSErr err = AudioComponentInstanceNew(defaultOutput, &m_toneUnit);
    if (err != noErr)
        return;

    // single channel, floating point, linear PCM
    AudioStreamBasicDescription streamFormat;
    streamFormat.mSampleRate = m_framerate;
    streamFormat.mFormatID = kAudioFormatLinearPCM;
    streamFormat.mFormatFlags =
    kLinearPCMFormatFlagIsFloat |
    kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
    streamFormat.mBytesPerPacket = sizeof(float);
    streamFormat.mFramesPerPacket = 1;
    streamFormat.mBytesPerFrame = sizeof(float);
    streamFormat.mChannelsPerFrame = 1;
    streamFormat.mBitsPerChannel = sizeof(float) * 8;
    err = AudioUnitSetProperty (m_toneUnit,
                                kAudioUnitProperty_StreamFormat,
                                kAudioUnitScope_Input,
                                0,
                                &streamFormat,
                                sizeof(AudioStreamBasicDescription));
    if (err != noErr)
        return;

    // Attach callback to default output
    AURenderCallbackStruct input;
    input.inputProc = RenderTone;
    input.inputProcRefCon = this;
    err = AudioUnitSetProperty(m_toneUnit, 
                               kAudioUnitProperty_SetRenderCallback, 
                               kAudioUnitScope_Input,
                               0, 
                               &input, 
                               sizeof(input));
    if (err != noErr)
        return;

    float aBufferLength = 0.001; // In seconds
    AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, 
                            sizeof(aBufferLength), &aBufferLength);

    err = AudioUnitInitialize(m_toneUnit);
    if (err != noErr)
        return;
    reset();
    m_init = true;
}

要启动它,只需调用:

OSErr err = AudioOutputUnitStart(m_toneUnit);

完成后:

OSErr err = AudioOutputUnitStop(m_toneUnit);

我尝试了各种方法: 将kAudioSessionProperty_PreferredHardwareIOBufferDuration属性设置为非常小的值(如5ms) 降低帧率(尝试过48kHz、44.1kHz、8kHz)
无论我做什么... 第一次启动音频单元,AudioOutputUnitStart只有在160-180毫秒后才返回。如果我立即停止并重新启动它,则只需要大约5毫秒,这更加可接受。
我的应用程序中延迟相当重要,而180毫秒绝对不可接受。
有什么建议吗? 我看到有些人问类似的问题,但他们通常没有得到答案。
我希望这次会有所不同 :)

你可能已经想到了这一点 - 但是添加/删除renderCallback在这里是否有效?还看到了这个(尽管你的缓冲区很小):http://stackoverflow.com/questions/5690460/objective-c-audiooutputunitstart-takes-a-long-time-to-start-possible-workaroun - spring
我其实没有考虑过移除回调函数;在回调函数中,声波实际上是由生成的,因此音频缓冲区可以很小。我会尝试。 - jyavenard
1个回答

3
处理音频单元启动延迟的方法是提前启动音频单元,而不是停止它。相反,只需为短缓冲区配置音频会话,然后用静音填充音频单元渲染回调缓冲区,直到该填充所需声音的时间。然后在播放声音之后,继续使用静音填充缓冲区,而不是停止它们。

我关心的问题是,现在你有第二个线程始终在运行,而我的音频缓冲区很短(为了减少延迟),这肯定会对性能产生相当大的影响。 - jyavenard
1
@jyavenard:如果我没记错的话,一个连续运行、使用非常短缓冲区的RemoteIO音频单元,在iPhone 4上使用的CPU周期不到1%。任何性能影响都很可能完全无法察觉。 - hotpaw2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接