matlab中inband函数,pjsip 实现 DTMF 数据获取,并解析按键信息
背景:
業(yè)務(wù)需要在 android 設(shè)備上添加支持通過網(wǎng)關(guān)撥打客戶電話,并根據(jù)客戶按鍵反饋執(zhí)行相應(yīng)的操作
平臺:
RK3399 + Android 7.1 + pjproject-2.4
步驟:
對 sip 這塊小白一枚,接到任務(wù)后做了如下操作:
1 了解 pjsip 、DTMF,并編譯出所需要的庫
這里參考了:《 https://www.cnblogs.com/lijingcheng/p/4454928.html DTMF三種模式(SIPINFO,RFC2833,INBAND)》介紹,了解了什么是 DTMF,內(nèi)容如下:
1、DTMF(雙音多頻)定義:由高頻音和低頻音的兩個正弦波合成表示數(shù)字按鍵(0~9 * # A B C D)。
2、SIP中檢測DTMF數(shù)據(jù)的方法:SIPINFO、RFC2833、INBAND
1)SIPINFO
為帶外檢測方式,通過SIP信令通道傳輸DTMF數(shù)據(jù)。沒有統(tǒng)一的實現(xiàn)標(biāo)準(zhǔn),目前以Cisco SIPINFO為標(biāo)準(zhǔn),通過SIPINFO包中的signal字段識別DTMF按鍵。注意當(dāng)DTMF為“*”時不同的標(biāo)準(zhǔn)實現(xiàn)對應(yīng)的signal=*或signal=10。SIPINFO的好處就是不影響RTP數(shù)據(jù)包的傳輸,但可能會造成不同步。
2)RFC2833
為帶內(nèi)檢測方式,通過RTP傳輸,由特殊的rtpPayloadType即TeleponeEvent來標(biāo)示RFC2833數(shù)據(jù)包。同一個DTMF按鍵通常會對應(yīng)多個RTP包,這些RTP數(shù)據(jù)包的時間戳均相同,此可以作為識別同一個按鍵的判斷依據(jù),最后一包RTP數(shù)據(jù)包的end標(biāo)志置1表示DTMF數(shù)據(jù)結(jié)束。另外,很多SIP UA 包括IAD都提供TeleponeEvent的設(shè)置功能如3CX Phone,Billion-IAD,ZTE-IAD等默認(rèn)的TeleponeEvent都為101,但可以人為修改,這時要求在進行RFC2833 DTMF檢測之前需事先獲取SDP協(xié)商的TeleponeEvent參數(shù)。
3)INBAND
為帶內(nèi)檢測方式,而且與普通的RTP語音包混在一起傳送。在進行INBAND DTMF檢測時唯一的辦法就是提取RTP數(shù)據(jù)包進行頻譜分析,經(jīng)過頻譜分析得到高頻和低頻的頻率,然后查表得到對應(yīng)的按鍵,進行頻譜分析的算法一般為Goertzel,這種算法的實現(xiàn)也很簡單,網(wǎng)上有很多可以下到,但建議采用定點算法,浮點算法效率很低。
在選擇壓縮比很高碼率很低的codec,比如G.723.1和G.729A等,建議不要使用INBAND模式,因為INBAND DTMF數(shù)據(jù)在進行復(fù)雜編解碼后會產(chǎn)生失真,造成DTMF檢測發(fā)生偏差或失敗。
另外,還特別需要注意的一點就是很多SIP UA中INBAND都是伴隨著RFC2833和SIPINFO同時發(fā)生的,這時需要區(qū)別對待,最好選擇RFC2833和SIPINFO
2 抓sip通話過程中手機按鍵的數(shù)據(jù)包
通過 Wireshark 分析,在sip通過過程中,對方按鍵時,網(wǎng)關(guān)回傳給 Android 設(shè)備的 DTMF 屬于 RFC2833 的模式,截圖如下:
3 pjsip 是否支持DTMF?
知道了當(dāng)前網(wǎng)關(guān)是以 RFC2833 方式回傳用戶按鍵信息了,接下來就是一波網(wǎng)絡(luò)檢索的操作,要先確認(rèn)下 pjsip 是否支持 DTMF?
找到一篇博客《 https://www.twblogs.net/a/5b8076cb2b71772165a7c25b PJSIP 檢測通話過程中對方手機發(fā)送過來的in-bnad DTMF(no rfc2833)按鍵信息》了解到 pjsip 不支持 in-band DTMF no rfc2833 這種 DTMF,然后看了下該文檔中記錄的操作,大概意思就是:檢測 SIP 客戶端接收到的數(shù)據(jù)流 ——> 用 Spandsp的庫分析該數(shù)據(jù)流獲取 DIMF 數(shù)據(jù) ——> 添加回調(diào)得到按鍵信息
奈何我對 sip 的了解應(yīng)該還沒有該博主多,看了下添加的 code 也較繁瑣,就沒有去實驗了。但是其實現(xiàn)的大體思路和我一開始想的一樣,若是 pjsip 不支持的話,就直接對數(shù)據(jù)流進行分析
4 開始尋找數(shù)據(jù)流的旅程
了解到 pjsip 不支持 DTMF 情況,暫敲定的方案是找到 rtp 獲取數(shù)據(jù)流的函數(shù),看下是否容易進行分析。
在這里為了方便實驗看數(shù)據(jù),我在 ./pjlib/include/pj/log.h 添加了如下code(要同步修改編譯文件,加上 -llog 庫),方便自己打 log:
#include
#define SEEINER_TAG "twz_sip"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,SEEINER_TAG,__VA_ARGS__)
//#define LOGE(...)
折騰到快要下班的時間,終于截取到了 DTMF 數(shù)據(jù)流,用Android設(shè)備通過網(wǎng)關(guān)打自己手機,Android設(shè)備log同步打印出我手機的撥號按鍵信息,中間的尋找過程就不做敘述了,直接上結(jié)果:
1 transport_udp.c 中 on_rx_rtp 函數(shù)能獲取每一幀的 RTP 數(shù)據(jù)
2 on_rx_rtp 會將取到的數(shù)據(jù)丟給 ioqueue_common_abs.c 文件中的 pj_ioqueue_recvfrom 函數(shù)進行分析
3 pj_ioqueue_recvfrom 函數(shù)將收到的數(shù)據(jù)進一步丟給 sock_bsd.c 文件中的 pj_sock_recvfrom 函數(shù)進行分析
4 在 pj_sock_recvfrom 函數(shù)中調(diào)用 recvfrom函數(shù)進一步對數(shù)據(jù)進行處理,這里打印 recvfrom 返回值 len 發(fā)現(xiàn),每當(dāng)我手機撥號時就會收到幾幀 len = 16 的字節(jié)數(shù)據(jù),對比之前抓包的 RTP EVENT 數(shù)據(jù),懷疑這 16 字節(jié)包含按鍵信息,后經(jīng)過打 log 發(fā)現(xiàn),其第 13 個字節(jié)即為撥號鍵,第14字節(jié)標(biāo)志點擊某個鍵結(jié)束(這里第14 字節(jié)對我來說有兩個作用:1 判斷按了某個鍵,且用戶已按完該鍵了 2 可以分析用戶連續(xù)按了某個鍵次數(shù))
即以上4步RTP 數(shù)據(jù)流通過程:
on_rx_rtp ——> pj_ioqueue_recvfrom ——> pj_sock_recvfrom ——> recvfrom
5 在 RTP 流中找到了按鍵數(shù)據(jù)后,因為對 pjsip 不夠了解,且為了最小化對 sip 業(yè)務(wù)流程影響,我直接在 pj_sock_recvfrom 函數(shù)里添加了回調(diào)函數(shù),并在 sock_bsd.c 中實現(xiàn)了 注冊該回調(diào)的函數(shù)
6 在 pjsua2_wrap.cpp jni 文件實現(xiàn)回調(diào)函數(shù),再寫個 jni 函數(shù)回調(diào) java 函數(shù)將每次的按鍵數(shù)據(jù)給實時的上報上去
至此,Android設(shè)備端就可以通過 pjsip 實時獲取通話過程中用戶的按鍵信息了
總結(jié)
以上是生活随笔為你收集整理的matlab中inband函数,pjsip 实现 DTMF 数据获取,并解析按键信息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: e开头的正则 php,PHP正则表达式e
- 下一篇: php 跳转网页 变量,php变量与JS