2016/04/25

如何使用 sipp 播放自訂的 RTP 語音

sipp 是 linux 上用來產生 SIP traffic 的測試工具,它可以使用 xml 描述一通電話的所有 SIP 封包的內容,並利用 pcap 播放工具,將 pcap 裡面的
RTP 語音直接送到受話端。sipp 安裝後,預設只會有一個 g711a.pcap 也就是 alaw 的 RTP 語音檔,如果要測試其他 codec 的語音檔,就要自己錄製。

tcpdump

首先我們準備好一個 SIP Client 當作發話端,在 SIP server 上先建立一個 conference room,當然 SIP Client 必須要設定只使用我們要錄製的 ilbc codec。

執行 tcpdump 將封包錄製下來。

tcpdump -i eth0 -w audio.pcap

接下來就用 SIP Client 撥打電話到 conference room 裡面,然後就講幾句話之後掛斷電話。

wireshark 處理 audio.pcap

用 wireshark 將 audio.pcap 打開之後,可以看到這一段時間錄製的所有封包,這時候,我們用 filter 將 RTP 封包擷取出來。

在 filter 的地方填寫以下的字串,就可以取出 RTP 的語音封包,192.168.1.11 是發話端的 IP,192.168.1.5 是受話端的 IP。

((ip.src == 192.168.1.11) and (ip.dst == 192.168.1.5)) and rtp

在 File -> Export Specific Packet 的選單中,選擇將 Displayed All Packets 另存到另一個 ilbc.pcap 檔案中。

sipp scenario

準備 sipp call scenario 檔案,內容就是撥打電話進去,接通後,播放 ilbc.pcap 檔案。

SIPP scenario: test.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<scenario name="test">

<send>
    <![CDATA[
      INVITE sip:[field2]@[remote_ip] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch];rport
      Max-Forwards: 70
      To: "[field2]" <sip:[field2]@[remote_ip]>
      From: "[field0]" <sip:[field0]@[remote_ip]>;tag=[call_number]
      Call-ID: [call_id]
      CSeq: [cseq] INVITE
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Content-Type: application/sdp
      Content-Length: [len]

      v=0
      o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]:[local_port]
      s=-
      c=IN IP[media_ip_type] [media_ip]
      t=0 0
      m=audio [auto_media_port] RTP/AVP 97 101
      a=rtpmap:97 ILBC/8000
      a=rtpmap:97 mode=20
      a=rtpmap:101 telephone-event/8000
      a=fmtp:101 0-11,16
    ]]>
</send>
<recv response="401" auth="true" />

<send>
    <![CDATA[
      INVITE sip:[field2]@[remote_ip] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch];rport
      Max-Forwards: 70
      To: "[field2]" <sip:[field2]@[remote_ip]>
      From: "[field0]" <sip:[field0]@[remote_ip]>;tag=[call_number]
      Call-ID: [call_id]
      CSeq: [cseq] INVITE
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Content-Type: application/sdp
      [field1]
      Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO,MESSAGE
      Supported: replaces,norefersub,100rel
      Content-Length: [len]

      v=0
      o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]:[local_port]
      s=-
      c=IN IP[media_ip_type] [media_ip]
      t=0 0
      m=audio [auto_media_port] RTP/AVP 97 101
      a=rtpmap:97 ILBC/8000
      a=rtpmap:97 mode=20
      a=rtpmap:101 telephone-event/8000
      a=fmtp:101 0-11,16
    ]]>
</send>
<recv response="100" optional="true" />
<recv response="180" optional="true" />
<recv response="200" />

<send>
    <![CDATA[
      
      ACK sip:[field2]@[remote_ip] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip];rport;branch=[branch]
      From: "[field0]" <sip:[field0]@[remote_ip]>;tag=[call_number]
      To: "[field2]" <sip:[field2]@[remote_ip]>[peer_tag_param]
      Call-ID: [call_id]
      CSeq: [cseq] ACK
      Content-Length: 0
       
    ]]>
</send>

<pause milliseconds="2000"/>

<nop>
    <action>
        <exec play_pcap_audio="pcap/dtmf_2833_star.pcap" />  
    </action>
</nop>
 <nop>
    <action>
       <exec play_pcap_audio="pcap/ilbc.pcap"/>
    </action>
 </nop>
 
<pause milliseconds="1000"/>

<send retrans="500">
    <![CDATA[
      
      BYE sip:[field2]@[remote_ip] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
      Max-Forwards: 70
      From: "[field0]" <sip:[field0]@[remote_ip]>;tag=[call_number]
      To: "[field2]" <sip:[field2]@[remote_ip]>[peer_tag_param]
      Call-ID: [call_id]
      Cseq: 3 BYE
      Subject: Performance Test
      Content-Length: 0
      
    ]]>
