ALSA PCM 時間戳

ALSA API 可以提供兩個不同的系統時間戳

  • Trigger_tstamp 是呼叫 .trigger 回撥時獲取的系統時間快照。 在一般情況下,此快照由 ALSA 核心獲取,但特定硬體可能具有同步功能,或者相反,可能只能延遲提供正確的估計。 在後兩種情況下,底層驅動程式負責在最合適和精確的時刻更新 trigger_tstamp。 應用程式不應僅僅依賴於第一個 trigger_tstamp,如果驅動程式延遲提供更精確的估計,則應更新其內部計算。

  • tstamp 是在上次事件或應用程式查詢期間更新的當前系統時間戳。 差值 (tstamp - trigger_tstamp) 定義了經過的時間。

ALSA API 提供兩個基本資訊:avail 和 delay。將它們與觸發器和當前系統時間戳結合使用,應用程式可以跟蹤環形緩衝區“滿”的程度和排隊的樣本數量。

這些不同指標和時間資訊的使用取決於應用程式的需求

  • avail 報告可以在環形緩衝區中寫入多少資料

  • delay 報告在播放完所有排隊樣本後,聽到新樣本所需的時間。

啟用時間戳後,avail/delay 資訊會與系統時間的快照一起報告。應用程式可以從 CLOCK_REALTIME(包括向後調整的 NTP 校正)、CLOCK_MONOTONIC(進行 NTP 校正但永遠不會向後調整)、CLOCK_MONOTIC_RAW(不進行 NTP 校正)中選擇,並使用 sw_params 動態更改模式

ALSA API 還提供一個 audio_tstamp,它反映了音訊硬體的不同元件測量的時間流逝。 在 ASCII 藝術中,這可以表示為如下(對於播放情況)

--------------------------------------------------------------> time
  ^               ^              ^                ^           ^
  |               |              |                |           |
 analog         link            dma              app       FullBuffer
 time           time           time              time        time
  |               |              |                |           |
  |< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
  |<----------------- delay---------------------->|           |
                                 |<----ring buffer length---->|

模擬時間是在播放的最後階段獲取的,儘可能接近實際換能器

鏈路時間是在 SoC/晶片組的輸出端獲取的,因為樣本被推送到鏈路上。如果硬體支援樣本計數器或牆鍾(例如,具有 HDAudio 24MHz 或用於網路解決方案的 PTP 時鐘),則可以直接測量鏈路時間,或者可以間接估計(例如,使用 USB 中的幀計數器)。

DMA 時間是使用計數器測量的 - 由於 DMA 傳輸的突發性質,通常是所有測量中最不可靠的。

應用時間對應於應用程式在寫入環形緩衝區後跟蹤的時間。

應用程式可以查詢硬體功能,透過選擇 audio_tstamp_config 欄位中的相關設定來定義它希望報告哪個音訊時間,從而估計時間戳的準確性。它還可以請求將延遲到模擬的時間包括在測量中。直接訪問鏈路時間在提供嵌入式 DSP 的平臺上非常有趣; 使用專用硬體直接測量鏈路時間,可能與系統時間同步,從而無需跟蹤內部 DSP 處理時間和延遲。

如果應用程式請求硬體/底層驅動程式不支援的音訊 tstamp,則型別將被覆蓋為 DEFAULT,並且時間戳將報告基於 hw_pointer 值的 DMA 時間。

為了與以前未提供時間戳選擇的實現向後相容,對於零值的 COMPAT 時間戳型別,結果將預設為播放流的 HDAudio 牆鍾,以及所有其他情況下的 DMA 時間 (hw_ptr)。

音訊時間戳的準確性可以返回到使用者空間,以便做出適當的決策

  • 對於 DMA 時間(預設值),傳輸的粒度可以從更新之間的步長推斷出來,進而提供有關應用程式指標可以安全地倒回多少的資訊。

  • 鏈路時間可用於使用 (tstamp-trigger_tstamp)/audio_tstamp 比率跟蹤音訊和系統時間之間的長期漂移,精度有助於定義需要多少平滑/低通濾波。鏈路時間可以在啟動時重置,也可以按原樣報告(後者對於比較不同流的進度很有用 - 但可能需要牆鍾始終執行並且在空閒期間不環繞)。如果硬體支援,絕對鏈路時間也可以用於定義精確的開始時間(正在進行的補丁)

  • 將延遲包括在音訊時間戳中可能與直覺相反,不會提高時間戳的精度,例如,如果編解碼器包括可變延遲 DSP 處理或一系列硬體元件,則延遲通常無法精確得知。

準確度以納秒為單位報告(使用一個無符號 32 位字),這給出了 4.29 秒的最大精度,對於音訊應用程式來說綽綽有餘...

由於時間戳需求的性質各異,即使對於單個應用程式,audio_tstamp_config 也可以動態更改。在 STATUS ioctl 中,引數是隻讀的,不允許任何應用程式選擇。為了解決此限制而不影響舊應用程式,引入了一個新的 STATUS_EXT ioctl,帶有讀/寫引數。 ALSA-lib 將被修改為使用 STATUS_EXT 並有效地棄用 STATUS

