解析:基于PC平臺的VoIP通信模式的實現(xiàn)
2007/02/05
1 序言
近幾年來傳統(tǒng)電信業(yè)的發(fā)展勢頭逐漸減弱。在激烈的市場競爭中,電信業(yè)需要不斷地去尋找新的收入增長點。VoIP在全球隨著技術(shù)的成熟及各種人為管制的放松,開始進(jìn)入一個新的發(fā)展時期。低廉的費用、低的帶寬、話音和數(shù)據(jù)應(yīng)用的集成以及應(yīng)用性廣泛等優(yōu)點使VoIP必然成為了人們的選擇。
IP(Internet Protocol)電話是一種數(shù)字電話,是技術(shù)創(chuàng)新的一種通信服務(wù)業(yè)務(wù)。它把語音、壓縮編碼、打包分組、分配路由、存儲交換、解包解壓等交換處理在IP網(wǎng)或互聯(lián)網(wǎng)上實現(xiàn)語音通信。
傳統(tǒng)的電話網(wǎng)是以電路交換方式傳輸語音,所要求的傳輸寬帶為64kbit/s。而VoIP是以IP分組交換網(wǎng)絡(luò)為傳輸平臺,對模擬的語音信號進(jìn)行壓縮、打包等一系列的特殊處理,使之可以采用無連接的UDP協(xié)議進(jìn)行傳輸。不同編碼方案應(yīng)用于VoIP,使得話音可以以不同的速率進(jìn)行傳輸,使得VoIP的傳輸帶寬進(jìn)一步減小到5-11kbit/s。
傳統(tǒng)的電話網(wǎng)絡(luò)都有自己遵循的協(xié)議,在呼叫過程中都要用到這些協(xié)議,比如用于電路交換的7號信令等。H.323和sip信令協(xié)議被廣泛應(yīng)用于VoIP網(wǎng)絡(luò)中。H.323是一個框架性協(xié)議,這一框架體系結(jié)構(gòu)包括H.323終端、網(wǎng)關(guān)、關(guān)守和MCU。網(wǎng)關(guān)是VoIP的重要組成部分,網(wǎng)關(guān)完成了兩項功能的轉(zhuǎn)換,媒體信息編碼的轉(zhuǎn)換和信令的轉(zhuǎn)換。通過這兩種轉(zhuǎn)換,網(wǎng)關(guān)將TCP/IP網(wǎng)和PSTN網(wǎng)連接連了起來。
2 VoIP軟件的實現(xiàn)
一般IP電話的業(yè)務(wù)可分為3類: PC-to-PC, PC-to-Phone和Phone-to-Phone。這里主要是針對PC-to-PC的編程過程進(jìn)行介紹。
IP電話的基本數(shù)據(jù)流程為:呼叫方經(jīng)錄音設(shè)備獲取音頻流,然后對音頻流進(jìn)行編碼、壓縮、打包處理。其中計算機對輸入的不同類型的數(shù)據(jù)進(jìn)行不同的處理(如果是音頻數(shù)據(jù),采用無連接的UDP協(xié)議進(jìn)行傳輸;如果是信令和數(shù)據(jù)則采用面向連接的TCP協(xié)議進(jìn)行傳輸),然后經(jīng)網(wǎng)絡(luò)傳輸?shù)奖唤蟹。被呼叫方接收到?shù)據(jù)以后,再進(jìn)行一系列的反變換,解包、解壓和解碼,送入放音緩沖區(qū),經(jīng)音頻設(shè)備輸出語音。
2.1 通信模塊的實現(xiàn)
MFC中提供了封裝的Socket類,它提供了全面的由事件驅(qū)動的Socket通信能力。程序必須按要求通過此Socket發(fā)送和接收數(shù)據(jù)。Winsock使用的是TCP協(xié)議或UDP協(xié)議,允許建立并保持一個到遠(yuǎn)程計算機上的連接,且可以在連接結(jié)束之前實時地進(jìn)行數(shù)據(jù)交換。用戶僅通過設(shè)置屬性并借助事件處理就能輕而易舉地連接到一個遠(yuǎn)程的計算機上。使用Winsock時,通信的雙方需要選定相同的協(xié)議。TCP協(xié)議適用于傳送大容量、需要安全性保證的數(shù)據(jù)文件; 而UDP協(xié)議適用需要分別與很多下屬通信,或建立的連接比較多且為時變的情況,如語音通信。
Socket是面向客戶/服務(wù)器模式設(shè)計的,它針對客戶和服務(wù)器程序提供了不同的系統(tǒng)調(diào)用。同時它還分為面向連接和無連接兩種類型。對于語音傳輸,由于語音對實時性要求高,所以采用無連接的形式。而對于信令和數(shù)據(jù)傳輸,對準(zhǔn)確性要求比較高,通常采用面向連接的形式。
//服務(wù)器端
sock=socket(AF_INET,SOCK_STREAM,0); //創(chuàng)建socket
if (bind(sock,(sockaddr*)&serv,addlen)) //綁定
{
m_edit.SetWindowText("bind error");
}
listen(sock,5);
AfxBeginThread(serthread,0); //調(diào)用線程
//客戶端
clisock=socket(AF_INET,SOCK_STREAM,0);// 創(chuàng)建socket
while(connect(clisock,(sockaddr*)&(cli),sizeof(cli))!=0)
{
dlg->m_edit.SetWindowText("等待.....");
for (int i=0;i<=65000;i++) //空循環(huán)
for(int j=0;j<=200;j++);
………
}
2.2 音頻模塊的實現(xiàn)
IP電話音頻功能的實現(xiàn)主要包括語音的錄制和播放。因為在IP電話中采集實時的音頻數(shù)據(jù)而不是WAVE文件,而且要把實時的語音數(shù)據(jù)傳輸出去,所以編程過程中采用了底層音頻處理函數(shù), 這些函數(shù)允許應(yīng)用程序直接與底層驅(qū)動程序通信,對錄制和播放提供更靈活的控制。對于波形設(shè)備來說,不論是錄制還是播放波形,系統(tǒng)要處理的數(shù)據(jù)量都很大,為了少占用內(nèi)存,底層服務(wù)函數(shù)以數(shù)據(jù)塊為單位進(jìn)行處理, 應(yīng)用程序要自己分配內(nèi)存,并將內(nèi)存塊的地址、大小等信息告訴底層音頻驅(qū)動程序。
首先介紹幾個要用到的數(shù)據(jù)結(jié)構(gòu)。WAVEFORMATEX結(jié)構(gòu)定義了WAVE音頻數(shù)據(jù)文件的格式。WAVEHDR結(jié)構(gòu)定義了波形音頻緩沖區(qū)。讀出的數(shù)據(jù)首先要填充此緩沖區(qū)才能送音頻設(shè)備播放,聲音的采集和播放都是在操作這個音頻數(shù)據(jù)塊結(jié)構(gòu)。 實際上主要用到的就是第一個成員變量lpData,所以只要在分配緩沖區(qū)(內(nèi)存)的同時相應(yīng)分配WAVEHDR數(shù)據(jù)塊結(jié)構(gòu), 然后將緩沖區(qū)的指針賦給對應(yīng)的數(shù)據(jù)塊結(jié)構(gòu)的成員變量lpData,這樣當(dāng)一個緩沖區(qū)填滿后,也就是一個音頻數(shù)據(jù)塊填滿了,通過消息機制就可以在消息函數(shù)中進(jìn)行處理和播放,播放完后又可通過消息函數(shù)把緩沖區(qū)再送給音頻設(shè)備輸入驅(qū)動程序,繼續(xù)進(jìn)行采集并播放。
當(dāng)一次性分配多個緩沖區(qū)和數(shù)據(jù)塊結(jié)構(gòu)并賦給音頻設(shè)備輸入驅(qū)動程序后,至于把哪個緩沖區(qū)填滿,然后再把哪個空緩沖區(qū)賦給設(shè)備輸入驅(qū)動程序,不需人為干預(yù),完全由Windows控制。在程序設(shè)計中可以使用兩個數(shù)據(jù)塊,交替進(jìn)行,當(dāng)正播放第一個緩沖區(qū),就用第二個緩沖區(qū)接收。
//檢查語音輸入/輸出設(shè)備
if(!waveInGetNumDevs())
{
return FALSE;
}
if(!waveOutGetNumDevs())
{
return FALSE;
}
//打開音頻設(shè)備之前,需要先設(shè)置音頻數(shù)據(jù)格式
……………
//分配緩沖區(qū)所需要的內(nèi)存
pWaveOutHdr=(LPWAVEHDR)GlobalAllocPtr(GHND|GMEM_SHARE,sizeof(WAVEHDR));
pWaveHdr1=(LPWAVEHDR)GlobalAllocPtr(GHND|GMEM_SHARE,sizeof(WAVEHDR));
pWaveHdr2=(LPWAVEHDR)GlobalAllocPtr(GHND|GMEM_SHARE,sizeof(WAVEHDR));
//放音緩沖區(qū)
pOutBuffer1=(char*)GlobalAllocPtr(GHND|GMEM_SHARE,PCMBUFFER_SIZE*BLOCK_PER_BUFFER+500);
pOutBuffer2=(char*)GlobalAllocPtr(GHND|GMEM_SHARE,PCMBUFFER_SIZE*BLOCK_PER_BUFFER+500);
rBuffer=(char*)GlobalAllocPtr(GHND|GMEM_SHARE,PCMBUFFER_SIZE); //接收緩沖區(qū)
//打開音頻設(shè)備
result=waveOutOpen((LPHWAVEOUT)&hWaveOut,WAVE_MAPPER,(LPWAVEFORMATEX)&pcm.wf,(DWORD)hwnd,0L, CALLBACK_WINDOW)
2.3 語音壓縮模塊的實現(xiàn)
VoIP帶寬比電路交換更窄的主要原因是對數(shù)據(jù)進(jìn)行了壓縮處理。VoIP除了可使用最普通的編碼技術(shù)G.711外,還可以采用G.728, G.729, G.723.1等其它多種編碼方案。
G.711有A律和μ律兩種形式。G.711通常被稱為PCM(脈沖編碼調(diào)制)。如果在編程中選擇PCM編碼方式。
G.711提供了良好的語音質(zhì)量,但是它的主要缺點是需要64Kbit/s的帶寬。所以在程序中靈活的選擇編碼方式是很重要的。
ITU-T推薦的G.723.1標(biāo)準(zhǔn)可以同時支持兩種速率的編碼。一種是6.3kbit/s另一種是5.3kbit/s。所以,G.723.1在高速率下提供了好的通話質(zhì)量,是一種好的編碼方案。在程序中的實現(xiàn)是通過對G.723.1軟件包中相應(yīng)功能函數(shù)的調(diào)用來完成的,而且,在進(jìn)行壓縮以前要將G.723.1的鏈接庫導(dǎo)入程序中。
在需要進(jìn)行壓縮時,要調(diào)用下面G.723.1的編碼和解碼函數(shù):
void Coder(FLOAT *DataBuff, char *Vout); //編碼
void Decod(FLOAT *DataBuff, char *Vinp, short int Crc); //解碼
2.4 RTP封裝
因為語音傳輸對實時性要求非常高, 所以在程序中要采用基于UDP的RTP傳輸。UDP無法做到避免分組丟失和確保分組有序傳輸,運行在UDP上的RTP幫助實現(xiàn)了這些功能,RTP含有一個時間戳,可以利用這個時間戳來確保信息同步的傳輸給了目的用戶并計算出了時延和抖動。
在程序中要對語音數(shù)據(jù)進(jìn)行RTP格式封裝,使用了makertp()函數(shù)。而在解析是使用了isrtp()函數(shù)。
LONG makertp(databuf *pdata,unsigned long ssrc_i,unsigned long timestamp_i,unsigned short seq_i,int spurt);
BOOL isrtp(unsigned char *pkt,int len);
在進(jìn)行RTCP 格式的封裝時,使用了三個函數(shù):
rtcp_make_sdes();
rtcp_make_sr();
rtcp_make_rr()。
3 結(jié)論
本文主要是利用VC++語言來實現(xiàn)PC-to-PC的軟件電話,它提供給Internet用戶在全球任何地方上網(wǎng)便可以呼叫對方的能力,提高了通信效率,是一種新的通信模式。
中國聯(lián)通網(wǎng)站
相關(guān)鏈接:
湖州市|
宁南县|
南和县|
石泉县|
伊宁县|
宁晋县|
梨树县|
武清区|
台南县|
浮山县|
双峰县|
东乌珠穆沁旗|
娄烦县|
台北市|
神农架林区|
会昌县|
富源县|
华容县|
定陶县|
伊春市|
开鲁县|
贡嘎县|
仙桃市|
筠连县|
两当县|
焉耆|
秦安县|
永胜县|
康马县|
时尚|
临夏县|
塔河县|
罗甸县|
抚松县|
怀远县|
沈丘县|
吴堡县|
女性|
锡林浩特市|
运城市|
探索|