</send>

<recv response="200" crlf="true" />

<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>

<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>

</scenario>

準備另一個搭配 test.xml call scenario 的 sip 帳號及密碼的 csv 檔案: test.csv

SEQUENTIAL
2106;[authentication username=2106 password=test];2105

執行 sipp

因為通話是設定讓 sipp 以門號 2106 撥打到 2105,所以我們利用 SIP Client 註冊到 2105 之後,執行以下的 sipp 指令,就可以在 2105 接聽到 sipp 撥打過來的電話,然後聽到剛剛錄製的 ilbc 語音。

sipp -sf test.xml -inf test.csv -r 1 -rp 1 -i 192.168.1.11 -m 1 192.168.1.5

2016/04/18

Apache Spark 應用情境

以往的 Big Data 大都是跟 Hadoop 劃上等號,以 Scala 實作的 Spark 以數十倍甚至百倍於 Hadoop 的處理速度聞名,原因在於 Spark 是基於記憶體而 Hadoop 是硬碟,因為這個基本條件的差別,以下整理一些來自於網路的資料,瞭解 Spark 的應用情境。

Spark 的定位

目前 Big Data 處理有以下幾個類型

  1. Batch Data Processing 複雜的批量處理 偏重於處理海量數據的能力,可忍受處理的時間在數十分鐘到數小時。可以用Hadoop的MapReduce來進行批量海量數據處理。

  2. Interactive Query 基於歷史數據的交互式查詢 可忍受處理的時間在數十秒到數十分鐘之間。可以Impala進行交互式查詢。

  3. Streaming Data Processing 即時資料流處理 可忍受處理的時間在數百毫秒到數秒之間。可以用Storm分佈式處理框架處理即時資料流。

而 Spark 定位在可以同時滿足以上應用的情境。

1,Spark是基於內部記憶體的迭代計算框架,適用於需要多次操作特定數據集的應用場合。需要反覆操作的次數越多,所需讀取的數據量越大,受益越大,數據量小但是計算密集度較大的場合,受益就相對較小。

2,由於RDD的特性,Spark不適合用在那種異步細維度更新狀態的應用,例如 web 服務的存儲或者是持續增加的web page index。就是對於那種增量修改的應用模型不適合。

3,數據量不是特別大,但是要求即時統計分析需求。

Hadoop, Spark, Storm

  • Hadoop常用於離線的、大量的複雜數據處理,採用MapReduce分佈式計算框架,並根據GFS開發了HDFS分佈式文件系統,使用HBase數據儲存系統。資料儲存在硬碟中,每次運算之後的結果需要儲存在HDFS裡面,下次再用的話,還需要再讀出來進行一次計算,磁盤IO開銷比較大。

  • Spark常用於離線的、快速的大數據處理,Spark使用記憶體來儲數存據,因此Spark可以提供超過Hadoop100倍的運算速度。但是,由於記憶體斷電後會遺失資料,Spark不適合處理需要長期保存的資料。

  • Storm 常用於 Real Time 的大數據處理,Storm在Hadoop的基礎上提供了實時運算的特性,可以實時的處理大數據流。不同於Hadoop和Spark,Storm不進行數據的收集和存儲工作,它直接通過網絡即時的接受並處理資料,然後直接通過網絡即時傳回結果。

誰可以使用 Spark?

  • Data Scientist 以往會使用 Python, Matlab, or R,目的是分析資料,並找出這些資料中隱藏的資訊。 Spark Shell 可使用 Python 或 Scala 進行互動式資料分析。Spark SQL 有獨立的 SQL Shell 可利用 SQL 進行資料處理。MLLib 函式庫是用來支援 Machine Learning 與 Data Analysis。也可以呼叫外部以 Matlab 或 R 實作的程式。

  • Data Processing Applications Spark 可在 clusters 之間平行處理資料,隱藏了分散式運算、網路傳輸、錯誤處理的複雜度。簡單地說,如果有某個應用程式的某一個部分,需要即時資料分析的數據,那麼在這個應用程式背後,可以劃分一個區塊,利用 Spark 進行即時運算,然後顯示在應用程式的畫面上。

Spark Streaming

Spark Streaming 支援以下三種業務場景 * 無狀態操作 只關注當前的 DStream 中的即時資料,例如對當前DStream中的資料做正確性校驗。

  • 有狀態操作 對有狀態的 DStream 進行操作時,需要依賴以前的資料,例如統計網站各個模塊總的訪問量。

  • 窗口操作 對指定時間段範圍內的 DStream 數據進行操作,例如需要統計一天之內網站各個模塊的訪問數量。

