首頁>>>技術>>>VoIP

解析:基于PC平臺的VoIP通信模式的實現

2007/02/05

1 序言

  近幾年來傳統(tǒng)電信業(yè)的發(fā)展勢頭逐漸減弱。在激烈的市場競爭中,電信業(yè)需要不斷地去尋找新的收入增長點。VoIP在全球隨著技術的成熟及各種人為管制的放松,開始進入一個新的發(fā)展時期。低廉的費用、低的帶寬、話音和數據應用的集成以及應用性廣泛等優(yōu)點使VoIP必然成為了人們的選擇。

  IP(Internet Protocol)電話是一種數字電話,是技術創(chuàng)新的一種通信服務業(yè)務。它把語音、壓縮編碼、打包分組、分配路由、存儲交換、解包解壓等交換處理在IP網或互聯網上實現語音通信。

  傳統(tǒng)的電話網是以電路交換方式傳輸語音,所要求的傳輸寬帶為64kbit/s。而VoIP是以IP分組交換網絡為傳輸平臺,對模擬的語音信號進行壓縮、打包等一系列的特殊處理,使之可以采用無連接的UDP協議進行傳輸。不同編碼方案應用于VoIP,使得話音可以以不同的速率進行傳輸,使得VoIP的傳輸帶寬進一步減小到5-11kbit/s。

  傳統(tǒng)的電話網絡都有自己遵循的協議,在呼叫過程中都要用到這些協議,比如用于電路交換的7號信令等。H.323和sip信令協議被廣泛應用于VoIP網絡中。H.323是一個框架性協議,這一框架體系結構包括H.323終端、網關、關守和MCU。網關是VoIP的重要組成部分,網關完成了兩項功能的轉換,媒體信息編碼的轉換和信令的轉換。通過這兩種轉換,網關將TCP/IP網和PSTN網連接連了起來。