ALSA API 一次只允許報告一個音訊時間戳。 這是一個有意識的設計決定,從硬體暫存器或 IPC 讀取音訊時間戳需要時間,讀取的時間戳越多,組合測量就越不精確。 為了避免任何解釋問題,將報告單個(系統,音訊)時間戳。 需要不同時間戳的應用程式將需要發出多個查詢並執行結果的插值

在某些特定於硬體的配置中,系統時間戳由低階音訊子系統鎖存,並將資訊提供回驅動程式。 由於與硬體通訊中可能存在的延遲,存在與 avail 和 delay 資訊錯位的風險。 為了確保應用程式不會感到困惑,snd_pcm_status 結構中添加了一個 driver_timestamp 欄位; 此時間戳顯示驅動程式何時將資訊放在一起,然後再從 STATUSSTATUS_EXT ioctl 返回。 在大多數情況下,此 driver_timestamp 將與常規系統 tstamp 相同。

使用 HDAudio 進行時間戳的示例

1. DMA 時間戳,沒有 DMA+模擬延遲補償

$ ./audio_time  -p --ts_type=1
playback: systime: 341121338 nsec, audio time 342000000 nsec,         systime delta -878662
playback: systime: 426236663 nsec, audio time 427187500 nsec,         systime delta -950837
playback: systime: 597080580 nsec, audio time 598000000 nsec,         systime delta -919420
playback: systime: 682059782 nsec, audio time 683020833 nsec,         systime delta -961051
playback: systime: 852896415 nsec, audio time 853854166 nsec,         systime delta -957751
playback: systime: 937903344 nsec, audio time 938854166 nsec,         systime delta -950822

2. DMA 時間戳,有 DMA+模擬延遲補償

$ ./audio_time  -p --ts_type=1 -d
playback: systime: 341053347 nsec, audio time 341062500 nsec,         systime delta -9153
playback: systime: 426072447 nsec, audio time 426062500 nsec,         systime delta 9947
playback: systime: 596899518 nsec, audio time 596895833 nsec,         systime delta 3685
playback: systime: 681915317 nsec, audio time 681916666 nsec,         systime delta -1349
playback: systime: 852741306 nsec, audio time 852750000 nsec,         systime delta -8694

3. 鏈路時間戳,有 DMA+模擬延遲補償

$ ./audio_time  -p --ts_type=2 -d
playback: systime: 341060004 nsec, audio time 341062791 nsec,         systime delta -2787
playback: systime: 426242074 nsec, audio time 426244875 nsec,         systime delta -2801
playback: systime: 597080992 nsec, audio time 597084583 nsec,         systime delta -3591
playback: systime: 682084512 nsec, audio time 682088291 nsec,         systime delta -3779
playback: systime: 852936229 nsec, audio time 852940916 nsec,         systime delta -4687
playback: systime: 938107562 nsec, audio time 938112708 nsec,         systime delta -5146

示例 1 表明 DMA 級別的時間戳比實際播放時間提前近 1 毫秒(順便說一句,這種測量可以幫助定義倒帶安全措施)。 在示例 2 中補償 DMA-鏈路延遲有助於消除硬體緩衝,但資訊仍然非常不穩定,最多有一個樣本的誤差。 在示例 3 中,時間戳是用鏈路牆鍾測量的,時間戳顯示出單調行為和較低的離散度。

示例 3 和 4 使用 USB 音訊類。 示例 3 顯示由於緩衝,音訊時間和系統時間之間存在高偏移量。 示例 4 顯示了補償延遲如何暴露 1 毫秒的精度(由於驅動程式使用了幀計數器)

示例 3:DMA 時間戳,沒有延遲補償,delta 約為 5 毫秒

$ ./audio_time -p -Dhw:1 -t1
playback: systime: 120174019 nsec, audio time 125000000 nsec,         systime delta -4825981
playback: systime: 245041136 nsec, audio time 250000000 nsec,         systime delta -4958864
playback: systime: 370106088 nsec, audio time 375000000 nsec,         systime delta -4893912
playback: systime: 495040065 nsec, audio time 500000000 nsec,         systime delta -4959935
playback: systime: 620038179 nsec, audio time 625000000 nsec,         systime delta -4961821
playback: systime: 745087741 nsec, audio time 750000000 nsec,         systime delta -4912259
playback: systime: 870037336 nsec, audio time 875000000 nsec,         systime delta -4962664

示例 4:DMA 時間戳,有延遲補償,延遲約為 1 毫秒

$ ./audio_time -p -Dhw:1 -t1 -d
playback: systime: 120190520 nsec, audio time 120000000 nsec,         systime delta 190520
playback: systime: 245036740 nsec, audio time 244000000 nsec,         systime delta 1036740
playback: systime: 370034081 nsec, audio time 369000000 nsec,         systime delta 1034081
playback: systime: 495159907 nsec, audio time 494000000 nsec,         systime delta 1159907
playback: systime: 620098824 nsec, audio time 619000000 nsec,         systime delta 1098824
playback: systime: 745031847 nsec, audio time 744000000 nsec,         systime delta 1031847