騰訊、雅虎、優酷 應用的參考

  1. 騰訊

    廣點通 pCTR 投放系統是最早使用Spark的應用之一,支援每天上百億的請求量。

    基於日誌數據的快速查詢系統業務構建於Spark之上的Shark,利用其快速查詢以及內存表等優勢,提供日誌數據的即時查詢功能。在性能方面,普遍比Hive高2-10倍。

  2. Yahoo

    Yahoo將Spark用在Audience Expansion中的應用。Audience Expansion是廣告中尋找目標用戶的一種方法:首先廣告者提供一些觀看了廣告並且購買產品的樣本客戶,據此進行學習,尋找更多可能轉化的用戶,對他們定向廣告。

    Yahoo採用的算法是logistic regression。同時由於有些SQL負載需要更高的服務質量,又加入了專門跑Shark的大內存集群,用於取代商業BI/OLAP工具,承擔報表/儀表盤和交互式/即席查詢,同時與桌面BI工具對接。目前在Yahoo部署的Spark集群有112台節點,9.2TB內存。

  3. 淘寶

    淘寶技術團隊將Spark運用於淘寶的推薦相關算法上,同時還利用Graphx解決了許多問題,包括以下計算場景:基於度分佈的中樞節點發現、基於最大連通圖的社區發現、基於三角形計數的關係衡量、基於隨機遊走的用戶屬性傳播等。

  4. 優酷土豆

    優酷土豆在使用Hadoop集群的問題主要包括:第一是商業智能BI方面,分析師提交任務之後需要等待很久才得到結果;第二就是大數據量計算,比如進行一些模擬廣告投放之時,計算量非常大的同時對效率要求也比較高,最後就是機器學習和圖計算的迭代運算也是需要耗費大量資源且速度很慢。

    最終發現這些應用場景並不適合在MapReduce裡面去處理。通過對比,發現Spark性能比MapReduce提升很多。首先,交互查詢響應快,性能比Hadoop提高若干倍;模擬廣告投放計算效率高、延遲小(同hadoop比延遲至少降低一個數量級);機器學習、圖計算等迭代計算,大大減少了網絡傳輸、數據落地等,極大的提高的計算性能。目前Spark已經廣泛使用在優酷土豆的視頻推薦(圖計算)、廣告業務等。

References

Spark適用哪些場景?

RDD:基於內存的集群計算容錯抽象

Cisco电话面试【Spark方向】

大數據三大平台hadoop,storm,spark的區別和應用場景

Spark Streaming 的原理以及應用場景介紹

解析Spark在騰訊、雅虎、優酷的成功應用

2分鐘讀懂大數據框架Hadoop和Spark的異同

2016/04/11

語音資料處理: Resampling

由於電話的語音資料,通常是以 8000 Hz 進行聲音取樣 (sampling) 的頻率,也就是每秒只取得 8000 個資料點,但如果是不同的聲音應用,可能會需要不同的取樣頻率,如果取樣的頻率越高,資料點越多,當然聲音的品質會越高,但如果要在不同的應用之間,讓語音資料能夠互相傳遞,就會面臨到 Resampling 的問題。

Audio 相關名詞的基本概念

通常從麥克風取到的語音資料,就是一連串的 byte array,要處理語音資料之前,要先對 Audio 有些基本的概念,關於 Audio 的相關概念,可以參考這個網頁 演算法筆記 - Audio)

sampling rate 取樣頻率:因為語音資料的數位化,電腦無法處理連續的資料,只能用大量的資料點,來趨近原始的連續函數,如果每一秒鐘取樣的資料點越多,就會越接近原始的連續函數,當然聲音的品質就越好。電腦的聲音檔案,通常採用 48000Hz 或 44100Hz 。手機與電話的聲音傳輸為 8000Hz 。

bit depth 位元深度:一個訊號用多少個位元紀錄。數值越高,音質越好。電腦的聲音檔案,通常採用 16 bits 或 24 bits。比較常見的是 16 bits 也就是兩個 bytes,剛好可對應到資料型別為 short。

channel 聲道:同時播放的聲音訊號總共幾條。比較常見的就是 mono 單聲道或是 stereo 雙聲道。當我們用 16 bits 進行聲音取樣時,如果是 mono,就是每 2個 bytes 一個取樣資料點,如果是 stereo,因為每一次取樣,會產生兩個資料點,所以取得的資料,就會是左聲道 2 bytes 加上右聲道 2 bytes,左右聲道交錯的 byte array。

在取樣理論中,原始的聲音音波如果是 x Hz,這時候取樣的頻率至少必須要是 2x Hz 兩倍以上,才能記錄原始震波的上下數值,換句話說,當 samping rate 為 48000Hz,最多只能記錄到 24000Hz 的聲音。

