1

私は、オーディオ録音がメインで最も重要な部分であるアプリを持っています。ただし、ユーザーは、すべてのレコードが表示され、記録が実行されないテーブル ビュー コントローラーに切り替えることができます。

問題は、どのアプローチが優れているかです。「オーディオシステムを開始して停止するか、単に開始するか」です。「必要なときに割り当て、使用時に割り当てを解除する」のように、最初の方がより正しいと思われるかもしれません。この質問に対する私の考えを示します。熟練した人々の間での議論で賛否両論を見つけたいと思います。

初めて 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% になります。

2 つ目の問題は、オーディオ カテゴリを RecordAndPlay に切り替えてミキシングを有効にするか、単に問題を無視することで解決できます。たとえば、私の場合、アプリでは外部デバイスでミニジャックを使用する必要があるため、ヘッドフォンを並行して使用することはできません。

これらすべてにもかかわらず、最初のアプローチは、不要になったときにすべてのストリーム/リソースを閉じる/クリーンアップするのが好きなので、私にはより近いです。そして、オーディオシステムを起動する以外に選択肢がないことを確認したいと思います。この解決策にたどり着いたのは私だけではなく、正しい解決策であることを確認してください。

4

1 に答える 1

1

この問題を解決する鍵は、オーディオ システムが実際には別の (リアルタイム) スレッドで実行されていることに注意することです。そして、あなた (またはアプリのメイン UI スレッド) が「必要ない」ときに、別のスレッドで実行されているものを実際に停止して割り当てを解除することはできませんが、他のスレッドが実行する必要があることを認識できるようにするために遅延する必要があります。何かを終了し、それ自体をクリーンアップします。これには、オーディオの場合、数百ミリ秒かかる可能性があります。

それを考えると、戦略 2 (開始するだけ) の方が安全で現実的です。

または、オーディオを停止しようとする前に何秒もの不使用の遅延を設定し、その後再起動を試みる前に別の短い遅延を設定することもできます。

于 2015-11-29T07:58:22.070 に答える