簡體   English   中英

iOS音頻系統。 開始和停止還是只是開始?

[英]iOS audio system. Start & stop or just start?

我有一個應用程序,其中錄音是主要和最重要的部分。 但是,用戶可以切換到顯示所有記錄且不執行任何記錄的表視圖控制器。

問題是哪種方法更好:“啟動或停止音頻系統或直接啟動”。 第一個似乎更正確,例如“在需要時分配,在使用時分配”。 我將展示我對這個問題的想法,並希望得到熟練技術人員的支持或反對。

當我第一次構造AudioController.m時,我實現了打開/關閉音頻會話以及啟動/停止音頻單元的方法。 我想在錄音未激活時停止音頻系統。 我使用以下代碼:

- (BOOL)startAudioSystem {

    // open audio session
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *err = nil;
    if (![audioSession setActive:YES error:&err] ) {
        NSLog(@"Couldn't activate audio session: %@", err);
    }
    // start audio unit
    OSStatus status;
    status = AudioOutputUnitStart([self audioUnit]);
    BOOL noErrors = err == nil && status == noErr;    
    return noErrors;
}

- (BOOL)stopAudioSystem {
    // stop audio unit
    BOOL result;
    result = AudioOutputUnitStop([self audioUnit]) == noErr;
    HANDLE_RESULT(result);
    // close audio session
    NSError *err;
    HANDLE_RESULT([[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&err]);
    HANDLE_ERROR(err);
    BOOL noErrors = err == nil && result;
    return noErrors;
}

我發現此方法存在問題,原因如下:

  1. 音頻系統延遲啟動。 這意味着recording_callback()已有一段時間沒有被調用。 我懷疑是AudioOutputUnitStart對此負責。 我試圖用此函數調用注釋掉該行,然后將其移至初始化。 延遲消失了。
  2. 如果用戶非常快地在記錄視圖和表視圖之間進行切換(音頻系統的啟動和停止也非常快),則會導致媒體服務中斷(我知道觀察AVAudioSessionMediaServicesWereResetNotification可能會有所幫助,但這不是重點)。

為了解決這些問題,我用設法發現的其他方法修改了AudioController.m: 在應用程序處於活動狀態時啟動音頻系統,並且在應用程序終止前不停止音頻系統。在這種情況下,還存在以下問題:

  1. CPU使用率
  2. 如果將音頻類別設置為僅錄制,則當用戶瀏覽表視圖控制器時無法播放其他音頻。

令人驚訝的是第一個並沒有什么大不了的,如果取消了recording_callback()中的任何處理,如下所示:

    static OSStatus recordingCallback(void *inRefCon,
                                  AudioUnitRenderActionFlags *ioActionFlags,
                                  const AudioTimeStamp *inTimeStamp,
                                  UInt32 inBusNumber,
                                  UInt32 inNumberFrames,
                                  AudioBufferList *ioData) {

    AudioController *input = (__bridge AudioController*)inRefCon;

    if(!input->shouldPerformProcessing)
        return noErr;

    // processing
    // ...
    //

    return noErr;
}

通過這樣做,在不需要記錄且不執行其他任何操作的情況下,實際設備上的CPU使用率等於0%。

第二個問題可以通過將音頻類別切換到RecordAndPlay並啟用混音來解決,或者只是忽略該問題即可解決。 例如,在我的案例中,應用程序要求外接設備使用迷你插孔,因此不能並行使用任何耳機。

盡管如此,第一種方法更接近我,因為我喜歡在不再需要時關閉/清理每個流/資源。 而且我想確保確實除了啟動音頻系統之外別無選擇。 請確保我不是唯一提出此解決方案的人,而且它是正確的。

解決此問題的關鍵是注意音頻系統實際上在另一個(實時)線程中運行。 而且,當您(或應用程序的主UI線程)“不需要”時,您不能真正真正地停止並重新分配在其他線程中運行的某些東西,但必須延遲才能讓另一個線程意識到它需要做然后完成並清理自身。 這可能會花費多達100毫秒的音頻時間。

鑒於此,策略2(剛剛開始)更安全,更現實。

或者,在嘗試停止音頻之前將不使用的延遲時間設置為許多秒,然后在嘗試重新啟動之前將其設置為另一短延遲時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM