由於路由式 IP 網路的普及化,企業與個人都希望降低電信費用,我們何不利用 IP 網路的數據傳輸來實作語音服務呢?本篇是筆者研讀許多 VoIP 相關文件後所整理的筆記,透過 SIP 不僅可以實現通話及會議通訊功能,也同時擁有視訊會議與訊息傳輸的技術,不過你可能會想,若只局限於 PC to PC 間的通話,是否對於使用者來說方便性過於狹隘?但是對於這部份,筆者最後也整理了幾個 APP client 提供使用者作為參考,讓你的智慧型手機 (android、iOS) 也可以享有與 PC 相同的服務品質。
SIP 網路元件可分為使用者代理器 (User Agents - UA) 與伺服器 (Server) 兩部分。其中 UA 又可細分為 UAC(User Agent Client) 與 UAS(User Agent Server)。UAC 負責建立請求,如:一個通話的開始,而 UAS 負責依照請求產生應答,如:接收通話。換而言之,每個 SIP User Agent 都包含 UAC 及 UAS ,如此一來每個終端設備都兼具接收與撥號功能。流程如下圖:
這個伺服器主要是接收 User Agent 註冊要求功能,並且提供 authentication (驗證)服務,通常與 Proxy 或 Redirect Server 放在一起,且更新 Location Server 上的 User Agent 資訊與位址。其流程如下:
- Register Server 接收並處理使用者之註冊請求。
- 使用者藉由註冊請求,向網路特定 Register Server 登錄該使用者連位址。
- 註冊處理完成後,註冊伺服器將使用者之聯絡位址上傳至 Location Server 資料庫中儲存。
SIP Proxy 主要負責將 User Agent 或者其他 SIP Proxy 發送的請求代為傳遞到另一個 SIP 元件。當 User Agent 發出請求時,請求並非直接傳遞到目的地端的 User Agent ,而是經過一層層的 SIP Proxy 後才將請求訊息傳遞至目的地端。每個 SIP Prxoy 都會決定下一個路由並且對請求訊息做出適當加工處理後才傳遞。反之,目的地端回送訊息給發送端也是如此。
SIP Proxy 事實上同時扮演 SIP Client 與 SIP Server 兩個角色,當他接受其他 Client 請求時,即為 SIP Server。當他轉送 SIP 請求至其他 Server 時,即為 SIP Client。
Redirect Server 目的是接受 SIP 的要求,將位址對應到零個或多個新的位址,並將結果回傳給 Client。
- 與 Proxy Server 不同,Redirect Server 並不會發出自己的 SIP 請求。
- 與 User Agent Server 不同,Redirect Server 並不會接受或結束一個通話。
當 Proxy Server 呼叫建立時,向 Location Server 查詢被呼叫者的聯絡位址,以轉送呼叫建立訊息。通常被 SIP Redirect 或 Proxy Server 所使用。
- 負責 SIP 協定和其他非 SIP 協定 (PSTN)轉換的橋樑
- 負責語音通訊時資料傳送,將封包型態的數位資料轉換成類比訊號後,由 PSTN 網路傳送,或將類比資料轉成數位後在包裝成封包後,由 IP 網路傳送出去。
- 簡單 : SIP 通訊協定與 HTTP 通訊協定類似,都是採用請求 (Requests) 與回應 (Responses) 模式,提供數種命令與回應代碼來完成呼叫控制。
- 以文字為主 : 類似 HTTP 的作法,將協定的訊息以文字表達並使用標準的字元編碼,如 ASCII 、 UTF-8 ,運用這個方式的好處是容易實作與偵錯、擴充性佳、增加額外訊息不需大幅更動原有解析程式。
- 與傳輸層分離 : SIP 運作在傳輸層之上,可以提昇網路傳輸的適應性和支援性。在封包容易遺失的環境下使用 TCP 連線,而在環境叫穩定的狀況下使用 UDP。
- 支援移動性 : SIP 在制定時,就已經將支援移動性納入考量,就算使用者在呼叫階段或是交談過程中,都可以藉由轉送或是重新邀請來維持會談。
- SDP (會談描述協定) : 此協定主要用來協商雙方建立多媒體資料封包通道之用,雙方會在邀請 (INVITE) 訊息的三向交握過程中交換彼此可以使用的通訊方式及資料格式。
- RTP (即時傳輸協定) : 此協定用於即時資料傳輸,如影像資料...等,由於 VoIP 所傳輸的多媒體資料大多屬於即時性優先於資料完整性,所以利用 RTP 的特性來編排及傳遞這些資料內容最適合。
- LDAP (輕量及目錄訪問協定) : 此協議主要是讓 SIP Server 用來與位址服務的伺服器溝通,以取得每個目的的正確位址。
SIP 的六項基本的方法向伺服器發出請求,以下簡單敘述:
方法 | 敘述 |
---|---|
INVITE | 邀請建立會議(Session) |
ACK | 回覆確認邀請(INVITE)的回覆已收到 |
OPTIONS | 用來傳送 midcall訊號(mid-session 資訊)並不改變 Session 狀態 |
BYE | 結束一個已連結的 Session |
CANCEL | 取消一個已發出邀請但尚未連結的 Session |
REGISTER | 註冊使用者的 URL |
SIP Responses 訊息包含一個三個位數的狀態碼 (status code),用來表示回應原因:
- 1XX - Information Messages. (訊息通知,請求處理中尚未完成。)
- 2XX - Successful Responses. (請求處理成功。)
- 3XX - Redirection Responses. (重新導向,將請求訊息重新導向至另一個 SIP 元件。)
- 4XX - Request Failure Responses. (客戶端錯誤,錯誤的原因在於請求端。可以矯正後重試。)
- 5XX - Server Failure Responses. (伺服器端錯誤,錯誤的原因在於目的端。可以重試其他的 location。)
- 6XX - Global Failure Responses. (錯誤 - Global Error ,請求失敗且無法重試。)
代碼 | 敘述 | 代碼 | 敘述 |
---|---|---|---|
100 | 正在嘗試 | 305 | 使用代理伺服器 |
180 | 正在撥打 | 380 | 替代服務 |
181 | 正在轉接 | 400 | 呼叫不當 |
182 | 正在排隊 | 401 | 未經授權 |
183 | 通話進展 | 402 | 要求付費 |
200 | OK | 403 | 被禁止的 |
202 | 被接受 | 404 | 未發現用戶 |
300 | 多項選擇 | 405 | 不允許的方法 |
301 | 被永久遷移 | 406 | 不可接受的 |
302 | 被暫時遷移 | 407 | 需要代理伺服器授權 |
代碼 | 敘述 | 代碼 | 敘述 |
---|---|---|---|
408 | 呼叫超時 | 481 | 通話/事務不存在 |
410 | 用戶曾經存在,但現在不存在 | 482 | 檢測到迴圈 |
413 | 呼叫實體過大 | 483 | 跳數過多 |
414 | 呼叫 URI 過長 | 484 | 位址不全 |
415 | 不支援的媒體類型 | 485 | 模糊不清 |
416 | 不支援的 URI 方案 | 486 | 忙碌中 |
420 | 不當擴展 | 487 | 呼叫被終止 |
421 | 需要擴展 | 488 | 此處不可接受 |
423 | 時間間隔過短 | 491 | 呼叫待批 |
480 | 暫時不可以使用 | 493 | 無法解讀 |
代碼 | 敘述 |
---|---|
500 | 伺服器內部錯誤 |
501 | SIP 呼叫方法在此無法實施 |
502 | 不當閘道 |
503 | 服務不可使用 |
504 | 伺服器超時 |
505 | 伺服器不支援 SIP 協定的這個版本 |
513 | 消息過長 |
600 | 各處忙碌 |
603 | 拒絕 |
604 | 無處存在 |
605 | 不可使用 |
由下圖可知,當 Client 1 撥打電話給 Client 2 時,會先發送 INVITE 請求並且與 Client 1 請求代理伺服器授權。當前置動作完成以後, SIP Server 會發送 INVITE 給 Client 2 ,此時雙方的電話將會響起,假設雙方都接受電話請求,此時開始進行對話。最後,當一方送出 BYE 訊息時,系統會執行通話終止,並且同時送出 BYE 訊息給另一方結束此次通話。
- Ubuntu - 14.04
- OpenSIPS - 2.1
- Openstack -
主機 | Private IP | Floating IP |
---|---|---|
SIP Server | 192.168.100.174 | 10.26.1.25 |
sudo apt-get update
sudo apt-get install -y git make bison flex mysql-server mysql-client libmysqlclient-dev libncurses5 libncurses5-dev
cd ~/
sudo git clone https://github.com/OpenSIPS/opensips.git -b 2.1 opensips_2_1
sudo vim ~/opensips_2_1/Makefile.conf.tmplate
移除 exclude_modules 中 db_mysql 並儲存
cd ~/opensips_2_1
sudo make all
sudo make install
sudo vim /usr/local/etc/opensips/opensipsctlrc
修改如下,將部分註解刪除
## your SIP domain
SIP_DOMAIN=ubuntustudio
## chrooted directory
# $CHROOT_DIR="/path/to/chrooted/directory"
## database type: MYSQL, PGSQL, ORACLE, DB_BERKELEY, or DBTEXT,
## by default none is loaded
# If you want to setup a database with opensipsdbctl, you must at least specify
# this parameter.
DBENGINE=MYSQL
## database host
DBHOST=localhost
## database name (for ORACLE this is TNS name)
DBNAME=opensips
# database path used by dbtext or db_berkeley
DB_PATH="/usr/local/etc/opensips/dbtext"
## database read/write user
DBRWUSER=opensips
## password for database read/write user
DBRWPW="opensipsrw"
## database super user (for ORACLE this is 'scheme-creator' user)
DBROOTUSER="root"
# user name column
USERCOL="username"
若出現
ERROR: database engine not specified, please setup one in the config script
錯誤,請修改 /usr/local/etc/opensips 權限。
/usr/local/sbin/opensipsdbctl create
你會看到如下方結果:
MySQL password for root:
INFO: test server charset
INFO: creating database opensips ...
INFO: Core OpenSIPS tables succesfully created.
Install presence related tables? (y/n): y
INFO: creating presence tables into opensips ...
INFO: Presence tables succesfully created.
Install tables for imc cpl siptrace domainpolicy carrierroute userblacklist? (y/n): y
INFO: creating extra tables into opensips ...
INFO: Extra tables succesfully created.
如果執行出現錯誤,可以從 /var/log/syslog 檢視錯誤資訊。
- var/run 路徑權限不足
sudo chmod 777 /var
sudo chmod 777 /var/run
- opensips.cfg 權限不足
sudo chmod 755 /usr/local/etc/opensips/opensips.cfg
使用你慣用的編輯軟體如: vim ,開啟 /usr/local/etc/opensips/opensips.cfg 進行設定。
...
advertised_address="10.26.1.25"
alias="10.26.1.25"
listen=udp:192.168.100.174:5060
...
若你想在 AWS EC2 或 Openstack Instance 佈署 OpenSIPS 服務,請務必加入 advertised_address 與 alias ,如此一來你的服務才能夠被正確的對應出來。如果你使用的是 EC2 請輸入 Public IP ,如果你使用的是 Openstack Instance 請輸入 Floating IPs。
首先使用 mysql -u root -p
指令並輸入密碼後進入 MySQL ,接下來,透過以下指令建立 Domain 至 opensips.domain 資料表。
INSERT INTO opensips.domain(domain) VALUES('192.168.100.174');
並且可以透過搜尋語法,確認是否有將該筆資料新增進資料表中。
SELECT * FROM opensips.domain;
最後,離開 MySQL。
exit;
啟動:
/usr/local/sbin/opensipsctl start
暫停:
/usr/local/sbin/opensipsctl stop
重新啟動:
/usr/local/sbin/opensipsctl restart
如果執行時出現錯誤,請檢查 opensips.cfg 、 /var 與 /var/run 權限是否有誤。
- Mac OS : Yate Client、Zoiper
- Android : ECOA Sip (可至 Play 商店下載)
- iOS : Zoiper (可至 App Store 下載)
以上為筆者列舉幾項作為示範,若需要更多相關用戶端軟體可至 open source VOIP Software 取得。