2012-04-13 316 views
2

我有一个播放单声道音频事件(各种频率的短蜂鸣声)的代码。 我创建一个AudioOutputUnit,停下来,每当我需要播放音频时。我开始吧。当我在规定的时间内播放时,我会停止播放。AudioOutputUnitStart非常慢

听起来很简单。

但是,AudioOutputUnitStart通常需要180ms才能在我的iPhone 4S(iOS 5.1)上返回,这太过分了。

这里是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属性t Ø一个很小的值(如5毫秒) 降低帧率(试过48kHz的,44.1kHz的,为8kHz)

不管我做什么... 的audiounit启动第一次,AudioOutputUnitStart只有160-180ms后返回。如果我立即停下来并开始它,那么它只需要5米左右,这更加可以接受。

在我的应用程序中的延迟是相当重要的,180毫秒是绝对不能接受的。

有什么建议吗? 我见过一些人提出类似的问题,但他们通常从来没有得到答案。

我希望这一次情况会有所不同:)

+0

您可能已经想到了这一点 - 但是在这里添加/删除renderCallback工作吗?也看到了这一点(虽然你的缓冲区很小):http://stackoverflow.com/questions/5690460/objective-c-audiooutputunitstart-takes-a-long-time-to-start-possible-workaroun – 2012-04-13 13:43:30

+0

我其实没有想到消除回调;在回调中,声波实际上是生成的,所以音频缓冲区可以很小。将尝试 – jyavenard 2012-04-13 16:35:02

回答

2

处理音频机组启动延迟的方式是提前所需的时间启动音频单元,而不是阻止它。相反,只需配置短暂缓冲区的音频会话,然后用静音填充音频单元呈现回调缓冲区,直到需要填充所需声音为止。然后,在你的声音之后,回到缓冲区而不是停下来。

+0

我担心的问题是,您知道第二个线程始终运行,并且使用我的短音频缓冲区(以减少延迟),这肯定会影响性能。 – jyavenard 2012-04-15 01:39:16

+1

@jyavenard:IIRC,连续运行的RemoteIO音频单元具有非常短的缓冲区,在iPhone 4上使用的CPU周期不到1%。任何性能影响都可能完全不明显。 – hotpaw2 2012-04-15 04:17:31