RTP包中timestamp的間隔問題

求真得真 發佈 2022-02-23T22:47:43+00:00

概述近期在和同事調試G729的編解碼庫時碰到一個語音質量的問題,問題產生的原因和RTP包中的時間戳設置有關,特此記錄下來。



概述

近期在和同事調試G729的編解碼庫時碰到一個語音質量的問題,問題產生的原因和RTP包中的時間戳設置有關,特此記錄下來。

問題現象,1001和1002帳號註冊在fs,媒體設置為G729並通過fs中轉,1001終端使用eyebean,1002終端使用自己開發的SIP終端,從1001-1002的語音正常,從1002-1001的語音卡頓異常。


環境

centos:CentOS release 7.0 (Final)或以上版本

freeswitch:v1.8.7

GCC:4.8.5


問題分析

freeswitch在正常的語音轉發中沒有發現過類似問題。

從語音質量的現象看,只有單邊的語音卡頓,即從1002-1001方向的語音有問題。

1002的終端屬於自研產品,其中G729模塊也是剛剛接入,發生問題的概率較大。

有了基本的分析之後,還是要找到明確的證據支撐,這時候就需要抓包分析。

使用wireshark對SIP終端側進行抓包,查看抓包的RTP流。如下圖



其中藍色的第1、3行,是出現問題的RTP流。

再打開RTP流分析的頁面。

從1002-fs的RTP流如下圖。可以看到stream0的包分析結果。



從fs-1001的RTP流如下圖。可以看到stream1的包分析結果。

這個頁面我們發現了一個問題,就是RTP流的發包中,Delta(ms)列的數據有一些異常,每隔5個包,就會出現1個40ms間隔的包,非常的規律。



對應到RTP流中,根據timestamp欄位就會發現,每隔6個包,就會有1個包丟掉了。



至此,我們可以得到一個初步的分析結果,就是1002發送的RTP包,經過fs的轉發後,被部分丟棄了,造成1001收到的語音質量問題。


RTP包timestamp欄位

由於1002SIP終端的G729庫是新接入的,所以對於RTP打包格式是首先要懷疑的。

RTP頭格式如下:

 0                   1                   2                   3
 0 12 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |V=2|P|X| CC   |M|     PT     |       sequence number         |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                           timestamp                           |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          synchronization source (SSRC) identifier            |
 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
 |           contributing source (CSRC) identifiers             |
 |                             ....                              |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


對於其他欄位的介紹網上很多,直接略過,這裡主要看一下timestamp欄位。

timestamp,32比特。時間戳,反映了RTP數據包中第一個八位字節的採樣時間。時間戳的初始值應當是隨機的,類似序號。時鐘頻率依賴於負載數據格式,因此時間戳增量依賴於當前數據格式和策略。如果RTP數據包周期性產生,那麼將使用採樣時鐘確定的標稱採樣時刻,而非讀取系統時間。舉例而言,對於固定採樣率的音頻,時間戳時鐘可能會在每個採樣周期增加1;如果音頻應用程式從輸入設備讀取覆蓋160個採樣周期的塊,則對於每個這樣的塊,時間戳將增加160,無論該塊是在分組中傳輸還是作為靜默丟棄。

上面這一段是官方的介紹,說實話我也看的稀里糊塗的,但是其中的關鍵是「時間戳將增加160」這一句,和我的認知有了衝突。

當我們看到timestamp欄位的名字時,首先想到的是時間戳,既然是時間,按照正常的理解,應該是和打包時長ptime相對應,比如打包時長ptime是20ms,那麼timestamp的間隔也應該是20。

但是事實上,RTP包中的timestamp欄位並不是這樣定義的。

在官方的RFC1889文檔中,If an audio application reads blocks covering 160 sampling periods from the input device, the timestamp would be increased by 160 for each such block, regardless of whether the block is transmitted in a packet or dropped as silent.

下面翻譯成我自己的理解。

timestamp欄位和通常的時間沒有關係。

timestamp欄位是為了表示媒體流的採樣長度和順序。

timestamp欄位的初始值是隨機數。

timestamp欄位的間隔的計算方法,根據媒體流協商的媒體類型來決定,具體由倆個指標,採樣率和打包時長。

計算公式是(timestamp間隔=採樣率*打包時長)。

舉個栗子,媒體類型的協商結果是G729,其中採樣率是8000,打包時長是20ms,那麼timestamp的間隔 = 8000 * 0.02 = 160。

再舉個栗子,媒體協商結果是iLBC,其中採樣率是8000,打包時長是30ms,那麼timestamp的間隔 = 8000 * 0.03 = 240。

再舉最後一個栗子,媒體協商結果是opus,其中採樣率是16000,打包時長是20ms,那麼timestamp的間隔 = 16000 * 0.02 = 320。


總結

RTP流在VOIP和RTC通信中非常常見。

我們從一個問題出發,在分析解決的過程中,重新認識了RTP包格式,尤其是其中timestamp欄位的定義,和平常的時間戳定義有區別。

碰到網絡問題,wireshark抓包是非常好用的工具,可以解決90%的問題。


空空如常

求真得真

關鍵字: