2012-04-13 313 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