由於人類的聽覺範圍為 20Hz ~ 20000 Hz,但是一般的電話為了減少傳輸的資料量,只使用 8000Hz,也就是只能記錄到 4000Hz 以下的聲音,所以在電話裡面聽到的另外一方的聲音,通常會跟直接面對面聽到的聲音不一樣。

Endianness

由於每一個 sample 的聲音資料超過了一個 byte 的容量,在程式中就必須要用 2個 bytes 以上的容量來儲存資料,這時候,如果我們需要以 sample 點來進行一些運算處理,勢必要用某一個資料型別來將超過一個 byte 的資料讀取進來。

因為聲音資料是 byte array 的方式傳遞進來,但是當一個資料點要轉換成 byte array 時,就會有順序的問題,也就是 Endianess 的問題。

例如: 0x12345678,首先拆成 bytes:12 34 56 78
然後 byte array 的表示方式就有兩種
Little Endian: 最低位元組在後面 78 56 34 12
Big Endian: 最低位元組在最前面 12 34 56 78

Big-Endian 和 Little-Endian 並不是計算機工程師定義的名稱, 而是英文作家 Jonathan Swift 在將近 300 年前創造的名詞!這個名詞出現於 Swift 創作的著名小說 "Gulliver's Travels", 中文通常翻譯作《格利佛遊記》或是《小人國歷險記》。

格利佛意外抵達 Lilliput 的時候,該國正在內戰。內戰分成兩大派系:Big-Endian 和 Little-Endian。Big-Endian (保守派) 堅持要從雞蛋比較大的那一頭敲開蛋殼,而 Little-Endian (改革派) 堅持要從雞蛋比較小的那一頭敲開蛋殼。雞蛋比較大的那一頭叫做 big-end,因此支持大頭開蛋者就叫做 big-endian;同理,另一派就叫做 Little-endian。

ref: 用 C 語言窺探記憶體

以目前常見的CPU為例:

  • INTEL X86、DEC VAX 使用 Little-Endian 設計;
  • HP、IBM、MOTOROLA 68K 系列使用 Big-Endian 設計;
  • POWERPC 同時支援兩種格式,稱為 BI-ENDIAN。
  • 而 JVM 這個 "Virtual Machine" 是採用 Big-Endian

在聲音處理的程式中,會需要注意是用哪一種位元排序方式,因為不同的排序會造成完全不同的數值。

Resampling

因為我們需要在不同的取樣應用程式中,轉換語音資料,如果是從取樣頻率 16000 Hz 要轉換成取樣頻率 8000 Hz,最簡單的想法,就是把多餘的資料丟掉,把原本 16000 Hz 的 byte array 裡面的資料丟掉一半,就會變成 8000 Hz。

但是如果是要把 8000 Hz 轉換成 16000 Hz 的語音資料,要用什麼方法無中生有呢?這時候可以用另一個最簡單的方式,就是內插法 linear interpolation。

Interpolation 內插法 就像是以下這個函數圖形:

(x0, y0) 以及 (x1, y1) 分別是已知的兩個座標點,所以只要計算出這條線的斜率,利用 y=mx+c 這樣的方程式,我們可以產生出新的資料點,而且這個值是根據原本兩個鄰近的資料點產生出來的。

如果我們需要的新的資料點的 x 的位置,並不是剛好在 x0 及 x1 的中間,就像是 Linear interpolation 的圖形一樣,這時候我們必須要讓比較靠近 x 的 x0 有比較高的 weight 權重。

如果不是用線性函數,而是用高次方的函數,這就稱為 Polynomial interpolation

類似的問題,會在單聲道以及雙聲道的轉換發生,因為立體聲的音效,左右聲道的聲音資料不同,當立體聲雙聲道的語音資料要轉換成單聲道時,可以用內插法的方式進行資料合併,相反地,當單聲道轉換成雙聲道,理論上應該只要複製一份一樣的資料就好了。

濾波器 filter

濾波器是修改聲音的工具,例如刪除聲音的高頻部分,稱做 lowpass filter。

剛剛在取樣理論中有提到,原始的聲音音波如果是 x Hz,這時候取樣的頻率至少必須要是 2x Hz 兩倍以上,才能記錄原始震波的上下數值,換句話說,當 samping rate 為 48000Hz,最多只能記錄到 24000Hz 的聲音。

因此,當我們要把聲音訊號,由 sample rate 16000 Hz 降低為 8000 Hz 的時候,就會發生頻率超過 4000 Hz 的聲音資料,會收錄在降低取樣的聲音資料中,這時候就會發生高頻的噪音,因此我們必須在降低取樣頻率之前,就先將資料放入 low-pass filter 裡面,先將超過 4000Hz 頻率的資料濾除,然後再進行 resampling。

低通濾波器 Low-pass filter

References

How to convert between (most) audio formats in .NET