低延遲音訊

低延遲音訊可提高遊戲的真實感,為玩家提供即時回應。

請完成以下檢查清單所列步驟,為 Android 遊戲啟用低延遲音訊:

  1. 使用 Oboe
  2. 要求「低延遲」效能模式
  3. 要求「專屬」共用模式
  4. 使用 48000 Hz 或 Oboe 取樣率轉換器
  5. 設定用途為 AAUDIO_USAGE_GAME
  6. 使用資料回呼
  7. 避免封鎖回呼作業
  8. 將緩衝區空間調整為「雙緩衝區」

1. 使用 Oboe API

Oboe API 是 C++ 包裝函式,可在 Android 8.1 (API 級別 27) 以上版本中呼叫 AAudio。在較舊的 Android 版本中,Oboe 會使用 OpenSL ES。

您可以在 GitHub 或以預先建構的二進位檔形式取得 Oboe。Oboe 也提供 QuirksManager,用來修正特定裝置上的問題,讓應用程式與更多裝置相容。如果無法使用 Oboe,請直接使用 AAudio。

2. 要求低延遲模式

您可以使用 Oboe 或 AAudio 要求低延遲模式。否則在預設情況下,您會取得延遲時間較長的模式。

Oboe

builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);

AAudio

AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

3. 要求專屬模式

您也可以要求 MMAP 緩衝區的專屬存取權。應用程式或許無法取得專屬存取權,但如果取得這項權限,就能直接寫入由 DSP 讀取的緩衝區,盡量縮短延遲時間。

Oboe

builder.setSharingMode(oboe::SharingMode::Exclusive);

AAudio

AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

4. 避免轉換取樣率

使用裝置的自然取樣率,方法是不指定取樣率,這樣很可能會取得 48000 Hz 的取樣率。如果指定取樣率,音訊架構會透過不同路徑傳送您的資料,而該路徑的延遲時間可能長得多。

如果需要採用不同的取樣率,請使用 Oboe 轉換取樣率:

builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);

5. 正確宣告用途

指定應用程式播放音訊的原因非常重要,系統會據以套用正確的路徑、音量和效能設定。舉例來說,遊戲應指出用途為 AAUDIO_USAGE_GAME,充分利用延遲最佳化的優勢,特別是在連線至藍牙耳機時。

Oboe

builder.setUsage(oboe::Usage::Game);

AAudio

AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);

6. 使用回呼函式

為輸出串流使用回呼。如果您使用阻斷寫入功能,但裝置不支援 AAudio MMAP 模式,則延遲時間可能會更長。

Oboe

builder.setDataCallback(&myCallbackObject);

AAudio

AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);

7. 避免封鎖回呼

使用低延遲串流時,回呼之間的間隔時間可能非常短,只有幾毫秒。因此,切勿在回呼中執行可能導致長時間封鎖的作業。如果回呼遭到封鎖,緩衝區會發生反向溢位,音訊也會出現異常情形。

請避免在回呼中執行下列作業:

  • 分配或釋出記憶體
  • 檔案或網路 I/O
  • 等待互斥鎖或鎖定
  • 休眠
  • 大量的一次性 CPU 計算

回呼應以均勻速度執行運算,才能流暢播放音訊,不會出現異常情形。

8. 調整緩衝區空間

應用程式開啟音訊串流後,您需要調整可用的緩衝區空間,最佳化延遲時間。Oboe 會自動將緩衝區空間設為兩個爆發,但如果使用 AAudio,預設值會高出許多。如要使用雙緩衝區,可以將緩衝區空間設為爆發大小的兩倍。爆發大小就是回呼大小上限。

AAudio:

int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);

如果緩衝區空間太小,則可能因緩衝區不足而出現異常情形。您可以呼叫 AAudioStream_getXRunCount(stream),取得異常次數。請視需要增加緩衝區空間。

詳情請參閱 GitHub Oboe 文件 ,瞭解緩衝區相關術語的說明。

OpenSL ES

如要支援 Android 8.1 以下版本,必須使用 OpenSL ES。如果要使用 Oboe,可以設定應用程式來縮短延遲時間。詳情請見 取得最佳延遲時間

檢查清單結果

下表為 OboeTester 對來回 (從輸入到輸出) 延遲時間的測量結果。

設定 延遲時間 (毫秒)
依循所有建議 20
未採用低延遲效能模式 205
非專屬 (共用) 26
44100 Hz (AAudio) 160
44100 Hz (Oboe SRC) 23
未使用輸出回呼 (MMAP) 21
未使用輸出回呼 (非 MMAP) 62
緩衝區空間設為最大 53