語音通信系統(tǒng)設計畢業(yè)論文.doc

語音通信系統(tǒng)設計畢業(yè)論文.doc

ID:213320

大?。?89.00 KB

頁數(shù):79頁

時間:2017-07-05

上傳者:U-255
語音通信系統(tǒng)設計畢業(yè)論文.doc_第1頁
語音通信系統(tǒng)設計畢業(yè)論文.doc_第2頁
語音通信系統(tǒng)設計畢業(yè)論文.doc_第3頁
語音通信系統(tǒng)設計畢業(yè)論文.doc_第4頁
語音通信系統(tǒng)設計畢業(yè)論文.doc_第5頁
資源描述:

《語音通信系統(tǒng)設計畢業(yè)論文.doc》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在學術(shù)論文-天天文庫。

鹽城工學院本科生畢業(yè)設計說明書(2010)語音通信系統(tǒng)設計畢業(yè)論文目錄1緒論11.1課題背景及意義11.2課題現(xiàn)狀11.3開發(fā)平臺、開發(fā)技術(shù)12系統(tǒng)需求分析及要求32.1語音通信系統(tǒng)需求分析32.2系統(tǒng)的功能要求32.3系統(tǒng)性能要求33系統(tǒng)整體設計44各模塊詳細設計74.1音頻編/解碼74.2音頻采集及回放134.3網(wǎng)絡的傳送和接收224.4界面設計355測試425.1模塊測試425.2功能測試42結(jié)論47致謝48附錄49程序核心代碼49 鹽城工學院本科生畢業(yè)設計說明書(2010)1緒論1.1課題背景及意義即時聊天工具是一種可以讓使用者在網(wǎng)絡上實時通訊的工具,大部分的即時通訊工具提供了狀態(tài)信息的特性,如顯示聯(lián)絡人名單,聯(lián)絡人是否在線及能否與聯(lián)絡人交談等。目前在互聯(lián)網(wǎng)上受歡迎的即時通訊軟件包括百度QQ、MSNMessenger、Yahoo!Messenger、AOLInstantMessenger、NETMessengerService、Jabber、ICQ等。在本設計中將討論一種基于MFCSocket的局域網(wǎng)通信工具的設計與實現(xiàn)方法?;赟ocket的局域網(wǎng)通信軟件可以為局域網(wǎng)提供一種良好、安全、快速的通信機制,在局域網(wǎng)內(nèi)部通信、教學、討論等應用中都具有一定的實用價值,它同時很好地詮釋了Socket通信的原理。基于Socket的局域網(wǎng)通信軟件應用范圍廣闊,不但可以處理傳統(tǒng)的通信需求,而且也能擴展以適應新型的網(wǎng)絡應用,如網(wǎng)絡教育,數(shù)據(jù)影音傳輸?shù)?,擁有廣泛的應用前景。1.2課題現(xiàn)狀基于局域網(wǎng)的即時通信工具,實際上是互聯(lián)網(wǎng)即時通信工具的一個小規(guī)模版本,廣域網(wǎng)上的即時通信工具,如今一般采用UDP或者TCP協(xié)議體系來實現(xiàn),開發(fā)技術(shù)已經(jīng)比較成熟,比如較早的ICQ、MSNMessenger、YAHOO通等國外開發(fā)的產(chǎn)品,還有國產(chǎn)的有名的QQ、新浪UC、LAVA-LAVA等,這些工具統(tǒng)統(tǒng)都實現(xiàn)了廣域網(wǎng)上的即時通信,盡管都是即時通信,實現(xiàn)了即時聊天,以及文件傳輸?shù)闹饕δ?,但是也各有各的特色,比如ICQ的巨大客戶群,MSN的個性化表情,YAHOO通的易操作性等,而QQ也具有一個相當方便的屏幕截圖功能,另外就是,所有上述軟件都實現(xiàn)了網(wǎng)絡即時的視頻,語音聊天功能。這些軟件,在使用方面各有特色,在實現(xiàn)方面也各有所長,但由于這些產(chǎn)品正在商業(yè)運營階段,其實現(xiàn)方式屬于商業(yè)機密,具體細節(jié)不可能得知,但是它在大的方面無非就是各種利用各種平臺上的網(wǎng)絡通信接口,建構(gòu)基于下層TCP/IP,或者UDP/IP協(xié)議的軟件產(chǎn)品。在局域網(wǎng)內(nèi),這些功能的實現(xiàn)跟廣域網(wǎng)相比更加簡單,因為局域網(wǎng)的網(wǎng)絡結(jié)構(gòu)本身比廣域網(wǎng)要簡單,但是可以借此理解網(wǎng)絡協(xié)議,以及網(wǎng)絡通信工具的實現(xiàn)原理,所以仍然極具研究價值。1.3開發(fā)平臺、開發(fā)技術(shù)1.3.1VC++6.0簡介我們通常所說的VisualC++實際上是一個完善的、非常強大的C++ 鹽城工學院本科生畢業(yè)設計說明書(2010)程序開發(fā)環(huán)境,它的名字是MicrosoftDeveloperStudio。二者之間的細小差別并不重要,通常這兩個術(shù)語可以互換。但如果你不圍繞DeveloperStudio來進行學習,就不能有效地使用VisualC++(DeveloperStudio聽起來很像VisualStudio,但它們之間沒有關(guān)系)。它包含:C++編譯器、調(diào)試器、應用程序框架生成器、項目管理器、設計和實現(xiàn)菜單等資源的編輯器等等。VisualC++是一個功能強大的可視化應用程序開發(fā)工具,用于Windows環(huán)境下32位的應用程序的開發(fā),是計算機界公認的最優(yōu)秀的應用開發(fā)工具之一。在提供可視化的編程方式的同時,VisualC++也適用于編寫直接對系統(tǒng)底層操作的程序,生成代碼的質(zhì)量也優(yōu)于其它的開發(fā)工具。在VisualC++環(huán)境下,利用Microsoft的基本類庫MFC(MicrosoftFoundationClassLibrary),可以使用完全的面向?qū)ο蟮姆椒▉磉M行Windows95/98/NT應用程序的開發(fā),使得Windows程序員從大量的復雜勞動中解救出來,體會到真正的程序語言的強大功能和良好的靈活性。VisualC++編程是一個面向?qū)ο蟮某绦蛟O計方法。同傳統(tǒng)的結(jié)構(gòu)化程序設計方法相比,它縮短軟件的研制時間,提高軟件的開發(fā)效率,使程序員可以更好地理解和管理龐大而復雜的程序。面向?qū)ο蟮某绦蛟O計吸取了結(jié)構(gòu)化程序設計的精華,它利用了人們根據(jù)對事物分類和抽象的傾向,引入了類和對象的概念,具有封裝性(數(shù)據(jù)抽象)、繼承和多態(tài)的特點。與結(jié)構(gòu)化程序設計不同的是,面向?qū)ο蟪绦蛟O計是用類抽象代表現(xiàn)實的實體,用類之間的繼承關(guān)系表示程序設計的抽象過程。函數(shù)只是對數(shù)據(jù)的操作,沒有數(shù)據(jù)的概念,而類是數(shù)據(jù)和數(shù)據(jù)操作的集合,由于面向?qū)ο蟮某绦蛟O計方法非常近現(xiàn)實,所以越來越流行。VisualC++中集成了大量的最新技術(shù),如ActiveX、COM等技術(shù),程序開發(fā)人員可以緊緊地把握住軟件開發(fā)技術(shù)發(fā)展的方向,開發(fā)出功能強大的應用程序。VisualC++還提供了豐富的技術(shù)資源,MSDN(MicrosoftDevelopNetwork)提供了強大的聯(lián)機幫助支持,同時還可以通過訪問Microsoft的網(wǎng)上站點來獲得最新的技術(shù)文檔。1.3.2WindowsSocket網(wǎng)絡編程WindowsSockets規(guī)范是以U.C.Berkeley大學BSDUNIX中流行的Socket接口為范例定義了一套開放的、支持多種協(xié)議的、MicrosoftWindows下的網(wǎng)絡編程接口,并不是一種網(wǎng)絡協(xié)議。它不僅包含了人們所熟悉的BerkeleySocket風格的庫函數(shù);也包含了一組針對Windows的擴展庫函數(shù),以使程序員能充分地利用Windows消息驅(qū)動機制進行編程。WindowsSockets規(guī)范本意在于提供給應用程序開發(fā)者一套簡單的API,使應用程序開發(fā)者能夠使用,并且網(wǎng)絡軟件供應商能夠?qū)崿F(xiàn)的一套庫函數(shù)調(diào)用和相關(guān)語義?,F(xiàn)在的WindowsSockets已經(jīng)基本上實現(xiàn)了與協(xié)議無關(guān),你可以使用 鹽城工學院本科生畢業(yè)設計說明書(2010)WindowsSockets來調(diào)用多種協(xié)議的功能,但較常使用的是TCP/IP協(xié)議。Socket實際在計算機中提供了一個通信端口,可以通過這個端口與任何一個具有Socket接口的計算機通信。應用程序在網(wǎng)絡上傳輸,接收的信息都通過這個Socket接口來實現(xiàn)。微軟為VC定義了WindowsSockets類如CAsyncSocket類和派生于CAsyncSocket的CSocket類,它們簡單易用。2系統(tǒng)需求分析及要求2.1語音通信系統(tǒng)需求分析隨著現(xiàn)代計算機技術(shù)的不斷發(fā)展,多媒體已經(jīng)成為現(xiàn)代計算機不可缺少的功能,而計算機的音頻,視頻功能是其中最為重要的部分。而隨著網(wǎng)絡的不斷發(fā)展,網(wǎng)絡已經(jīng)成為人們最重要的交流方式之一。計算機硬件的更新,非凡是海量存儲設備和大容量內(nèi)存在PC機上的實現(xiàn),對音頻媒體進行數(shù)字化處理早已經(jīng)成為可能?,F(xiàn)在,企業(yè)、機關(guān)、學校都建立起了局域網(wǎng)。雖然可以通過文件共享的方式進行通訊,但單使用這種方式,非常不方便。在網(wǎng)上鄰居里,只能看到機器名,不清楚對方是誰,也不知道對方機器里有什么資源可以共享,尤其當局域網(wǎng)的機器很多時,這種方式就更加麻煩了。而文字聊天方式比較單一缺乏真實感,所以語音通信就有了必要。但是語音傳輸需要有很大的網(wǎng)絡帶寬,對于撥號上網(wǎng)用戶,語音傳輸仍然是奢侈品,不過對于局域網(wǎng)和寬帶用戶來說,是很不錯的選擇,本系統(tǒng)就是研究的基于局域網(wǎng)的語音傳輸,并以語音聊天為例給出了實例。語音聊天方式一般有兩種,一種是專門的語音聊天室,采用Web方式,B/S結(jié)構(gòu),另外一中則是類似于QQ、MSN等聊天工具,采用C/S結(jié)構(gòu)。本設計是采用的后者。TCP/IP網(wǎng)絡中兩個進程間的相互作用的主機模式是客戶機/服務器模式。該模式的建立基于以下兩點:1、非對等作用;2、通信完全是異步的。客戶機/服務器模式在操作過程中采取的是主動請示方式,首先服務器方要先啟動,并根據(jù)請示提供相應服務。綜上所述,做一個語音通信軟件是有必要的,也是能夠?qū)崿F(xiàn)的。2.2系統(tǒng)的功能要求在線朋友指的是在所有使用本系統(tǒng)在局域網(wǎng)上進行信息傳遞的用戶。局域網(wǎng)中在線用戶之間的語音聊天就是指在線雙方互相傳遞語音信息的功能。1)在聊天窗口為基礎,建立與服務器端的連接。2)與對方連接以后開始語音聊天。3)想結(jié)束語音聊天時,按結(jié)束鍵就能與對方斷開連接,即結(jié)束語音聊天。 鹽城工學院本科生畢業(yè)設計說明書(2010)2.3系統(tǒng)性能要求1)時間性能要求:在實際應用中由于客戶端的大量頻繁的訪問,服務器響應時間應該盡可能縮短,對于有特殊需求的應用,還要求達到實時響應。2)存儲性能要求:根據(jù)應用中的實際情況配置適當容量的存儲設備,特別是音頻存儲設備容量方面要適當?shù)门渲谩?)穩(wěn)定性安全性要求:要求軟件盡可能的穩(wěn)定,對于一般的應用系統(tǒng),對安全性要求不高,對于特殊的應用,還需要在安全性方面加以保證,所以要相應提高服務器端的配置。3系統(tǒng)整體設計要實現(xiàn)點對點語音通信,原理非常簡單,只要針對一個點實現(xiàn)話音的實時采集、處理、播放,同時能進行可靠的傳送和接收,這樣兩點一連便可通話。對于前者,采用Windows的低層音頻服務比較合適,因為低層音頻服務中的回調(diào)機制為我們提供了很大的方便。當應用程序不斷向設備驅(qū)動程序提供音頻數(shù)據(jù)時,設備驅(qū)動程序控制音頻設備在后臺完成錄音和放音的具體操作,通過回調(diào)機制,我們又可以檢測到什么時候用完一個數(shù)據(jù)塊,并及時傳送下一個數(shù)據(jù)塊,從而保證了聲音的連續(xù),有了這種實時采集、回放功能后,接下來的工作就是在網(wǎng)絡上傳送話音數(shù)據(jù)。在點對點網(wǎng)絡傳輸方面,選擇面向連接的TCP/IP協(xié)議,TCP/IP傳輸協(xié)議自動處理分組丟失和交付失序問題,這樣我們不用為這些問題操心,只需很好地利用這個連接,在采集話音回放之前一方面將自己的話音傳給網(wǎng)絡,另一方面接收網(wǎng)絡傳來的話音,這樣便實現(xiàn)了點對點語音通信。其模塊框圖如圖3-1所示,總體結(jié)構(gòu)圖為圖3-2所示。語音通信系統(tǒng)音頻采集音頻回放網(wǎng)絡傳輸音頻編/解碼圖3-1模塊框圖 鹽城工學院本科生畢業(yè)設計說明書(2010)圖3-2總體結(jié)構(gòu)圖一個完整的音頻通信系統(tǒng)程序要完成以下工作:發(fā)送端完成音頻采集、壓縮編碼、碼流發(fā)送等;接收端則要完成碼流接收、解碼恢復、音頻回放等。其總體程序流程圖如圖3-3所示。 鹽城工學院本科生畢業(yè)設計說明書(2010)程序開始啟動音頻輸入/輸出呼叫對方連接成功連接失敗壓縮編碼音頻輸出音頻輸入Socket發(fā)送網(wǎng)絡Socket接收程序退出圖3-3總體程序流程 鹽城工學院本科生畢業(yè)設計說明書(2010)4各模塊詳細設計4.1音頻編/解碼4.1.1音頻編/解碼介紹  自然界中的聲音非常復雜,波形極其復雜,通常我們采用的是脈沖代碼調(diào)制編碼,即PCM編碼。PCM通過抽樣、量化、編碼三個步驟將連續(xù)變化的模擬信號轉(zhuǎn)換為數(shù)字編碼。  1)采樣率和采樣大?。ㄎ?bit)?! ÷曇羝鋵嵤且环N能量波,因此也有頻率和振幅的特征,頻率對應于時間軸線,振幅對應于電平軸線。波是無限光滑的,弦線可以看成由無數(shù)點組成,由于存儲空間是相對有限的,數(shù)字編碼過程中,必須對弦線的點進行采樣。采樣的過程就是抽取某點的頻率值,很顯然,在一秒中內(nèi)抽取的點越多,獲取得頻率信息更豐富,為了復原波形,一次振動中,必須有2個點的采樣,人耳能夠感覺到的最高頻率為20kHz,因此要滿足人耳的聽覺要求,則需要至少每秒進行40k次采樣,用40kHz表達,這個40kHz就是采樣率。我們常見的CD,采樣率為44.1kHz。光有頻率信息是不夠的,我們還必須獲得該頻率的能量值并量化,用于表示信號強度。量化電平數(shù)為2的整數(shù)次冪,我們常見的CD位16bit的采樣大小,即2的16次方。采樣大小相對采樣率更難理解,因為要顯得抽象點,舉個簡單例子:假設對一個波進行8次采樣,采樣點分別對應的能量值分別為A1-A8,但我們只使用2bit的采樣大小,結(jié)果我們只能保留A1-A8中4個點的值而舍棄另外4個。如果我們進行3bit的采樣大小,則剛好記錄下8個點的所有信息。采樣率和采樣大小的值越大,記錄的波形更接近原始信號?! ?)有損和無損  根據(jù)采樣率和采樣大小可以得知,相對自然界的信號,音頻編碼最多只能做到無限接近,至少目前的技術(shù)只能這樣了,相對自然界的信號,任何數(shù)字音頻編碼方案都是有損的,因為無法完全還原。在計算機應用中,能夠達到最高保真水平的就是PCM編碼,被廣泛用于素材保存及音樂欣賞,CD、DVD以及我們常見的WAV文件中均有應用。因此,PCM約定俗成了無損編碼,因為PCM代表了數(shù)字音頻中最佳的保真水準,并不意味著PCM就能夠確保信號絕對保真,PCM也只能做到最大程度的無限接近。我們而習慣性的把MP3列入有損音頻編碼范疇,是相對PCM編碼的。強調(diào)編碼的相對性的有損和無損,是為了告訴大家,要做到真正的無損是困難的,就像用數(shù)字去表達圓周率,不管精度多高,也只是無限接近,而不是真正等于圓周率的值?! ?)音頻壓縮技術(shù)  要算一個PCM音頻流的碼率是一件很輕松的事情,采樣率值×采樣大小值×聲道數(shù) 鹽城工學院本科生畢業(yè)設計說明書(2010)bps。一個采樣率為44.1KHz,采樣大小為16bit,雙聲道的PCM編碼的WAV文件,它的數(shù)據(jù)速率則為44.1K×16×2=1411.2Kbps。我們常說128K的MP3,對應的WAV的參數(shù),就是這個1411.2Kbps,這個參數(shù)也被稱為數(shù)據(jù)帶寬,它和ADSL中的帶寬是一個概念。將碼率除以8,就可以得到這個WAV的數(shù)據(jù)速率,即176.4KB/s。這表示存儲一秒鐘采樣率為44.1KHz,采樣大小為16bit,雙聲道的PCM編碼的音頻信號,需要176.4KB的空間,1分鐘則約為10.34M,這對大部分用戶是不可接受的,尤其是喜歡在電腦上聽音樂的朋友,要降低磁盤占用,只有2種方法,降低采樣指標或者壓縮。降低指標是不可取的,因此專家們研發(fā)了各種壓縮方案。4)頻率與采樣率  采樣率表示了每秒對原始信號采樣的次數(shù),我們常見到的音頻文件采樣率多為44.1KHz,這意味著什么呢?假設我們有2段正弦波信號,分別為20Hz和20KHz,長度均為一秒鐘,以對應我們能聽到的最低頻和最高頻,分別對這兩段信號進行40KHz的采樣,我們可以得到一個什么樣的結(jié)果呢?結(jié)果是:20Hz的信號每次振動被采樣了40K/20=2000次,而20K的信號每次振動只有2次采樣。顯然,在相同的采樣率下,記錄低頻的信息遠比高頻的詳細。這也是為什么有些音響發(fā)燒友指責CD有數(shù)碼聲不夠真實的原因,CD的44.1KHz采樣也無法保證高頻信號被較好記錄。要較好的記錄高頻信號,看來需要更高的采樣率,于是有些朋友在捕捉CD音軌的時候使用48KHz的采樣率,這是不可取的!這其實對音質(zhì)沒有任何好處,對抓軌軟件來說,保持和CD提供的44.1KHz一樣的采樣率才是最佳音質(zhì)的保證之一,而不是去提高它。較高的采樣率只有相對模擬信號的時候才有用,如果被采樣的信號是數(shù)字的,請不要去嘗試提高采樣率?! ?)流特征隨著網(wǎng)絡的發(fā)展,人們對在線收聽音樂提出了要求,因此也要求音頻文件能夠一邊讀一邊播放,而不需要把這個文件全部讀出后然后回放,這樣就可以做到不用下載就可以實現(xiàn)收聽了。也可以做到一邊編碼一邊播放,正是這種特征,可以實現(xiàn)在線的直播,架設自己的數(shù)字廣播電臺成為了現(xiàn)實。4.1.2PCM編碼和WAVE音頻格式 1)PCM編碼  PCM脈沖編碼調(diào)制是PulseCodeModulation的縮寫。前面的文字我們提到了PCM大致的工作流程,我們不需要關(guān)心PCM最終編碼采用的是什么計算方式,我們只需要知道PCM編碼的音頻流的優(yōu)點和缺點就可以了。PCM編碼的最大的優(yōu)點就是音質(zhì)好,最大的缺點就是體積大。我們常見的AudioCD就采用了PCM編碼。  2)WAVE  這是一種經(jīng)典的音頻文件格式,由微軟開發(fā)。WAV是一種文件格式,符合PIFFResourceInterchangeFile 鹽城工學院本科生畢業(yè)設計說明書(2010)Format規(guī)范。所有的WAV都有一個文件頭,這個文件頭音頻流的編碼參數(shù)。WAV對音頻流的編碼沒有硬性規(guī)定,除了PCM之外,還有幾乎所有支持ACM規(guī)范的編碼都可以為WAV的音頻流進行編碼。很多朋友沒有這個概念,我們拿AVI做個示范,因為AVI和WAV在文件結(jié)構(gòu)上是非常相似的,不過AVI多了一個視頻流而已。我們接觸到的AVI有很多種,因此我們經(jīng)常需要安裝一些Decode才能觀看一些AVI,我們接觸到比較多的DivX就是一種視頻編碼,AVI可以采用DivX編碼來壓縮視頻流,當然也可以使用其他的編碼壓縮。同樣,WAV也可以使用多種音頻編碼來壓縮其音頻流,不過我們常見的都是音頻流被PCM編碼處理的WAV,但這不表示W(wǎng)AV只能使用PCM編碼,MP3編碼同樣也可以運用在WAV中,和AVI一樣,只要安裝好了相應的Decode,就可以欣賞這些WAV了。在Windows平臺下,基于PCM編碼的WAV是被支持得最好的音頻格式,所有音頻軟件都能完美支持,由于本身可以達到較高的音質(zhì)的要求,因此,WAV也是音樂編輯創(chuàng)作的首選格式,適合保存音樂素材。因此,基于PCM編碼的WAV被作為了一種中介的格式,常常使用在其他編碼的相互轉(zhuǎn)換之中,例如MP3轉(zhuǎn)換成WMA。3)PCM編碼的WAV  PCM編碼的WAV文件是音質(zhì)最好的格式,Windows平臺下,所有音頻軟件都能夠提供對它的支持。Windows提供的WinAPI中有不少函數(shù)可以直接播放wav,因此,在開發(fā)多媒體軟件時,往往大量采用wav,用作事件聲效和背景音樂。PCM編碼的wav可以達到相同采樣率和采樣大小條件下的最好音質(zhì),因此,也被大量用于音頻編輯、非線性編輯等領域。其特點是音質(zhì)非常好,被大量軟件所支持。適用于多媒體開發(fā)、保存音樂和音效素材。所以本設計選用WAV格式的音頻進行錄制和播放4.1.3G729編/解碼本設計使用G729編解碼標準對音頻進行音頻編解碼,在VisualC++環(huán)境中直接調(diào)用G729庫來對音頻數(shù)據(jù)進行處理。4.1.3.1G729編/解碼標準20世紀80年代末,為滿足長途通信的需求,ITU制訂8kbps的高質(zhì)量低延時的語音編碼標準。1)技術(shù)指標:采樣率8kHz、碼率8kbps。2)技術(shù)特點:采用代數(shù)碼本,碼書簡單、無需存儲,恢復音質(zhì)清晰;分析窗采用混合窗,LSP參數(shù)采用兩級矢量量化;基音分析采用開環(huán)基音分析和自適應碼本搜索結(jié)合,低運算復雜度、高精度;采用10ms分析幀,編碼時延小。3)應用狀況:被廣泛應用于IP電話、視訊電話、視訊會議系統(tǒng)等。4)技術(shù)框架:如圖4-1所示。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖4-1G729編/解碼技術(shù)框架4.1.3.2G729編/解碼C++實現(xiàn)核心代碼//音頻解碼#pragmacomment(lib,"G729a")//構(gòu)造函數(shù)CAudioCode::CAudioCode(){va_g729a_init_encoder();//初始化編碼器va_g729a_init_decoder();//初始化解碼器}//析構(gòu)函數(shù)CAudioCode::~CAudioCode(){}//編碼音頻數(shù)據(jù)BOOLCAudioCode::EncodeAudioData(char*pin,intlen,char*pout,int*lenr){//編碼成功與否標記BOOLbRet=FALSE;//無效輸入或輸出if(!pin||len!=SIZE_AUDIO_FRAME||!pout)gotoRET;//分塊進行編碼 鹽城工學院本科生畢業(yè)設計說明書(2010)va_g729a_encoder((short*)pin,(BYTE*)pout);va_g729a_encoder((short*)(pin+160),(BYTE*)pout+10);va_g729a_encoder((short*)(pin+320),(BYTE*)pout+20);va_g729a_encoder((short*)(pin+480),(BYTE*)pout+30);va_g729a_encoder((short*)(pin+640),(BYTE*)pout+40);va_g729a_encoder((short*)(pin+800),(BYTE*)pout+50);//編碼長度if(lenr)*lenr=SIZE_AUDIO_PACKED;//編碼成功標記bRet=TRUE;RET://返回returnbRet;}//音頻解碼BOOLCAudioCode::DecodeAudioData(char*pin,intlen,char*pout,int*lenr){//解碼成功與否標記BOOLbRet=FALSE;//無效輸入或輸出if(!pin||len!=SIZE_AUDIO_PACKED||!pout)gotoRET;//分塊解碼va_g729a_decoder((BYTE*)pin,(short*)(pout),0);va_g729a_decoder((BYTE*)pin+10,(short*)(pout+160),0);va_g729a_decoder((BYTE*)pin+20,(short*)(pout+320),0);va_g729a_decoder((BYTE*)pin+30,(short*)(pout+480),0);va_g729a_decoder((BYTE*)pin+40,(short*)(pout+640),0);va_g729a_decoder((BYTE*)pin+50,(short*)(pout+800),0);//解碼長度if(lenr)*lenr=SIZE_AUDIO_FRAME;//設置解碼成功標記bRet=TRUE;RET: 鹽城工學院本科生畢業(yè)設計說明書(2010)returnbRet;}4.2音頻采集及回放本設計采用基于WaveX低級音頻API采集音頻及實時播放的技術(shù)。利用雙/多緩沖技術(shù)和網(wǎng)絡擁塞控制策略可很好的控制音頻的實時性和連續(xù)性。雙/多緩沖技術(shù)可以很好的實現(xiàn)聲音的快速連續(xù)采集和實時順暢播放。4.2.1方案選擇音頻的采集WINDOWS下音頻的采集,播放有三種模式:1)通過高級音頻函數(shù)、媒體控制接口MCI[1、2]設備驅(qū)動程序;2)低級音頻函數(shù)MIDIMapper、低級音頻設備驅(qū)動(WaveXAPI);3)利用DirectX中的DirectSound?! ∈褂肕CI的方法極其簡便,靈活性較差,因此較難推廣;使用低級音頻函數(shù)的方法相對來說難一點,但是能夠?qū)σ纛l數(shù)據(jù)進行靈活的操控;而采用DirectSound的方法,控制聲音數(shù)據(jù)靈活,效果比前二者都好,但實現(xiàn)起來是三者中最難的。其三者的關(guān)系如圖4-2所示。圖4-2三者關(guān)系低層音頻服務及重要的數(shù)據(jù)結(jié)構(gòu)低級音頻服務控制著不同的音頻設備,這些設備包括WAVE,MIDI和輔助音頻設備。 鹽城工學院本科生畢業(yè)設計說明書(2010)如果想編寫一個功能較強大的音頻處理程序,那就必須使用低級音頻函數(shù)和多媒體文件I/O來控制音頻設備的輸入和輸出。因為低級音頻函數(shù)可直接與音頻驅(qū)動程序交互,通過窗口消息或回調(diào)(CALLBACK)函數(shù)來管理音頻數(shù)據(jù)塊的記錄和播放,控制非常靈活。重要的一點是,低級音頻函數(shù)為我們提供了一個設備無關(guān)的接口。低層音頻服務及重要的數(shù)據(jù)結(jié)構(gòu)低級音頻服務控制著不同的音頻設備,這些設備包括WAVE,MIDI和輔助音頻設備。低級音頻服務包括如下內(nèi)容:1)查詢音頻設備;  2)打開和關(guān)閉設備驅(qū)動程序;  3)分配和準備音頻數(shù)據(jù)塊;  4)管理音頻數(shù)據(jù)塊;  5)應用MMTIME結(jié)構(gòu);6)處理錯誤。4.2.2相關(guān)數(shù)據(jù)結(jié)構(gòu)1)WaveX低級音頻函數(shù)的相關(guān)聲明和定義在mmsystem.h頭文件和Winmm.lib庫中。所以如果程序中用到這些函數(shù),必須包含mmsystem.h這個頭文件,同時導進Winmm.lib庫。如下:#include"mmsystem.h"#pragmacomment(lib,"Winmm.lib")2)聲音在采集和播放的時需要有一些統(tǒng)一的格式,包括音頻格式類型,聲道,采樣率等信息。下面的數(shù)據(jù)結(jié)構(gòu)具體描述了該格式:wFormatTag是音頻格式類型,nChannels是聲道數(shù),nSamplesPerSec是采樣頻率,nAvgBytesPerSec是每秒鐘的字節(jié)數(shù),nBlockAlign是每個樣本的字節(jié)數(shù),wBitsPerSample是每個樣本的量化位數(shù),cbSize是附加信息的字節(jié)大小。3)音頻數(shù)據(jù)塊有一個頭結(jié)構(gòu),這個結(jié)構(gòu)包含了音頻數(shù)據(jù)緩沖的地址,大小,已錄音數(shù)據(jù)大小等信息和其他各種控制標志。這個結(jié)構(gòu)適用于音頻的輸入(錄音)和輸出(播放)緩沖中。詳細信息包括:lpData是指定的緩沖塊地址,dwBufferLength是指定的緩沖塊大小,dwBytesRecorded是已錄音數(shù)據(jù)大小,dwUser是用戶數(shù)據(jù),dwFlags是控制標志,表明緩沖的使用狀態(tài),dwLoops是音頻輸出時緩沖數(shù)據(jù)塊循環(huán)的次數(shù),lpNext和reserved是系統(tǒng)保留數(shù)據(jù)。在程序?qū)崿F(xiàn)時,通過設置或修改這個結(jié)構(gòu)的相關(guān)參數(shù)來實現(xiàn)對音頻輸入和輸出緩沖區(qū)的控制。4.2.3音頻采集4.2.3.1音頻采集原理電腦依靠聲卡來處理聲音,Windows 鹽城工學院本科生畢業(yè)設計說明書(2010)把聲卡看作是錄音和放音設備的組合體,錄音時首先要準備一個錄音隊列,隊列中包含錄音的基本參數(shù),比如錄音數(shù)據(jù)緩沖區(qū)的地址、緩沖區(qū)的大小等,為了使錄音過程平滑的進行,隊列中至少包含兩個以上數(shù)據(jù)緩沖區(qū),當一個緩沖區(qū)錄完后,Windows系統(tǒng)會給應用程序發(fā)送一個錄音結(jié)束的消息,并自動開始轉(zhuǎn)入下一個緩沖區(qū)進行錄音,應用程序收到該消息后應該釋放含有錄音數(shù)據(jù)的隊列,并取出該隊列所指向的緩沖區(qū)的聲音數(shù)據(jù),然后將該緩沖區(qū)再次加入錄音隊列,以便繼續(xù)進行錄音。Windows就是這樣利用這些數(shù)據(jù)緩沖區(qū)進行周而復始的錄入工作。采集聲音時,緩沖滿了會有一個消息,程序在響應這個消息需要幾毫秒~幾十毫秒甚至更多的時間,假設為Xms,如果只使用一個緩沖,程序必須在響應完該消息才再次采集聲音,那么在這Xms的時間里,沒有采集到任何聲音;聲音的播放也是一樣的道理,這樣聲音就會不連續(xù)。因此雙緩沖或多緩沖技術(shù)是必要的,讓輸入和輸出設備可以循環(huán)使用這些緩沖,當程序在響應某塊緩沖數(shù)據(jù)已滿或播放完畢消息時,聲卡可以繼續(xù)往下一塊緩沖添加數(shù)據(jù)或播放下一塊緩沖的數(shù)據(jù),如此循環(huán)保障聲音的連續(xù)性。其基本原理圖如圖4-3所示。圖4-3音頻采集原理圖4.2.3.2音頻采集具體流程在使用音頻設備之前,必須打開設備驅(qū)動程序。為可靠起見,在播放和記錄音頻之前,要確定系統(tǒng)音頻設備的能力。在用完之后必須關(guān)閉音頻設備。音頻采集流程圖如圖4-4所示。具體流程如下:1)查詢設備數(shù)目和能力因為計算機的硬件和性能各不相同,所以在音頻采集前,首先要檢測有無音頻錄制設備。通過使用waveOutGetNumDevs和waveOutGetDevCaps來獲取波形輸出設備的個數(shù)和能力。只有在確定設備存在之后,才可以打開設備、使用設備。2)打開波形輸出設備在使用錄入設備前,必須打開音頻錄入設備。這里可以調(diào)用waveOutOpen為進行重放操作打開特定的波形設備。該函數(shù)打開與指定的設備ID相關(guān)聯(lián)的設備,并以給出指定內(nèi)存句柄的方法返回打開波形設備的句柄。 鹽城工學院本科生畢業(yè)設計說明書(2010)當有多種波形輸出設備時,建議使用WAVE_MAPPER常數(shù)作為設備ID,這使waveOutOpen函數(shù)會自動挑選最適合播放給定的數(shù)據(jù)格式的設備。3)準備音頻數(shù)據(jù)塊在錄制時音頻錄入會產(chǎn)生大量的數(shù)據(jù),所以我們要為這些數(shù)據(jù)分配緩沖區(qū)。在波形重放之前,要準備好音頻數(shù)據(jù)塊。將數(shù)據(jù)塊傳遞給設備驅(qū)動程序就實現(xiàn)了重放。使用的函數(shù)是waveOutPerpareHeader。4)開始錄制經(jīng)過以上步驟后,一切準備就緒,調(diào)用WaveInStart就可以開始錄制。當一個緩沖區(qū)使用完后音頻驅(qū)動程序就調(diào)用上述在打開錄入設備時指定的回調(diào)函數(shù)。在用完數(shù)據(jù)塊之后,必須用waveOutUnPrepareHeader函數(shù)來清除對波形數(shù)據(jù)塊的準備。再將數(shù)據(jù)讀出,然后再把該緩沖區(qū)添加給驅(qū)動程序。圖4-4音頻采集流程圖4.2.3.3音頻采集核心代碼//WaveIn.CPPclassCWaveIn{public://線程處理 鹽城工學院本科生畢業(yè)設計說明書(2010)staticDWORDWINAPIAudioInThreadProc(LPVOIDlpParameter);public://獲取數(shù)據(jù)virtualvoidGetData(char*pBuffer,intiLen);//啟動錄音BOOLStartRec();//停止錄音BOOLStopRec();//獲取實例inlineDWORDGetInstance();//獲取采樣位數(shù)inlineWORDGetBit();//獲取采樣速率inlineDWORDGetSample();//獲取頻道數(shù)inlineWORDGetChannel();//設置采樣位數(shù)inlinevoidSetBit(WORDwBit);//設置采樣速率inlinevoidSetSample(DWORDdwSample);//設置采樣速率inlinevoidSetChannel(WORDwChannel);//獲取錯誤信息inlineMMRESULTGetLastMMError();CStringGetLastErrorString();//構(gòu)造函數(shù)CWaveIn();//析構(gòu)函數(shù)virtual~CWaveIn();protected://打開設備BOOLOpenDev();//關(guān)閉設備BOOLCloseDev();//停止線程BOOLStopThread();//啟動線程 鹽城工學院本科生畢業(yè)設計說明書(2010)BOOLStartThread();//準備緩存BOOLPerPareBuffer();//釋放緩存BOOLFreeBuffer();//開始錄音BOOLOpenRecord();//結(jié)束錄音BOOLCloseRecord();protected://用戶實例數(shù)據(jù)staticDWORDs_dwInstance;protected://頻道數(shù)WORDm_wChannel;//采樣速率DWORDm_dwSample;//采樣位數(shù)WORDm_wBit;protected://音頻輸入設備句柄HWAVEINm_hIn;//函數(shù)調(diào)用返回信息MMRESULTm_mmr;//回調(diào)函數(shù)指針DWORDm_dwAudioInId;//線程句柄HANDLEm_hAudioIn;//WAVEHDR結(jié)構(gòu)緩存指針WAVEHDR*m_pHdr;//線程啟動標志BOOLm_bThreadStart;//設備打開標記BOOLm_bDevOpen;//內(nèi)存分配標記BOOLm_bAllocBuffer;//錄音開始標記 鹽城工學院本科生畢業(yè)設計說明書(2010)BOOLm_bRecord;};4.2.4音頻回放4.2.4.1音頻回放原理經(jīng)過處理過的語音數(shù)據(jù)通過音頻處理傳送到這個模塊,當接收到語音數(shù)據(jù)以后它將經(jīng)過錄音的語音數(shù)據(jù)進行放音,然后把內(nèi)存釋放出來以備保存其他緩沖區(qū)里保存的聲源信息。由于聲音數(shù)據(jù)具有很強的前后相關(guān)性,數(shù)據(jù)量大、實時性強,又由于聲音是連續(xù)的,通常把其稱之為連續(xù)型時基媒體類型,因此需要釋放內(nèi)存。當緩沖區(qū)接收到聲源以后要是內(nèi)存不夠的話就不能及時把全部語音數(shù)據(jù)保存并傳送,所以經(jīng)過這個模塊以后就得把錄音內(nèi)存釋放掉,好讓上一個模塊及時得到完成。其基本原理圖如圖4-5所示。圖4-5音頻回放原理圖4.2.4.2音頻回放具體流程緩沖區(qū)中數(shù)據(jù)播放完成后系統(tǒng)會向應用程序發(fā)送放音完成的消息,應用程序可以重復前面的工作,先釋放完成的隊列,然后向緩沖區(qū)加入新的聲音數(shù)據(jù),并再次將該緩沖區(qū)加入放音隊列,讓該隊列繼續(xù)工作。音頻回放流程圖如圖4-6所示。具體流程如下:1)管理波形重放在使用低級音頻函數(shù)播放音頻時,應用程序必須不斷地向設備驅(qū)動程序提供數(shù)據(jù)塊,直到播放結(jié)束。WINDOWS提供兩種方法管理波形重放:一是使用窗口消息管理,二是使用低級回調(diào)函數(shù)管理。另外,通過使用waveOutPause、waveOutRestart和waveOutReset來進行暫停、重新啟動和停止播放。2)關(guān)閉波形設備用完設備之后,必須調(diào)用waveOutClose函數(shù)關(guān)閉波形輸出設備,以便其他程序可以使用設備。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖4-6音頻回放流程圖4.2.4.3音頻回放核心代碼classCWaveOut{public://線程處理staticDWORDWINAPIAudioOutThreadProc(LPVOIDlpParameter);public://根據(jù)文件設置格式BOOLSetFormatByFile(CStringfile);//播音BOOLPlay(char*buf,UINTuSize);//開始播音BOOLStartPlay();//停止播音BOOLStopPlay();//獲取緩存數(shù)目inlineintGetBufferNum();//減少緩存數(shù)目inlinevoidBufferSub();//增加緩存數(shù)目inlinevoidBufferAdd(); 鹽城工學院本科生畢業(yè)設計說明書(2010)//獲取實例inlineDWORDGetInstance();//獲取采樣位數(shù)inlineWORDGetBit();//獲取采樣速率inlineDWORDGetSample();//獲取頻道數(shù)inlineWORDGetChannel();//設置采樣位數(shù)inlinevoidSetBit(WORDwBit);//設置采樣速率inlinevoidSetSample(DWORDdwSample);//設置頻道數(shù)inlinevoidSetChannel(WORDwChannel);//獲取錯誤信息inlineMMRESULTGetLastMMError();CStringGetLastErrorString();//構(gòu)造函數(shù)CWaveOut();//析構(gòu)函數(shù)virtual~CWaveOut();protected://打開設備BOOLOpenDev();//關(guān)閉設備BOOLCloseDev();//停止線程BOOLStopThread();//啟動線程BOOLStartThread();protected://用戶實例數(shù)據(jù)staticDWORDs_dwInstance;protected://頻道數(shù)WORDm_wChannel;//采樣速率 鹽城工學院本科生畢業(yè)設計說明書(2010)DWORDm_dwSample;//采樣位數(shù)WORDm_wBit;protected://函數(shù)調(diào)用返回信息MMRESULTm_mmr;//播音設備句柄HWAVEOUTm_hOut;//線程句柄HANDLEm_hAudioOut;//回調(diào)函數(shù)指針DWORDm_dwAudioOutId;//緩存數(shù)目intm_iBufferNum;//重要部分(criticalsection)CCriticalSectionm_csLock;//線程啟動標志BOOLm_bThreadStart;//播音設備打開標志BOOLm_bDevOpen;//線程處理friendDWORDWINAPIAudioOutThreadProc(LPVOIDlpParameter);};4.3網(wǎng)絡的傳送和接收網(wǎng)絡的傳輸和接收部分是本設計最重要的模塊,對于主機1傳送到主機2的音頻數(shù)據(jù)信息這條數(shù)據(jù)通路,主機1為客戶端,主機2為服務端;而對于主機2傳送到主機1的音頻數(shù)據(jù)信息這條數(shù)據(jù)通路,主機2為客戶端,主機1為服務器端。雙方通話時,主機1和主機2同時既處于服務器狀態(tài)又處于客戶端狀態(tài),即通話狀態(tài)。主機1呼叫主機2時,主機1進入客戶端狀態(tài),主機2收到呼叫信息,進入服務器端狀態(tài),若主機2同意通話,則兩機都進入通話狀態(tài),雙方可以通過上述兩條數(shù)據(jù)通路進行網(wǎng)絡通話,若有一機掛斷,兩機都返回偵聽狀態(tài),等待呼叫或被呼叫。4.3.1TCP/IP體系結(jié)構(gòu)與特點4.3.1.1TCP/IP體系結(jié)構(gòu)TCP/IP協(xié)議實際上就是在物理網(wǎng)上的一組完整的網(wǎng)絡協(xié)議。其中TCP是提供傳輸層服務,而IP則是提供網(wǎng)絡層服務。TCP/IP包括以下協(xié)議:結(jié)構(gòu)圖如圖4-7 鹽城工學院本科生畢業(yè)設計說明書(2010)圖4-7TCP/IP結(jié)構(gòu)圖IP:網(wǎng)間協(xié)議(InternetProtocol)負責主機間數(shù)據(jù)的路由和網(wǎng)絡上數(shù)據(jù)的存儲。同時為ICMP、TCP、UDP提供分組發(fā)送服務。用戶進程通常不需要涉及這一層。ARP:地址解析協(xié)議(AddressResolutionProtocol)此協(xié)議將網(wǎng)絡地址映射到硬件地址。RARP:反向地址解析協(xié)議(ReverseAddressResolutionProtocol)此協(xié)議將硬件地址映射到網(wǎng)絡地址。ICMP:網(wǎng)間報文控制協(xié)議(InternetControlMessageProtocol),此協(xié)議處理信關(guān)和主機的差錯和傳送控制。TCP:傳送控制協(xié)議(TransmissionControlProtocol),這是一種提供給用戶進程的可靠的全雙工字節(jié)流面向連接的協(xié)議,它要為用戶進程提供虛電路服務,并為數(shù)據(jù)可靠傳輸建立檢查。(大多數(shù)網(wǎng)絡用戶程序使用TCP)UDP:用戶數(shù)據(jù)報協(xié)議(UserDatagramProtocol),這是提供給用戶進程的無連接協(xié)議,用于傳送數(shù)據(jù)而不執(zhí)行正確性檢查。FTP:文件傳輸協(xié)議(FileTransferProtocol),允許用戶以文件操作的方式(文件的增、刪、改、查、傳送等)與另一主機相互通信。SMTP:簡單郵件傳送協(xié)議(SimpleMailTransferProtocol),SMTP協(xié)議為系統(tǒng)之間傳送電子郵件。TELNET:終端協(xié)議(TelnetTerminalProcotol),允許用戶以虛終端方式訪問遠程主機。HTTP:超文本傳輸協(xié)議(HypertextTransferProcotol),TFTP:簡單文件傳輸協(xié)議(TrivialFileTransferProtocol)。4.3.1.2TCP/IP特點 鹽城工學院本科生畢業(yè)設計說明書(2010)TCP/IP協(xié)議的核心部分是傳輸層協(xié)議(TCP、UDP),網(wǎng)絡層協(xié)議(IP)和物理接口層,這三層通常是在操作系統(tǒng)內(nèi)核中實現(xiàn)。因此用戶一般不涉及。編程時,編程界面有兩種形式:一、是由內(nèi)核心直接提供的系統(tǒng)調(diào)用;二、使用以庫函數(shù)方式提供的各種函數(shù)。前者為核內(nèi)實現(xiàn),后者為核外實現(xiàn)。用戶服務要通過核外的應用程序才能實現(xiàn),所以要使用套接字(socket)來實現(xiàn)。Socket與TCP/IPc協(xié)議的關(guān)系如圖4-8圖4-8Socket與TCP/IPc協(xié)議4.3.1.3WindowsSocketVC++對網(wǎng)絡編程的支持有socket支持,Winlnet支持,MAPI和ISAPI支持等。其中WindowsSocketsAPI是TCP/IP網(wǎng)絡環(huán)境里,也是Internet上進行開發(fā)最為通用的API。最早美國加州大學Berkeley分校在UNIX下為TCP/IP協(xié)議開發(fā)了一個API,這個API就是著名的BerkeleySocket接口(套接字)。在桌面操作系統(tǒng)進入Windows時代后,仍然繼承了Socket方法。從表4-1中可以看出,主要的WinSockAPI函數(shù)。[表4-1]WinSockAPI函數(shù)函數(shù)功能WSAStartup()連結(jié)應用程序與WindowsSocketsDLL的第一個函數(shù)WSACleanup()結(jié)束WindowsSocketsDLL的使用socket()建立Socketclosesocket()關(guān)閉某一Socketbind()將一本地地址與一個SOCKET描述字連接在一起listen()設定Socket為監(jiān)聽狀態(tài),準備被連接accept()接受某一Socket的連接要求,以完成面向連接的客戶端Socket的連接請求。 鹽城工學院本科生畢業(yè)設計說明書(2010)connect()要求連接某一Socket到指定的網(wǎng)絡上服務端recv()從面向連接的Socket接收信息send()使用面向連接的Socket發(fā)送信息WSAAsyncSelect()要求某一Socket有事件(event)發(fā)生時通知使用者套接字(Socket)是一種雙向的通信接口,可以通過這個端口與任何一個具有Socket端口的計算機通信,套接字是網(wǎng)絡通信的基礎。Socket在Windows以句柄的形式被創(chuàng)建。使用Socket進行網(wǎng)絡通信必須包含下面的幾種信息:雙方認可的協(xié)議,本地主機的IP地址,本地進程的協(xié)議端口,對方主機的IP地址,對方進程的協(xié)議端口。Socket可分為:1)數(shù)據(jù)報套接字(DatagramSockets)——對于在TCP/IP上實現(xiàn)的WinSock,數(shù)據(jù)報套接字使用用戶數(shù)據(jù)報協(xié)議(UDP)。數(shù)據(jù)報套接字提供了一種不可靠的、非連接的數(shù)據(jù)包通信方式。2)流式套接字(StreamSockets)——流式套接字使用傳輸控制協(xié)議(TCP)。流式套接字可以將數(shù)據(jù)按順序無重復地發(fā)送到目的地,它提供的是一種可靠的、面向連接的數(shù)據(jù)傳輸方式。不管是對單個的數(shù)據(jù)報,還是對數(shù)據(jù)包,流式套接字都提供了一種流式數(shù)據(jù)傳輸。在TCP/IP網(wǎng)絡中兩個進程間的相互作用的主機模式是客戶機/服務器模式(Client/Servermodel)。該模式的建立基于以下兩點:1、非對等作用;2、通信完全是異步的??蛻魴C/服務器模式在操作過程中采取的是主動請示方式:首先服務器方要先啟動,并根據(jù)請示提供相應服務:(過程如下)1)打開一通信通道并告知本地主機,它愿意在某一個公認地址上接收客戶請求。2)等待客戶請求到達該端口。3)接收到重復服務請求,處理該請求并發(fā)送應答信號。4)返回第二步,等待另一客戶請求5)關(guān)閉服務器。而客戶方過程為:1)打開一通信通道,并連接到服務器所在主機的特定端口。2)向服務器發(fā)送服務請求報文,等待并接收應答;繼續(xù)提出請求……3)請求結(jié)束后關(guān)閉通信通道并終止。其中基本的套接字有以下幾種:1)創(chuàng)建套接字——socket()功能:使用前創(chuàng)建一個新的套接字格式:SOCKETPASCALFARsocket(intaf,inttype,intprocotol);參數(shù):af:通信發(fā)生的區(qū)域;type:要建立的套接字類型。2)指定本地地址——bind() 鹽城工學院本科生畢業(yè)設計說明書(2010)功能:將套接字地址與所創(chuàng)建的套接字號聯(lián)系起來。格式:intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);參數(shù):s:是由socket()調(diào)用返回的并且未作連接的套接字描述符(套接字號)。其它:沒有錯誤,bind()返回0,否則SOCKET_ERROR地址結(jié)構(gòu)說明:structsockaddr_in{shortsin_family;//AF_INETu_shortsin_port;//16位端口號,網(wǎng)絡字節(jié)順序structin_addrsin_addr;//32位IP地址,網(wǎng)絡字節(jié)順序charsin_zero[8];//保留}3)建立套接字連接——connect()和accept()功能:共同完成連接工作格式:intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen)。4)監(jiān)聽連接——listen()功能:用于面向連接服務器,表明它愿意接收連接。格式:intPASCALFARlisten(SOCKETs,intbacklog)。5)數(shù)據(jù)傳輸——send()與recv()功能:數(shù)據(jù)的發(fā)送與接收。格式:intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags);參數(shù):buf:指向存有傳輸數(shù)據(jù)的緩沖區(qū)的指針。6)關(guān)閉套接字——closesocket()功能:關(guān)閉套接字s格式:BOOLPASCALFARclosesocket(SOCKETs)。4.3.1.4MFCCAsyncSocket編程為簡化套接字編程,MFC定義了兩個套接字類:CAsyncSocket、CSocket。CAsyncSocket類在低層次上對WindowsSocketsAPI進行了封裝,其成員函數(shù)和WindowsSocketsAPI函數(shù)直接相對應。一個CAsyncSocket對象就代表了一個套接字。為了給程序員提供更方便的接口以自動處理網(wǎng)絡通信中的一些任務,MFC在CAsycnSocket類的基礎上派生了CSocket類,它提供了比CAsyncSocket更高層的WinSock 鹽城工學院本科生畢業(yè)設計說明書(2010)API接口。CSocket的網(wǎng)絡操作是同步方式,即阻塞式的。CSocket建立的Socket不是阻塞的,而是對非阻塞的Socket進行處理后實現(xiàn)的阻塞操作。在阻塞任務執(zhí)行過程中,Windows線程的消息循環(huán)仍然有效,也就是說CSocket類的阻塞操作不影響Windows的消息循環(huán)。MFC中Socket相關(guān)類的繼承關(guān)系如圖4-9所示。CObjectCAsyncSockCSocket圖4-9MFC中Socket相關(guān)類的繼承關(guān)系???建立Socket的WSAStartup過程和bind過程被簡化成為Create過程,IP地址類型轉(zhuǎn)換、主機名和IP地址轉(zhuǎn)換的過程中許多復雜的變量類型都被簡化成字符串和整數(shù)操作,特別是CAsyncSocket類的異步特點,完全可以替代繁瑣的線程操作。4.3.1.4.1CAsyncSocketCAsyncSocket類直接派生于CObject類,稱為異步套接字對象。由于CAsyncSocket類的構(gòu)造函數(shù)不帶參數(shù),需要調(diào)用起成員函數(shù)Create來創(chuàng)建底層的套接字句柄,決定套接字對象的具體特性,并綁定它的地址。其格式為:BOOLCreate(UINTnSocketPort=0,???IntnSocketType=SOCK_STREAM,???LongIevent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,???LPCTSTRlpszSocketAddress=NULL)CAsyncSocket類的6種網(wǎng)絡事件,如表4-2所示。[表4-2]網(wǎng)絡事件及重載函數(shù)事件涵???義對應處理函數(shù)FD_ACCEPT作為服務端等待連接成功OnAccept(intnErrorCode)FD_CONNECT通知請求連接的套接字,連接要求已被處理OnConnect(intnErrorCode)FD_CLOSE通知與其連接的套接字已關(guān)閉OnClose(intnErrorCode);FD_READ通知有數(shù)據(jù)到達OnReceive(intnErrorCode)FD_WRITE通知可以發(fā)送數(shù)據(jù)OnSend(intnErrorCode) 鹽城工學院本科生畢業(yè)設計說明書(2010)FD_OOB通知將有外帶數(shù)據(jù)到達OnOutOfBandData(intErrorCode);當某個網(wǎng)絡事件發(fā)生時,MFC框架把消息發(fā)送給相應的套接字對象,相當于給了該對象一個通知,告訴它某個重要的事件已經(jīng)發(fā)生,接著自動調(diào)用該對象的事件處理函數(shù)。??正常情況下,服務器端必須首先創(chuàng)建一個CAsyncSocket套接字對象,并調(diào)用它的Create成員函數(shù)創(chuàng)建底層套接字句柄。這個套接字對象專門用來偵聽來自客戶機的連接請求,所以稱它為偵聽套接字對象。再調(diào)用偵聽套接字對象的Listen函數(shù),使偵聽套接字對象開始偵聽來自客戶端的連接請求。當Listen函數(shù)確認并接納了一個客戶端連接請求后,觸發(fā)FD_ACCEPT事件,偵聽套接字收到通知,MFC框架自動調(diào)用偵聽套接字的OnAccept事件處理函數(shù)。一般需要重載OnAccept函數(shù),再在其中調(diào)用偵聽套接字對象的Accept函數(shù)。創(chuàng)建一個新的空套接字對象,專門用來與客戶端連接并進行數(shù)據(jù)的傳輸,一般稱為連接套接字,并作為參數(shù)傳遞給下一步的Accept成員函數(shù)??蛻舳苏埱筮B接到服務器端,在服務器端套接字對象已經(jīng)進入偵聽狀態(tài)之后,客戶應用程序可以調(diào)用CAsyncSocket類的Connect成員函數(shù),向服務器發(fā)出一個連接請求。調(diào)用結(jié)束返回時發(fā)生FD_CONNECT事件,MFC框架會自動調(diào)用客戶端套接字的OnConnect事件處理函數(shù)。CSocket類是CAsyncSocket的派生類。創(chuàng)建CSocket對象時,首先要調(diào)用CSocket類的構(gòu)造函數(shù)創(chuàng)建一個空的CSocket對象,再調(diào)用其Create成員函數(shù),創(chuàng)建對象的底層套接字。其格式為:BOOLCreate(?????UINTnSocketPort=端口號,?????IntnSocketPort=SOCK_STREAM|SOCK_DGRAM,?????LPCTSTRlpszSocketAddress=套接字所用的網(wǎng)絡地址);4.3.1.4.2CSocketCSocket類使用基類CAsyncSocket的同名成員函數(shù)Connect、Listen、Accept來建立服務器和客戶機套接字之間的連接,使用方法基本相同。在創(chuàng)建CSocket類對象后,對于流式套接字,首先在服務器和客戶機之間建立連接,然后使用Send函數(shù)、Receive函數(shù)來發(fā)送和接收數(shù)據(jù)。??需要注意的是,CSocket對象從不調(diào)用OnConnect和OnSend事件處理函數(shù)。CSocket類繼承了CAsyncSocket類的許多成員函數(shù),用法基本一致。CSocket類的高級性主要表現(xiàn)在3個方面。1)CSocket結(jié)合CArchive類來使用套接字。2)CSocket管理了通信的許多方面,比如字節(jié)順序問題和字符串轉(zhuǎn)換問題。3)CSocket類為Windows消息的后臺處理提供了阻塞的工作模式。因此,一般將CSocket與CArchive、CSocketFile 鹽城工學院本科生畢業(yè)設計說明書(2010)類相結(jié)合,來發(fā)送和接收數(shù)據(jù),這將使編程更為簡單。4.3.2網(wǎng)絡的傳送和接收流程圖進行聊天需要建立服務器端Socket和客戶端Socket,并且要連接上,這樣才能進行信息的傳送,通信模塊主要定義的就是這部分Socket建立和連接。面向連接的套接字的系統(tǒng)調(diào)用時序,如圖4-10所示。圖4-10套接字的系統(tǒng)調(diào)用流程4.3.3網(wǎng)絡的傳送和接收核心代碼//初始化網(wǎng)絡BOOLCUdpSocket::Ini(){ 鹽城工學院本科生畢業(yè)設計說明書(2010)//已經(jīng)初始化if(m_bIni)//返回returnFALSE;//創(chuàng)建數(shù)據(jù)報類型的套接字if(!this->Create(NULL,SOCK_DGRAM)){returnFALSE;};//設置初始化完成標記m_bIni=TRUE;returnTRUE;}intCUdpSocket::Send(constvoid*lpBuf,intnBufLen,intnFlags){//音頻數(shù)據(jù)序號m_pFrame->iIndex++;//復制音頻格式信息memcpy(m_cBuffer+sizeof(structFrame),lpBuf,nBufLen);//調(diào)用基類SendTo()函數(shù)發(fā)送音頻格式信息returnCAsyncSocket::SendTo(m_pFrame,nBufLen+sizeof(structFrame),TALK_REC_PORT,m_ip,nFlags);}//關(guān)閉套接字BOOLCUdpSocket::CloseSocket(){//已經(jīng)關(guān)閉if(!m_bIni)returnFALSE;//關(guān)閉套接字CAsyncSocket::Close();//設置初始化未完成標記m_bIni=FALSE;//返回returnTRUE;}//設置Ip地址 鹽城工學院本科生畢業(yè)設計說明書(2010)voidCUdpSocket::SetIp(CStringip){m_ip=ip;}//發(fā)送端CSendClientmemberfunctions//重載OnReceive()函數(shù)voidCSendClient::OnReceive(intnErrorCode){structTalkFrame*frame;frame=(structTalkFrame*)m_pBuffer;intiLen=sizeof(structTalkFrame);//接收緩存中所有的TalkFrame結(jié)構(gòu)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)-iLen,iLen);//出錯if(i==SOCKET_ERROR)//返回return;iLen-=i;}//如果不是正常數(shù)據(jù)就返回if(strcmp(frame->cFlag,"TalkFrame")!=0){return;}iLen=frame->iLen;//接收緩存中所有的音頻數(shù)據(jù)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)+(frame->iLen-iLen),iLen);//出錯if(i==SOCKET_ERROR) 鹽城工學院本科生畢業(yè)設計說明書(2010)//返回return;iLen-=i;}//對方地址CStringadd;//端口UINTport;switch(frame->iCom){//正常通信幀caseTC_AGREE_TALK://獲取連接對方地址和端口GetPeerName(add,port);//提示開始工作m_pInterFace->TalkStart(add);//允許發(fā)送數(shù)據(jù)m_pIn->EnableSend(TRUE);//設置允許工作標志m_pInterFace->m_bWork=TRUE;break;default:break;}//接收端//重載OnAccept()函數(shù)voidCListenSocket::OnAccept(intnErrorCode){//客戶端地址SOCKADDRadd;//客戶端地址長度intiLen;iLen=sizeof(SOCKADDR);//臨時socketCSocketsoTemp;//已經(jīng)連接 鹽城工學院本科生畢業(yè)設計說明書(2010)if(m_sopClient->m_bConnect){//用臨時socket接收連接請求soTemp.Accept(*this);//關(guān)閉soTemp.Close();//返回return;}//接受連接請求if(!Accept(*m_sopClient,&add,&iLen)){//返回return;}//設置連接標記m_sopClient->m_bConnect=TRUE;//調(diào)用基類OnAccept()函數(shù)CSocket::OnAccept(nErrorCode);}//關(guān)閉套接字voidCListenSocket::CloseClient(){//關(guān)閉套接字m_sopClient->Close();//設置未連接標記m_sopClient->m_bConnect=FALSE;}//CSendClientmemberfunctions//重載OnReceive()函數(shù)voidCSendClient::OnReceive(intnErrorCode){structTalkFrame*frame;frame=(structTalkFrame*)m_pBuffer;intiLen=sizeof(structTalkFrame);//接收緩存中所有的TalkFrame結(jié)構(gòu) 鹽城工學院本科生畢業(yè)設計說明書(2010)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)-iLen,iLen);//出錯if(i==SOCKET_ERROR)//返回return;iLen-=i;}//如果不是正常數(shù)據(jù)就返回if(strcmp(frame->cFlag,"TalkFrame")!=0){return;}iLen=frame->iLen;//接收緩存中所有的音頻數(shù)據(jù)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)+(frame->iLen-iLen),iLen);//出錯if(i==SOCKET_ERROR)//返回return;iLen-=i;}//對方地址CStringadd;//端口UINTport;switch(frame->iCom){//正常通信幀caseTC_AGREE_TALK: 鹽城工學院本科生畢業(yè)設計說明書(2010)//獲取連接對方地址和端口GetPeerName(add,port);//提示開始工作m_pInterFace->TalkStart(add);//允許發(fā)送數(shù)據(jù)m_pIn->EnableSend(TRUE);//設置允許工作標志m_pInterFace->m_bWork=TRUE;break;default:break;}4.4界面設計4.4.1MFC及其特點MFC,即微軟基礎類(MicrosoftFoundationClasses),用于在C++環(huán)境下編寫應用程序的一個框架和引擎,VC++是WinDOS下開發(fā)人員使用的專業(yè)C++SDK(SDK,StandardSoftWareDevelopKit,專業(yè)軟件開發(fā)平臺),MFC就是掛在它之上的一個輔助軟件開發(fā)包,MFC作為與VC++血肉相連的部分,同BC++集成的VCL一樣是一個非外掛式的軟件包,類庫,MFC類是微軟為VC++專配的?! FC是WinAPI與C++的結(jié)合,API,即微軟提供的WinDOS下應用程序的編程語言接口,是一種軟件編程的規(guī)范,但不是一種程序開發(fā)語言本身,可以允許用戶使用各種各樣的第三方(如我是一方,微軟是一方,Borland就是第三方)的編程語言來進行對WinDOS下應用程序的開發(fā),使這些被開發(fā)出來的應用程序能在WinDOS下運行,比如VB、VC++、Java、Dehpi等編程語言函數(shù)本質(zhì)上全部源于API。因此用它們開發(fā)出來的應用程序都能工作在WinOS的消息機制和繪圖里,遵守WinDOS作為一個操作系統(tǒng)的內(nèi)部實現(xiàn),這其實也是一種必要,微軟如果不提供API,這個世上對Win編程的工作就不會存在,微軟的產(chǎn)品就會迅速從時尚變成垃圾,上面說到MFC是微軟對API函數(shù)的專用C++封裝,這種結(jié)合一方面讓用戶使用微軟的專業(yè)C++SDK來進行Win下應用程序的開發(fā)變得容易,因為MFC是對API的封裝。微軟做了大量的工作,隱藏了好多程序開發(fā)人員在Win下用C++&MFC編制軟件時的大量內(nèi)節(jié)。進行界面開發(fā),關(guān)聯(lián)一個窗口的動作,但它提供的類中有好多類不與一個窗口關(guān)聯(lián),即類的作用不是一個界面類,不實現(xiàn)對一個窗口對象的控制(如創(chuàng)建、銷毀), 鹽城工學院本科生畢業(yè)設計說明書(2010)而是一些在WinDOS(用MFC編寫的程序絕大部分都在WinDOS中運行)中實現(xiàn)內(nèi)部處理的類,如數(shù)據(jù)庫的管理類等,學習中最應花費時間的是消息和設備環(huán)境,對C++和MFC的學習中最難的部分是指針,C++面向?qū)ο癯绦蛟O計的其它部分,如數(shù)據(jù)類型,流程控制都不難,建議學習數(shù)據(jù)結(jié)構(gòu)C++版?! FC是微軟封裝了的API。windows作為一個提供功能強大的應用程序接口編程的操作系統(tǒng),的確方便了許多程序員,傳統(tǒng)的win32開發(fā)(直接使用windows的接口函數(shù)API)對于程序員來說非常的困難,因為,API函數(shù)實在太多了,而且名稱很亂,從零構(gòu)架一個窗口動輒就是上百行的代碼。MFC是面向?qū)ο蟪绦蛟O計與Applicationframework的完美結(jié)合,他將傳統(tǒng)的API進行了分類封裝,并且創(chuàng)建了程序的一般框架。MFC是對WindowsAPI的封裝,大大簡化了我們的工作;學VC主要就是要學MFC,大約有100多個類,但常用的也就二三十個。面對底層程序,它能很輕松的與WindowsAPI或驅(qū)動程序結(jié)合,就是在自己的代碼中直接使用API函數(shù),而API和驅(qū)動程序的資料都是以C語言為基礎的,這使得VC程序員能夠更輕松的使用WindowsAPI。這樣造成了一個很有意思的現(xiàn)象,即入門時VC程序員要付出更多的努力來學習,但是一旦掌握后,開發(fā)其他領域的程序或使用第三方軟件時,如工業(yè)控制類的程序等。4.4.2界面實現(xiàn)過程單擊新建,在彈出的對話框中單擊工程,點擊MFCAppWizard[exe],在右邊工程名稱[N]:下面的文本框中寫入工程名稱“test”,單擊確定,進入MFC應用程序向?qū)А襟E1,在“您要創(chuàng)建的應用程序類型是:”一欄里選擇“基本對話框[D]”,單擊下一步,在WindowsSocket[W]選項前打鉤,單擊下一步,選擇默認設置,繼續(xù)單擊下一步,保持默認設置,單擊完成。在彈出的新建工程信息對話框中單擊確定,在出現(xiàn)的原始test對話框中添加connect和disconnect按鈕,添加一個文本框,初始界面如圖4-11所示。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖4-11初始界面圖4.4.3界面實現(xiàn)代碼//testDlg.cpp:implementationfile#include"stdafx.h"#include"test.h"#include"testDlg.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif///////////////////////////////////////////////////////////////////////////////CAboutDlgdialogusedforAppAboutclassCAboutDlg:publicCDialog{public:CAboutDlg();//DialogData//{{AFX_DATA(CAboutDlg)enum{IDD=IDD_ABOUTBOX}; 鹽城工學院本科生畢業(yè)設計說明書(2010)//}}AFX_DATA//ClassWizardgeneratedvirtualfunctionoverrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport//}}AFX_VIRTUAL//Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)//{{AFX_MSG_MAP(CAboutDlg)//Nomessagehandlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CTestDlgdialogCTestDlg::CTestDlg(CWnd*pParent/*=NULL*/):CDialog(CTestDlg::IDD,pParent){//{{AFX_DATA_INIT(CTestDlg)m_ip=_T(""); 鹽城工學院本科生畢業(yè)設計說明書(2010)//}}AFX_DATA_INIT//NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCTestDlg::DoDataExchange(CDataExchange*pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CTestDlg)DDX_Text(pDX,IDC_EDIT1,m_ip);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CTestDlg,CDialog)//{{AFX_MSG_MAP(CTestDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON2,OnButton2)ON_BN_CLICKED(IDC_BUTTON3,OnButton3)//}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CTestDlgmessagehandlersBOOLCTestDlg::OnInitDialog(){CDialog::OnInitDialog();//Add"About..."menuitemtosystemmenu.//IDM_ABOUTBOXmustbeinthesystemcommandrange.ASSERT((IDM_ABOUTBOX&0xFFF0)==IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX<0xF000);CMenu*pSysMenu=GetSystemMenu(FALSE);if(pSysMenu!=NULL){CStringstrAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX); 鹽城工學院本科生畢業(yè)設計說明書(2010)if(!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);}}//Settheiconforthisdialog.Theframeworkdoesthisautomatically//whentheapplication'smainwindowisnotadialogSetIcon(m_hIcon,TRUE);//SetbigiconSetIcon(m_hIcon,FALSE);//Setsmallicon//TODO:Addextrainitializationherem_ip="192.168.10.116";UpdateData(FALSE);m_talk.Ini();returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}voidCTestDlg::OnSysCommand(UINTnID,LPARAMlParam){if((nID&0xFFF0)==IDM_ABOUTBOX){CAboutDlgdlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID,lParam);}}//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,//thisisautomaticallydoneforyoubytheframework.voidCTestDlg::OnPaint() 鹽城工學院本科生畢業(yè)設計說明書(2010){if(IsIconic()){CPaintDCdc(this);//devicecontextforpaintingSendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);//CentericoninclientrectangleintcxIcon=GetSystemMetrics(SM_CXICON);intcyIcon=GetSystemMetrics(SM_CYICON);CRectrect;GetClientRect(&rect);intx=(rect.Width()-cxIcon+1)/2;inty=(rect.Height()-cyIcon+1)/2;//Drawtheicondc.DrawIcon(x,y,m_hIcon);}else{CDialog::OnPaint();}}//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags//theminimizedwindow.HCURSORCTestDlg::OnQueryDragIcon(){return(HCURSOR)m_hIcon;}voidCTestDlg::OnButton2(){//TODO:Addyourcontrolnotificationhandlercodeherethis->UpdateData();m_talk.Start(m_ip);voidCTestDlg::OnButton3(){//TODO:Addyourcontrolnotificationhandlercodeherem_talk.End();} 鹽城工學院本科生畢業(yè)設計說明書(2010)5測試測試在開發(fā)軟件過程中是一個不可缺少的部分。因為在開發(fā)軟件系統(tǒng)的漫長過程中,面對著極其錯綜復雜的問題,人的主觀認識不可能完全符合客觀現(xiàn)實,與工程密切相關(guān)的各類人員之間的通信和配合也不可能完美無缺,因此,在軟件生命周期的各個階段都不可避免地產(chǎn)生差錯。我們力求在每個階段結(jié)束之前通過嚴格的技術(shù)審查,盡可能早地發(fā)現(xiàn)并糾正錯誤;但是,經(jīng)驗表明審查并不能發(fā)現(xiàn)所有的差錯,此外在編碼過程中還不可避免地會引入一些新的錯誤。如果在軟件生產(chǎn)性運行之前,沒有發(fā)現(xiàn)并糾正軟件中的大部分差錯,則這些錯誤遲早在生產(chǎn)過程中暴露出來,那時不僅僅改正這些錯誤的代價更高,而且往往會造成很惡劣的后果。測試的目的就是在軟件投入生產(chǎn)運行之前,盡可能多地發(fā)現(xiàn)并糾正軟件中的錯誤?;谏鲜龅脑?,我在編碼過程中進行了模塊測試,編碼結(jié)束進行了系統(tǒng)測試和驗收測試。下面是測試方案,測試過程和測試結(jié)果。5.1模塊測試1)測試方案采用了白盒測試,即按照程序內(nèi)部的邏輯結(jié)構(gòu),檢驗程序中的每條通路是否都按預定要求正常工作。2)測試過程檢驗模塊之間的接口。A每個被調(diào)用模塊是否正確接受參數(shù)。B每個調(diào)用模塊是否能調(diào)用每個自己想要調(diào)用的模塊。3)測試結(jié)果測試結(jié)果表明,每個模塊之間的接口都吻合,即被調(diào)用模塊都能正確接受參數(shù),調(diào)用模塊能調(diào)用自己想要調(diào)用的每個模塊。5.2功能測試1)測試方法采用了黑盒測試,即檢查程序功能是否能要求進行,是否適當?shù)亟邮軘?shù)據(jù)產(chǎn)生正確的輸出信息,并且保持外部信息的完整性。2)測試過程主要檢驗是否能正確實現(xiàn)每個功能。A每個功能是否按要求正常進行。B用戶界面是否友好測試結(jié)果表明,每個功能都按要求進行。3)測試結(jié)果 鹽城工學院本科生畢業(yè)設計說明書(2010)結(jié)果表明,經(jīng)過測試每個功能都能按預先要求正常進行且速度達到了預期的標準。用戶界面友好。當用戶請求語音聊天的時,系統(tǒng)能快速準確地聯(lián)系到對方并建立語音連接。當然,整個系統(tǒng)在測試過程中仍發(fā)現(xiàn)了不少的錯誤,但在指導老師的指導下改正并完善了所發(fā)現(xiàn)的錯誤。其測試過程的界面分別為:①在要實現(xiàn)通信的兩臺機器分別將test應用程序打開,初始界面為圖5-1所示。圖5-1初始狀態(tài)②將另一方IP地址輸入文本框里,點擊連接,服務端顯示如圖5-2所示。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖5-2①點擊確定客戶端顯示如圖5-3所示。圖5-3②點擊是,服務端顯示圖5-4,客戶端顯示如圖5-5所示。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖5-4圖5-5①兩端都點擊確定,就可以進行語音通信了,若有一方點擊斷開連接,顯示如圖5-6所示,點擊確定應用程序自動退出。 鹽城工學院本科生畢業(yè)設計說明書(2010)圖5-6 鹽城工學院本科生畢業(yè)設計說明書(2010)結(jié)論為期三個月的畢業(yè)設計已經(jīng)結(jié)束了,從中我學到了很多東西,包括治學的也包括做人的。本次畢業(yè)論文的研究的課題是語音通信系統(tǒng),主要實現(xiàn)在局域網(wǎng)里進行語音聊天,來實現(xiàn)彼此溝通、交流信息。本設計主要用了VisualC++編程環(huán)境,實現(xiàn)了在LAN中在線用戶實現(xiàn)語音交互。在設計里涉及到了網(wǎng)絡通信基本原理和Socket編程及語音處理API技術(shù)。語音通信系統(tǒng)包括四個模塊,分別是通信模塊、聲源采集模塊、音頻編解碼模塊、音頻再生模塊?;仡櫰鸫舜萎厴I(yè)設計,至今我仍感慨頗多,從選題到定稿,從理論到實踐,可以說是苦多于甜,但是可以學到很多很多的的東西,同時不僅可以鞏固了以前所學過的知識,而且學到了很多在書本上所沒有學到過的知識。通過這次課程設計使我懂得了理論與實際相結(jié)合是很重要的,只有理論知識是遠遠不夠的,只有把所學的理論知識與實踐相結(jié)合起來,從理論中得出結(jié)論,才能真正為社會服務,從而提高自己的實際動手能力和獨立思考的能力。在設計的過程中遇到問題,可以說得是困難重重,但是作為畢業(yè)設計,難免會遇到過各種各樣的問題,同時在設計的過程中發(fā)現(xiàn)了自己的不足之處,對以前所學過的知識理解得不夠深刻,通過這次課程設使我對c語言有了更深入的認識和了解,還有學會如何查閱文獻。很重要的一點是對進行軟件設計的整體設計流程及思維方法有了深刻的認識。在期間,發(fā)現(xiàn)的許多問題都源于沒有認真地按步驟進行設計,不重視需求分析,總體設計部分,對各個方面將會產(chǎn)生的問題考慮不周全。在設計過程中,對于我來說,由于很多都是新知識,這就迫使我到處查閱相關(guān)資料,學習新知識,不僅體會到VisualC++編程環(huán)境的強大功能,也對新接觸到的Socket編程和語言處理API有了大概的了解。由于我本人的技術(shù)限制,可能有很多不足之處,望各位老師多加批評和指正,謝謝! 鹽城工學院本科生畢業(yè)設計說明書(2010)參考文獻[1]張海棠.VisualC++6.0編程指南[J].航空工業(yè)出版社,1999.[2]張岳新.VisualC++程序設計[M].蘇州大學出版社,2005.[3]胡海璐.VisualC++高級編程技術(shù)與范例[M].電子工業(yè)出版社,2002.[4]易軍.VisualC++網(wǎng)絡編程[J].中國鐵道出版社,2003[5]丁展.VisualC++網(wǎng)絡通信實用案例精選[M].郵電出版社,2004.[6]張海棠.VisualC++數(shù)據(jù)庫通用模塊開發(fā)與系統(tǒng)移植[J].清華大學出版社,2006.[7]趙立新.網(wǎng)絡多媒體通信——語音編碼技術(shù)研究[D].西安電子科技大學,2002.[8]涂友華.基于SIP會議系統(tǒng)的研究[D].北京郵電大學,2004. 鹽城工學院本科生畢業(yè)設計說明書(2010)致謝首先,也是最主要感謝的是我的指導老師,朱明老師。在整個過程中他給了我很大的幫助,在論文題目制定時,他首先肯定了我的題目大方向,同時又幫我具體分析了具體目標,讓我在寫作時有了具體方向。在論文提綱制定時,我的思路不是很清晰,經(jīng)過老師的幫忙,讓我具體寫作時思路頓時清晰。在完成初稿后,老師認真查看了我的文章,指出了我存在的很多問題。在此十分感謝朱老師的細心指導,才能讓我順利完成畢業(yè)論文。同時,對給過我?guī)椭乃型瑢W和其他指導老師再次表示忠心的感謝!感謝他們這幾個月來的悉心教導和幫助。 鹽城工學院本科生畢業(yè)設計說明書(2010)附錄源程序核心代碼//音頻編/解碼#include"stdafx.h"#include"AudioCode.h"extern"C"voidva_g729a_init_encoder();extern"C"voidva_g729a_encoder(short*speech,unsignedchar*bitstream);extern"C"voidva_g729a_init_decoder();extern"C"voidva_g729a_decoder(unsignedchar*bitstream,short*synth_short,intbfi);#defineL_FRAME_COMPRESSED10#defineL_FRAME80//包含動態(tài)鏈接庫#pragmacomment(lib,"G729a")//構(gòu)造函數(shù)CAudioCode::CAudioCode(){va_g729a_init_encoder();//初始化編碼器va_g729a_init_decoder();//初始化解碼器}//析構(gòu)函數(shù)CAudioCode::~CAudioCode(){}//編碼音頻數(shù)據(jù)BOOLCAudioCode::EncodeAudioData(char*pin,intlen,char*pout,int*lenr){//編碼成功與否標記BOOLbRet=FALSE;//無效輸入或輸出if(!pin||len!=SIZE_AUDIO_FRAME||!pout)gotoRET;//分塊進行編碼va_g729a_encoder((short*)pin,(BYTE*)pout);va_g729a_encoder((short*)(pin+160),(BYTE*)pout+10);va_g729a_encoder((short*)(pin+320),(BYTE*)pout+20);va_g729a_encoder((short*)(pin+480),(BYTE*)pout+30);va_g729a_encoder((short*)(pin+640),(BYTE*)pout+40);va_g729a_encoder((short*)(pin+800),(BYTE*)pout+50);//編碼長度if(lenr)*lenr=SIZE_AUDIO_PACKED;//編碼成功標記bRet=TRUE; 鹽城工學院本科生畢業(yè)設計說明書(2010)RET://返回returnbRet;}//音頻解碼BOOLCAudioCode::DecodeAudioData(char*pin,intlen,char*pout,int*lenr){//解碼成功與否標記BOOLbRet=FALSE;//無效輸入或輸出if(!pin||len!=SIZE_AUDIO_PACKED||!pout)gotoRET;//分塊解碼va_g729a_decoder((BYTE*)pin,(short*)(pout),0);va_g729a_decoder((BYTE*)pin+10,(short*)(pout+160),0);va_g729a_decoder((BYTE*)pin+20,(short*)(pout+320),0);va_g729a_decoder((BYTE*)pin+30,(short*)(pout+480),0);va_g729a_decoder((BYTE*)pin+40,(short*)(pout+640),0);va_g729a_decoder((BYTE*)pin+50,(short*)(pout+800),0);//解碼長度if(lenr)*lenr=SIZE_AUDIO_FRAME;//設置解碼成功標記bRet=TRUE;RET://返回returnbRet;}//音頻錄取#include"stdafx.h"#include"WaveIn.h"#include"math.h"#pragmacomment(lib,"Winmm")DWORDCWaveIn::s_dwInstance=0;//線程處理DWORDWINAPICWaveIn::AudioInThreadProc(LPVOIDlpParameter){CWaveIn*pWaveIn;pWaveIn=(CWaveIn*)lpParameter;//緩存charbuffer[1024];//消息處理主循環(huán)MSGmsg;while(GetMessage(&msg,0,0,0)){switch(msg.message) 鹽城工學院本科生畢業(yè)設計說明書(2010){//打開錄音設備caseMM_WIM_OPEN:break;//關(guān)閉錄音設備caseMM_WIM_CLOSE:break;//錄音設備返回數(shù)據(jù)caseMM_WIM_DATA://錄音格式WAVEHDR*pWH=(WAVEHDR*)msg.lParam;//釋放緩存waveInUnprepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));//非法數(shù)據(jù)if(pWH->dwBytesRecorded!=SIZE_AUDIO_FRAME)break;//復制錄音數(shù)據(jù)memcpy(buffer,pWH->lpData,pWH->dwBytesRecorded);//設置時戳pWaveIn->GetData(buffer,pWH->dwBytesRecorded);//為音頻設備增加一個緩存,準備繼續(xù)錄音waveInPrepareHeader((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));waveInAddBuffer((HWAVEIN)msg.wParam,pWH,sizeof(WAVEHDR));break;}}//返回returnmsg.wParam;}//構(gòu)造函數(shù)CWaveIn::CWaveIn():m_wChannel(1),m_dwSample(WISA_POOR),m_wBit(16){m_hIn=0;m_bThreadStart=FALSE;m_bDevOpen=FALSE;m_bAllocBuffer=FALSE;m_bRecord=FALSE;m_pHdr=NULL;m_dwAudioInId=0;s_dwInstance++;}//構(gòu)析函數(shù)CWaveIn::~CWaveIn(){} 鹽城工學院本科生畢業(yè)設計說明書(2010)//關(guān)閉錄音設備BOOLCWaveIn::CloseDev(){//設備已經(jīng)關(guān)閉if(!m_bDevOpen){//返回returnFALSE;}//設備句柄無效if(!m_hIn){//返回returnFALSE;}//關(guān)閉錄音設備m_mmr=waveInClose(m_hIn);//出錯if(m_mmr){//設置設備句柄無效m_hIn=0;//設置設備啟動標記m_bDevOpen=FALSE;//返回returnFALSE;}//設置設備句柄無效m_hIn=0;//設置設備啟動標記m_bDevOpen=FALSE;//返回returnTRUE;}//打開錄音設備BOOLCWaveIn::OpenDev(){//已經(jīng)打開錄音設備if(m_bDevOpen){//返回returnFALSE;}//設置錄音設備輸出格式WAVEFORMATEXwfx;wfx.wFormatTag=WAVE_FORMAT_PCM;wfx.nChannels=m_wChannel;wfx.nSamplesPerSec=m_dwSample; 鹽城工學院本科生畢業(yè)設計說明書(2010)wfx.nAvgBytesPerSec=m_wChannel*m_dwSample*m_wBit/8;wfx.nBlockAlign=m_wBit*m_wChannel/8;wfx.wBitsPerSample=m_wBit;wfx.cbSize=0;//檢查錄音設備是否支持設定的輸出格式m_mmr=waveInOpen(0,WAVE_MAPPER,&wfx,0,0,WAVE_FORMAT_QUERY);//出錯if(m_mmr){//返回returnFALSE;}//打開錄音設備m_mmr=waveInOpen(&m_hIn,WAVE_MAPPER,&wfx,m_dwAudioInId,s_dwInstance,CALLBACK_THREAD);//出錯if(m_mmr){//返回returnFALSE;}//設置設備打開標記m_bDevOpen=TRUE;//返回returnTRUE;}//啟動線程BOOLCWaveIn::StartThread(){//線程已經(jīng)啟動if(m_bThreadStart){//返回returnFALSE;}//創(chuàng)建線程m_hAudioIn=CreateThread(0,0,AudioInThreadProc,this,0,&m_dwAudioInId);//出錯if(!m_hAudioIn){//返回returnFALSE;}//設置線程啟動標記m_bThreadStart=TRUE;//返回returnTRUE; 鹽城工學院本科生畢業(yè)設計說明書(2010)}//關(guān)閉線程BOOLCWaveIn::StopThread(){//線程已經(jīng)停止if(!m_bThreadStart){//返回returnFALSE;}//線程句柄有效if(m_hAudioIn){//循環(huán)變量intt=50;//線程結(jié)束狀態(tài)信息DWORDExitCode;//線程結(jié)束標記BOOLbEnd=FALSE;//發(fā)送WM_QUIT消息PostThreadMessage(m_dwAudioInId,WM_QUIT,0,0);//主循環(huán)while(t){//獲取線程結(jié)束狀態(tài)信息GetExitCodeThread(m_hAudioIn,&ExitCode);//尚未結(jié)束if(ExitCode!=STILL_ACTIVE){//設置線程結(jié)束bEnd=TRUE;break;}//休眠10毫秒else{Sleep(10);}//修改循環(huán)變量t--;}//線程尚未結(jié)束if(!bEnd){//終止線程TerminateThread(m_hAudioIn,0);}//錄音設備句柄無效 鹽城工學院本科生畢業(yè)設計說明書(2010)m_hAudioIn=0;}//設置線程結(jié)束標記m_bThreadStart=FALSE;//返回returnTRUE;}//啟動錄音BOOLCWaveIn::StartRec(){//返回值BOOLbRet=FALSE;//啟動線程失敗if(!StartThread()){gotoExit;};//打開錄音設備失敗if(!OpenDev()){gotoExit1;};//準備緩存失敗if(!PerPareBuffer()){gotoExit2;}//開始錄音if(!OpenRecord()){gotoExit3;}//設置返回值bRet=TRUE;gotoExit;Exit3://釋放緩存FreeBuffer();Exit2://關(guān)閉錄音設備CloseDev();Exit1://停止線程StopThread();Exit://返回returnbRet;} 鹽城工學院本科生畢業(yè)設計說明書(2010)//終止錄音BOOLCWaveIn::StopRec(){//停止錄音CloseRecord();//休眠1500毫秒Sleep(1500);//釋放緩存FreeBuffer();//關(guān)閉錄音設備if(CloseDev()){//停止線程StopThread();}//返回returnTRUE;}//分配內(nèi)存BOOLCWaveIn::PerPareBuffer(){//已經(jīng)分配內(nèi)存if(m_bAllocBuffer){//返回returnFALSE;}//重置錄音設備m_mmr=waveInReset(m_hIn);//出錯if(m_mmr){//返回returnFALSE;}//循環(huán)變量UINTi;//新建WAVEHDR結(jié)構(gòu)m_pHdr=newWAVEHDR[NUM_BUF];for(i=0;i=1){memcpy(&time,&time1,sizeof(time));TRACE("Len/second%d ",l);l=0;}l=l+iLen;i++;}MMRESULTCWaveIn::GetLastMMError() 鹽城工學院本科生畢業(yè)設計說明書(2010){returnm_mmr;}CStringCWaveIn::GetLastErrorString(){charbuffer[256];memset(buffer,0,256);waveInGetErrorText(m_mmr,buffer,256);returnbuffer;}voidCWaveIn::SetChannel(WORDwChannel){m_wChannel=(m_wChannel==wChannel)?2:1;}voidCWaveIn::SetSample(DWORDdwSample){m_dwSample=dwSample;}voidCWaveIn::SetBit(WORDwBit){m_wBit=(wBit==8)?8:16;}DWORDCWaveIn::GetInstance(){returns_dwInstance;}WORDCWaveIn::GetBit(){returnm_wBit;}DWORDCWaveIn::GetSample(){returnm_dwSample;}WORDCWaveIn::GetChannel(){returnm_wChannel;}//音頻回放#include"stdafx.h"#include"WaveOut.h"#pragmacomment(lib,"Winmm")DWORDCWaveOut::s_dwInstance=0;//線程處理DWORDWINAPICWaveOut::AudioOutThreadProc(LPVOIDlpParameter){CWaveOut*pWaveIn;pWaveIn=(CWaveOut*)lpParameter; 鹽城工學院本科生畢業(yè)設計說明書(2010)MSGmsg;//消息處理主循環(huán)while(GetMessage(&msg,0,0,0)){switch(msg.message){//打開播音設備caseWOM_OPEN:break;//關(guān)閉播音設備caseWOM_CLOSE:break;//播音完畢caseWOM_DONE://播音格式WAVEHDR*pwh=(WAVEHDR*)msg.lParam;//釋放播音緩存waveOutUnprepareHeader((HWAVEOUT)msg.wParam,pwh,sizeof(WAVEHDR));//減少播音緩存數(shù)目pWaveIn->BufferSub();//刪除Play調(diào)用時分配的內(nèi)存delete[]pwh->lpData;//刪除播音格式deletepwh;break;}}//返回returnmsg.wParam;}//構(gòu)造函數(shù),用于初始化CWaveOut::CWaveOut():m_wChannel(1),m_dwSample(WOSA_POOR),m_wBit(16){m_hOut=0;m_hAudioOut=0;m_dwAudioOutId=0;m_iBufferNum=0;m_bThreadStart=FALSE;m_bDevOpen=FALSE;s_dwInstance++;}//構(gòu)析函數(shù)CWaveOut::~CWaveOut(){} 鹽城工學院本科生畢業(yè)設計說明書(2010)//啟動線程BOOLCWaveOut::StartThread(){//線程已經(jīng)啟動if(m_bThreadStart){//返回returnFALSE;}//創(chuàng)建線程m_hAudioOut=CreateThread(0,0,AudioOutThreadProc,this,0,&m_dwAudioOutId);//出錯if(!m_hAudioOut){//返回returnFALSE;}//設置線程啟動標記m_bThreadStart=TRUE;//返回returnTRUE;}//停止線程BOOLCWaveOut::StopThread(){//線程已經(jīng)停止if(!m_bThreadStart){//返回returnFALSE;}//線程句柄有效if(m_hAudioOut){//循環(huán)變量intt=50;//線程結(jié)束狀態(tài)DWORDExitCode;//線程結(jié)束標記BOOLbEnd=FALSE;//發(fā)送WM_QUIT消息PostThreadMessage(m_dwAudioOutId,WM_QUIT,0,0);while(t){//獲取線程結(jié)束狀態(tài)信息GetExitCodeThread(m_hAudioOut,&ExitCode);//線程結(jié)束 鹽城工學院本科生畢業(yè)設計說明書(2010)if(ExitCode!=STILL_ACTIVE){//設置線程尚未結(jié)束標記bEnd=TRUE;break;}//休眠10毫秒else{Sleep(10);}//修改循環(huán)變量t--;}//線程尚未結(jié)束if(!bEnd){//結(jié)束線程TerminateThread(m_hAudioOut,0);}//設置音頻設備句柄無效m_hAudioOut=0;}//設置線程停止標記m_bThreadStart=FALSE;//返回returnTRUE;}//打開播音設備BOOLCWaveOut::OpenDev(){//設備已經(jīng)打開if(m_bDevOpen){//返回returnFALSE;}//設置播音輸出格式WAVEFORMATEXwfx;wfx.wFormatTag=WAVE_FORMAT_PCM;wfx.nChannels=m_wChannel;wfx.nSamplesPerSec=m_dwSample;wfx.nAvgBytesPerSec=m_wChannel*m_dwSample*m_wBit/8;wfx.nBlockAlign=m_wBit*m_wChannel/8;wfx.wBitsPerSample=m_wBit;wfx.cbSize=0;//檢查播音設備是否支持上述格式m_mmr=waveOutOpen(0,WAVE_MAPPER,&wfx,0,0,WAVE_FORMAT_QUERY); 鹽城工學院本科生畢業(yè)設計說明書(2010)//出錯if(m_mmr){//返回returnFALSE;}//打開播音設備m_mmr=waveOutOpen(&m_hOut,WAVE_MAPPER,&wfx,m_dwAudioOutId,s_dwInstance,CALLBACK_THREAD);//出錯if(m_mmr){//返回returnFALSE;}//設置設備打開標記m_bDevOpen=TRUE;//初始化播音緩存數(shù)目m_iBufferNum=0;//返回returnTRUE;}//關(guān)閉播音設備BOOLCWaveOut::CloseDev(){//播音設備已經(jīng)關(guān)閉if(!m_bDevOpen){//返回returnFALSE;}//播音設備句柄無效if(!m_hOut){//返回returnFALSE;}//關(guān)閉播音設備m_mmr=waveOutClose(m_hOut);//出錯if(m_mmr){//返回returnFALSE;}//設置播音設備句柄無效m_hOut=0;//設置播音設備打開標記 鹽城工學院本科生畢業(yè)設計說明書(2010)m_bDevOpen=FALSE;//返回returnTRUE;}//開始播音BOOLCWaveOut::StartPlay(){//函數(shù)返回標志BOOLbRet=FALSE;//啟動線程失敗if(!StartThread()){gotoExit;};//打開播音設備失敗if(!OpenDev()){gotoExit1;};//設置函數(shù)返回標志bRet=TRUE;gotoExit;Exit1://停止線程StopThread();Exit://返回returnbRet;}//停止播音BOOLCWaveOut::StopPlay(){//關(guān)閉播音設備CloseDev();//關(guān)閉線程StopThread();//返回returnTRUE;}MMRESULTCWaveOut::GetLastMMError(){returnm_mmr;}CStringCWaveOut::GetLastErrorString(){charbuffer[256];memset(buffer,0,256);waveOutGetErrorText(m_mmr,buffer,256); 鹽城工學院本科生畢業(yè)設計說明書(2010)returnbuffer;}voidCWaveOut::SetChannel(WORDwChannel){m_wChannel=(m_wChannel==wChannel)?2:1;}voidCWaveOut::SetSample(DWORDdwSample){m_dwSample=dwSample;}voidCWaveOut::SetBit(WORDwBit){m_wBit=(wBit==8)?8:16;}DWORDCWaveOut::GetInstance(){returns_dwInstance;}WORDCWaveOut::GetBit(){returnm_wBit;}DWORDCWaveOut::GetSample(){returnm_dwSample;}WORDCWaveOut::GetChannel(){returnm_wChannel;}//播放BOOLCWaveOut::Play(char*buf,UINTuSize){//播音設備未打開if(!m_bDevOpen){//返回returnFALSE;}//延時太大if(GetBufferNum()>PLAY_DELAY){//返回returnTRUE;}//新建WAVEHDR結(jié)構(gòu),用于接收播音格式LPWAVEHDRpwh=newWAVEHDR;//出錯 鹽城工學院本科生畢業(yè)設計說明書(2010)if(!pwh){//返回returnFALSE;}//新建字符數(shù)組,用于接收緩存數(shù)據(jù)char*p;p=newchar[uSize];//出錯if(!p){//返回returnFALSE;}//復制緩存數(shù)據(jù)CopyMemory(p,buf,uSize);//初始化ZeroMemory(pwh,sizeof(WAVEHDR));//數(shù)據(jù)長度pwh->dwBufferLength=uSize;//波音數(shù)據(jù)pwh->lpData=p;//為回放數(shù)據(jù)作好準備m_mmr=waveOutPrepareHeader(m_hOut,pwh,sizeof(WAVEHDR));//出錯if(m_mmr){//返回returnFALSE;}//將數(shù)據(jù)發(fā)往播音設備m_mmr=waveOutWrite(m_hOut,pwh,sizeof(WAVEHDR));//出錯if(m_mmr){//返回returnFALSE;}//緩存數(shù)目增1m_iBufferNum++;//返回returnTRUE;}//增加緩存數(shù)目voidCWaveOut::BufferAdd(){//鎖住內(nèi)存m_csLock.Lock(); 鹽城工學院本科生畢業(yè)設計說明書(2010)//緩存數(shù)目增1m_iBufferNum++;//解除鎖定m_csLock.Unlock();}//減少緩存數(shù)目voidCWaveOut::BufferSub(){//鎖住內(nèi)存m_csLock.Lock();//緩存數(shù)目減1m_iBufferNum--;//解除鎖定m_csLock.Unlock();}//獲取緩存數(shù)目intCWaveOut::GetBufferNum(){//中間變量intiTemp;//鎖住內(nèi)存m_csLock.Lock();//獲得緩存數(shù)目iTemp=m_iBufferNum;//解除鎖定m_csLock.Unlock();//返回returniTemp;}BOOLCWaveOut::SetFormatByFile(CStringfile){#pragmapack(push,1)structFileHeader{charcFlagFiff[4];unsigned__int32iFileLen;charcFlagWave[4];charcFlagFmt[4];charcResove[4];unsigned__int16cFormat;unsigned__int16cChannel;unsigned__int32cSample;unsigned__int32cBytePerSec;unsigned__int16cByteprocess;unsigned__int16cBit;charcFlagDat[4];unsigned__int32iLenData;}; 鹽城工學院本科生畢業(yè)設計說明書(2010)#pragmapack(pop)CFilefi;if(!fi.Open(file,CFile::modeRead,NULL)){returnFALSE;};structFileHeaderhead;fi.Read((void*)&head,sizeof(head));fi.Close();this->SetChannel(head.cChannel);this->SetSample(head.cSample);this->SetBit(head.cBit);returnTRUE;}//網(wǎng)絡傳輸//初始化#include"stdafx.h"#include"UdpSocket.h"#include"head.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif//CUdpSocket//構(gòu)造函數(shù)CUdpSocket::CUdpSocket(){m_pFrame=(structFrame*)m_cBuffer;m_pFrame->iIndex=0;m_bIni=FALSE;}//析構(gòu)函數(shù)CUdpSocket::~CUdpSocket(){}//Donoteditthefollowinglines,whichareneededbyClassWizard.#if0BEGIN_MESSAGE_MAP(CUdpSocket,CAsyncSocket)//{{AFX_MSG_MAP(CUdpSocket)//}}AFX_MSG_MAPEND_MESSAGE_MAP()#endif////CUdpSocketmemberfunctions//初始化網(wǎng)絡BOOLCUdpSocket::Ini(){//已經(jīng)初始化 鹽城工學院本科生畢業(yè)設計說明書(2010)if(m_bIni)//返回returnFALSE;//創(chuàng)建數(shù)據(jù)報類型的套接字if(!this->Create(NULL,SOCK_DGRAM)){//返回returnFALSE;};//設置初始化完成標記m_bIni=TRUE;//返回returnTRUE;}intCUdpSocket::Send(constvoid*lpBuf,intnBufLen,intnFlags){//音頻數(shù)據(jù)序號m_pFrame->iIndex++;//復制音頻格式信息memcpy(m_cBuffer+sizeof(structFrame),lpBuf,nBufLen);//調(diào)用基類SendTo()函數(shù)發(fā)送音頻格式信息returnCAsyncSocket::SendTo(m_pFrame,nBufLen+sizeof(structFrame),TALK_REC_PORT,m_ip,nFlags);}//關(guān)閉套接字BOOLCUdpSocket::CloseSocket(){//已經(jīng)關(guān)閉if(!m_bIni)returnFALSE;//關(guān)閉套接字CAsyncSocket::Close();//設置初始化未完成標記m_bIni=FALSE;//返回returnTRUE;}//設置Ip地址voidCUdpSocket::SetIp(CStringip){m_ip=ip;}//客戶端//ClientSocket.cpp:implementationfile#include"stdafx.h"#include"ClientSocket.h"#include"head.h"#ifdef_DEBUG 鹽城工學院本科生畢業(yè)設計說明書(2010)#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif//CClientSocket//構(gòu)造函數(shù),初始化CClientSocket::CClientSocket(CInterface*pInterFace,CMyWaveIn*pIn,CUdpSocket*pUdp):m_bConnect(FALSE),m_pInterface(NULL),m_pIn(NULL),m_pUdp(NULL){m_pBuffer=newchar[1024];m_pInterface=pInterFace;m_pIn=pIn;m_pUdp=pUdp;}//析構(gòu)函數(shù)CClientSocket::~CClientSocket(){delete[1024]m_pBuffer;}//Donoteditthefollowinglines,whichareneededbyClassWizard.#if0BEGIN_MESSAGE_MAP(CClientSocket,CSocket)//{{AFX_MSG_MAP(CClientSocket)//}}AFX_MSG_MAPEND_MESSAGE_MAP()#endif//0//CClientSocketmemberfunctionsvoidCClientSocket::OnClose(intnErrorCode){//設置關(guān)閉標志m_bConnect=FALSE;//關(guān)閉m_pInterface->BeClose();//調(diào)用基類OnClose()函數(shù)CSocket::OnClose(nErrorCode);}voidCClientSocket::OnReceive(intnErrorCode){structTalkFrame*frame;frame=(structTalkFrame*)m_pBuffer;//接收緩存中的所有TalkFrame結(jié)構(gòu)intiLen=sizeof(structTalkFrame);while(iLen>0){ 鹽城工學院本科生畢業(yè)設計說明書(2010)//接收inti=Receive(m_pBuffer+sizeof(structTalkFrame)-iLen,iLen);//出錯if(i==SOCKET_ERROR)return;iLen-=i;}//如果是非法數(shù)據(jù)就返回if(strcmp(frame->cFlag,"TalkFrame")!=0){//返回return;}//接收緩存中的所有音頻數(shù)據(jù)iLen=frame->iLen;while(iLen>0){//接收inti=Receive(m_pBuffer+sizeof(structTalkFrame)+(frame->iLen-iLen),iLen);//出錯if(i==SOCKET_ERROR)return;//修改循環(huán)標志iLen-=i;}//地址CStringadd;//端口UINTport;switch(frame->iCom){//正常通信幀caseTC_NORMAL_TALK://初始化memset(frame,0,sizeof(structTalkFrame));//設置數(shù)據(jù)幀標志sprintf(frame->cFlag,"TalkFrame");//獲得與此套接字相連的地址和端口GetPeerName(add,port);//處于連接狀態(tài)if(m_pInterface->IsConnect(add)){//設置通信幀標志及其長度frame->iCom=TC_AGREE_TALK;frame->iLen=0;//出錯 鹽城工學院本科生畢業(yè)設計說明書(2010)if(SOCKET_ERROR==Send(m_pBuffer,sizeof(structTalkFrame))){break;};//提示開始通信m_pInterface->TalkStart(add);//設置IP地址m_pUdp->SetIp(add);//允許發(fā)送m_pIn->EnableSend(TRUE);//允許工作m_pInterface->m_bWork=TRUE;break;};//設置通信幀標志frame->iCom=TC_DISAGREE_TALK;//設置通信幀長度frame->iLen=0;//發(fā)送Send(m_pBuffer,sizeof(structTalkFrame));//關(guān)閉Close();break;default:break;//調(diào)用基類OnReceive()函數(shù)CSocket::OnReceive(nErrorCode);}//偵聽//ListenSocket.cpp:implementationfile#include"stdafx.h"#include"ListenSocket.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif//CListenSocket//構(gòu)造函數(shù),用于初始化CListenSocket::CListenSocket(CInterface*pTemp,CMyWaveIn*pIn,CUdpSocket*pUdp):m_sopClient(NULL),m_pIn(NULL),m_pUdp(NULL){m_sopClient=newCClientSocket(pTemp,pIn,pUdp); 鹽城工學院本科生畢業(yè)設計說明書(2010)m_pInterface=pTemp;m_pIn=pIn;m_pUdp=pUdp;}//析構(gòu)函數(shù)CListenSocket::~CListenSocket(){deletem_sopClient;}#if0BEGIN_MESSAGE_MAP(CListenSocket,CSocket)//{{AFX_MSG_MAP(CListenSocket)//}}AFX_MSG_MAPEND_MESSAGE_MAP()#endif//0//CListenSocketmemberfunctions//重載OnAccept()函數(shù)voidCListenSocket::OnAccept(intnErrorCode){//客戶端地址SOCKADDRadd;//客戶端地址長度intiLen;iLen=sizeof(SOCKADDR);//臨時socketCSocketsoTemp;//已經(jīng)連接if(m_sopClient->m_bConnect){//用臨時socket接收連接請求soTemp.Accept(*this);//關(guān)閉soTemp.Close();//返回return;}//接受連接請求if(!Accept(*m_sopClient,&add,&iLen)){//返回return;}//設置連接標記m_sopClient->m_bConnect=TRUE;//調(diào)用基類OnAccept()函數(shù)CSocket::OnAccept(nErrorCode);}//關(guān)閉套接字 鹽城工學院本科生畢業(yè)設計說明書(2010)voidCListenSocket::CloseClient(){//關(guān)閉套接字m_sopClient->Close();//設置未連接標記m_sopClient->m_bConnect=FALSE;}//發(fā)送//SendClient.cpp:implementationfile#include"stdafx.h"#include"SendClient.h"#include"head.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endifCSendClient::CSendClient(CMyWaveIn*pIn,CInterface*pInterface):m_pIn(NULL),m_pInterFace(NULL){m_pBuffer=newchar[1024];m_pIn=pIn;m_pInterFace=pInterface;}CSendClient::~CSendClient(){delete[1024]m_pBuffer;}BEGIN_MESSAGE_MAP(CSendClient,CAsyncSocket)//{{AFX_MSG_MAP(CSendClient)//}}AFX_MSG_MAPEND_MESSAGE_MAP()#endif//0//CSendClientmemberfunctions//重載OnReceive()函數(shù)voidCSendClient::OnReceive(intnErrorCode){structTalkFrame*frame;frame=(structTalkFrame*)m_pBuffer;intiLen=sizeof(structTalkFrame);//接收緩存中所有的TalkFrame結(jié)構(gòu)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)-iLen,iLen); 鹽城工學院本科生畢業(yè)設計說明書(2010)//出錯if(i==SOCKET_ERROR)//返回return;iLen-=i;}//如果不是正常數(shù)據(jù)就返回if(strcmp(frame->cFlag,"TalkFrame")!=0){return;}iLen=frame->iLen;//接收緩存中所有的音頻數(shù)據(jù)while(iLen>0){//接收數(shù)據(jù)inti=Receive(m_pBuffer+sizeof(structTalkFrame)+(frame->iLen-iLen),iLen);//出錯if(i==SOCKET_ERROR)//返回return;iLen-=i;}//對方地址CStringadd;//端口UINTport;switch(frame->iCom){//正常通信幀caseTC_AGREE_TALK://獲取連接對方地址和端口GetPeerName(add,port);//提示開始工作m_pInterFace->TalkStart(add);//允許發(fā)送數(shù)據(jù)m_pIn->EnableSend(TRUE);//設置允許工作標志m_pInterFace->m_bWork=TRUE;break;default:break;}//調(diào)用基類OnReceive()函數(shù)CAsyncSocket::OnReceive(nErrorCode);}voidCSendClient::OnClose(intnErrorCode) 鹽城工學院本科生畢業(yè)設計說明書(2010){//設置連接斷開標志m_bConnect=FALSE;//關(guān)閉m_pInterFace->BeClose();//調(diào)用基類OnClose()函數(shù)CAsyncSocket::OnClose(nErrorCode);}voidCSendClient::OnConnect(intnErrorCode){//獲取連接結(jié)果m_pInterFace->ConnectResult(nErrorCode);//調(diào)用基類OnConnect()函數(shù)CAsyncSocket::OnConnect(nErrorCode);}//接收//RecSocket.cpp:implementationfile#include"stdafx.h"#include"RecSocket.h"#include"head.h"#include"AudioCode.h"#include"WaveOut.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif//CRecSocketexternCAudioCodeg_ACode;externCWaveOut*g_pOut;//構(gòu)造函數(shù)CRecSocket::CRecSocket(){m_bIni=FALSE;m_pFrame=(structFrame*)m_cBuffer;}//析構(gòu)函數(shù)CRecSocket::~CRecSocket(){}#if0BEGIN_MESSAGE_MAP(CRecSocket,CSocket)//{{AFX_MSG_MAP(CRecSocket)//}}AFX_MSG_MAPEND_MESSAGE_MAP()#endif//0//CRecSocketmemberfunctions//初始化 鹽城工學院本科生畢業(yè)設計說明書(2010)BOOLCRecSocket::Ini(){//已經(jīng)初始化if(m_bIni)returnFALSE;//創(chuàng)建數(shù)據(jù)報類型的套接字if(!Create(TALK_REC_PORT,SOCK_DGRAM))returnFALSE;//設置初始化完成標記m_bIni=TRUE;returnTRUE;}voidCRecSocket::OnReceive(intnErrorCode){//接收數(shù)據(jù)長度m_iLen=sizeof(m_cBuffer);//接收數(shù)據(jù)m_iLen=this->Receive(m_pFrame,m_iLen);//排序m_sort.ReceiveData((char*)m_pFrame,m_iLen);//靜態(tài)變量staticinti=0;i++;//調(diào)用基類OnReceive()函數(shù)CSocket::OnReceive(nErrorCode);}//關(guān)閉套接字BOOLCRecSocket::CloseSocket(){//已經(jīng)關(guān)閉if(!m_bIni)returnFALSE;//設置套接字關(guān)閉標記m_bIni=FALSE;//調(diào)用基類Close()函數(shù)CSocket::Close();returnTRUE;}voidCRecSocket::Play(char*pBuffer,intiLen){//解碼輸出長度intiOut;iOut=sizeof(m_cOut);//解碼g_ACode.DecodeAudioData(pBuffer,iLen,m_cOut,&iOut);//播放g_pOut->Play(m_cOut,iOut);}

當前文檔最多預覽五頁,下載文檔查看全文

此文檔下載收益歸作者所有

當前文檔最多預覽五頁,下載文檔查看全文
溫馨提示:
1. 部分包含數(shù)學公式或PPT動畫的文件,查看預覽時可能會顯示錯亂或異常,文件下載后無此問題,請放心下載。
2. 本文檔由用戶上傳,版權(quán)歸屬用戶,天天文庫負責整理代發(fā)布。如果您對本文檔版權(quán)有爭議請及時聯(lián)系客服。
3. 下載前請仔細閱讀文檔內(nèi)容,確認文檔內(nèi)容符合您的需求后進行下載,若出現(xiàn)內(nèi)容與標題不符可向本站投訴處理。
4. 下載文檔時可能由于網(wǎng)絡波動等原因無法下載或下載錯誤,付費完成后未能成功下載的用戶請聯(lián)系客服處理。
大家都在看
近期熱門
關(guān)閉