2 VoIP軟件的實現

  一般IP電話的業(yè)務可分為3類: PC-to-PC, PC-to-Phone和Phone-to-Phone。這里主要是針對PC-to-PC的編程過程進行介紹。

  IP電話的基本數據流程為:呼叫方經錄音設備獲取音頻流,然后對音頻流進行編碼、壓縮、打包處理。其中計算機對輸入的不同類型的數據進行不同的處理(如果是音頻數據,采用無連接的UDP協議進行傳輸;如果是信令和數據則采用面向連接的TCP協議進行傳輸),然后經網絡傳輸到被叫方。被呼叫方接收到數據以后,再進行一系列的反變換,解包、解壓和解碼,送入放音緩沖區(qū),經音頻設備輸出語音。

  2.1 通信模塊的實現

  MFC中提供了封裝的Socket類,它提供了全面的由事件驅動的Socket通信能力。程序必須按要求通過此Socket發(fā)送和接收數據。Winsock使用的是TCP協議或UDP協議,允許建立并保持一個到遠程計算機上的連接,且可以在連接結束之前實時地進行數據交換。用戶僅通過設置屬性并借助事件處理就能輕而易舉地連接到一個遠程的計算機上。使用Winsock時,通信的雙方需要選定相同的協議。TCP協議適用于傳送大容量、需要安全性保證的數據文件; 而UDP協議適用需要分別與很多下屬通信,或建立的連接比較多且為時變的情況,如語音通信。

  Socket是面向客戶/服務器模式設計的,它針對客戶和服務器程序提供了不同的系統(tǒng)調用。同時它還分為面向連接和無連接兩種類型。對于語音傳輸,由于語音對實時性要求高,所以采用無連接的形式。而對于信令和數據傳輸,對準確性要求比較高,通常采用面向連接的形式。

  //服務器端
  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); //調用線程
  //客戶端
  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 音頻模塊的實現

  IP電話音頻功能的實現主要包括語音的錄制和播放。因為在IP電話中采集實時的音頻數據而不是WAVE文件,而且要把實時的語音數據傳輸出去,所以編程過程中采用了底層音頻處理函數, 這些函數允許應用程序直接與底層驅動程序通信,對錄制和播放提供更靈活的控制。對于波形設備來說,不論是錄制還是播放波形,系統(tǒng)要處理的數據量都很大,為了少占用內存,底層服務函數以數據塊為單位進行處理, 應用程序要自己分配內存,并將內存塊的地址、大小等信息告訴底層音頻驅動程序。

  首先介紹幾個要用到的數據結構。WAVEFORMATEX結構定義了WAVE音頻數據文件的格式。WAVEHDR結構定義了波形音頻緩沖區(qū)。讀出的數據首先要填充此緩沖區(qū)才能送音頻設備播放,聲音的采集和播放都是在操作這個音頻數據塊結構。 實際上主要用到的就是第一個成員變量lpData,所以只要在分配緩沖區(qū)(內存)的同時相應分配WAVEHDR數據塊結構, 然后將緩沖區(qū)的指針賦給對應的數據塊結構的成員變量lpData,這樣當一個緩沖區(qū)填滿后,也就是一個音頻數據塊填滿了,通過消息機制就可以在消息函數中進行處理和播放,播放完后又可通過消息函數把緩沖區(qū)再送給音頻設備輸入驅動程序,繼續(xù)進行采集并播放。

  當一次性分配多個緩沖區(qū)和數據塊結構并賦給音頻設備輸入驅動程序后,至于把哪個緩沖區(qū)填滿,然后再把哪個空緩沖區(qū)賦給設備輸入驅動程序,不需人為干預,完全由Windows控制。在程序設計中可以使用兩個數據塊,交替進行,當正播放第一個緩沖區(qū),就用第二個緩沖區(qū)接收。

  //檢查語音輸入/輸出設備
  if(!waveInGetNumDevs())
  {
  return FALSE;
  }
  if(!waveOutGetNumDevs())
  {
  return FALSE;
  }
  //打開音頻設備之前,需要先設置音頻數據格式
  ……………
  //分配緩沖區(qū)所需要的內存
  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ū)
  //打開音頻設備
  result=waveOutOpen((LPHWAVEOUT)&hWaveOut,WAVE_MAPPER,(LPWAVEFORMATEX)&pcm.wf,(DWORD)hwnd,0L,  CALLBACK_WINDOW)

  2.3 語音壓縮模塊的實現

  VoIP帶寬比電路交換更窄的主要原因是對數據進行了壓縮處理。VoIP除了可使用最普通的編碼技術G.711外,還可以采用G.728, G.729, G.723.1等其它多種編碼方案。

  G.711有A律和μ律兩種形式。G.711通常被稱為PCM(脈沖編碼調制)。如果在編程中選擇PCM編碼方式。

  G.711提供了良好的語音質量,但是它的主要缺點是需要64Kbit/s的帶寬。所以在程序中靈活的選擇編碼方式是很重要的。

  ITU-T推薦的G.723.1標準可以同時支持兩種速率的編碼。一種是6.3kbit/s另一種是5.3kbit/s。所以,G.723.1在高速率下提供了好的通話質量,是一種好的編碼方案。在程序中的實現是通過對G.723.1軟件包中相應功能函數的調用來完成的,而且,在進行壓縮以前要將G.723.1的鏈接庫導入程序中。

  在需要進行壓縮時,要調用下面G.723.1的編碼和解碼函數:

  void Coder(FLOAT *DataBuff, char *Vout); //編碼
  void Decod(FLOAT *DataBuff, char *Vinp, short int Crc); //解碼

  2.4 RTP封裝

  因為語音傳輸對實時性要求非常高, 所以在程序中要采用基于UDP的RTP傳輸。UDP無法做到避免分組丟失和確保分組有序傳輸,運行在UDP上的RTP幫助實現了這些功能,RTP含有一個時間戳,可以利用這個時間戳來確保信息同步的傳輸給了目的用戶并計算出了時延和抖動。

  在程序中要對語音數據進行RTP格式封裝,使用了makertp()函數。而在解析是使用了isrtp()函數。

  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);

  在進行RTCP 格式的封裝時,使用了三個函數:

  rtcp_make_sdes();
  rtcp_make_sr();
  rtcp_make_rr()。

3 結論

  本文主要是利用VC++語言來實現PC-to-PC的軟件電話,它提供給Internet用戶在全球任何地方上網便可以呼叫對方的能力,提高了通信效率,是一種新的通信模式。

中國聯通網站



相關鏈接:
從VoIP起步——網絡設備廠商眼中的融合通信 2007-02-02
多個VOIP電話PA168芯片組會話劫持漏洞 2007-02-02
VoIP發(fā)展的新方向-IP PBX 2007-02-02
2006至2007年度VOIP行業(yè)發(fā)展分析 2007-02-01
解析:邊緣接入控制解決VoIP問題 2007-01-31

分類信息: