日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

制作自己的xmpp/gtalk客户端

發(fā)布時(shí)間:2023/12/29 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 制作自己的xmpp/gtalk客户端 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文作者的這個(gè)研究過程跟我的好像,我也在xmpp和libjingle之間輾轉(zhuǎn)研究,用了xmppframework,libjingle,gloox,其中l(wèi)ibjingle我是以前都研究過,所有基于它的P2P進(jìn)行數(shù)據(jù)傳輸這部分沒有問題,也是會(huì)遇到用戶系統(tǒng)的問題,我們需要使用自己的用戶系統(tǒng),又不想建立自己的STUN,而xmppframework這個(gè)又實(shí)現(xiàn)的不完整而且也沒什么資料,所以最后又使用gloox來(lái)實(shí)現(xiàn)消息與數(shù)據(jù)的傳輸。確切的來(lái)講使用了先后使用了libjingle和gloox來(lái)實(shí)現(xiàn)了兩個(gè)不同的項(xiàng)目的不同需求。


[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端

1.[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:07

這里有很多xmpp的開源庫(kù)

http://xmpp.org/software/libraries.shtml

之前我研究了一下QXmpp,是基于qt的

然后又順帶跑去研究了一下qt

先去qt網(wǎng)站上把sdk下載并安裝好,然后用qt creater打開.pro文件進(jìn)行編譯

就可以運(yùn)行里面的example了,這里記住就是安裝路徑和源代碼路徑都不能有中文或者空格

這里能看出qt多么小家子氣

當(dāng)然了,之前接觸qt是通過python的qt庫(kù),這回仔細(xì)看了一下qt的sdk

已經(jīng)QXmpp對(duì)qt的調(diào)用,還是感嘆一下qt確實(shí)是做的很不錯(cuò)的

很多東西都封裝的很好,并且最大的優(yōu)勢(shì)是跨平臺(tái),源代碼只需要到對(duì)應(yīng)平臺(tái)的sdk上編譯一下就可以使用了,不需要任何修改

---------------------------------------------------------------------------------------

但我還是想用純c++來(lái)做,畢竟在qt上寫程序有了通用性缺也得礙手礙腳

所以又找到了gloox 0.9.9.7,這個(gè)是純C++的,并且用VS2008編譯很方便,不需要任何修改

建立一個(gè)靜態(tài)庫(kù)項(xiàng)目,把src里的文件拷貝并包含進(jìn)項(xiàng)目,就可以編譯了,記住不能用定義為UNICODE,否則會(huì)出錯(cuò)

因?yàn)間loox使用的是UTF-8編碼,所以只需要將數(shù)據(jù)轉(zhuǎn)換成UTF-8再傳給gloox處理就可以了,不需要把整個(gè)庫(kù)都改成UNICODE

不過現(xiàn)在正在研究怎么用gloox連接到gtalk服務(wù)器,看上去沒有OXmpp方便

------------------------------------------------------------

吃完盒飯,回來(lái)繼續(xù)研究看問題出在哪

研究了一下gloox的源碼,發(fā)現(xiàn)有點(diǎn)不太好的地方,Client類會(huì)把domain和server搞混

gtalk的domain應(yīng)該是gmail.com,而server應(yīng)該是gtalk.google.com

而Client類都用的同一個(gè),所以之前沒法連接,初始化以后再手動(dòng)改下server地址就可以了

把message_example那個(gè)例子里的

JID jid( "hurkhurk@example.net/gloox" );
j = new Client( jid, "hurkhurks" );?

改成下面的代碼就可以了登陸了

j = new Client("username","password","gmail.com","gtalk",5222);
j->setServer("talk.google.com");

然后用其他賬號(hào)給這個(gè)賬號(hào)發(fā)個(gè)消息,會(huì)收到消息回復(fù)

2.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:10

做了一個(gè)MFC對(duì)話框程序把gloox程序包裝了一下



填寫server domain username password等信息就可以登陸到不同的服務(wù)器了

現(xiàn)在已經(jīng)試驗(yàn)了gtalk和renren網(wǎng)的都沒有問題

右側(cè)為好友列表

下面是收到的消息列表 以及文本信息輸入框



大概的思路是,點(diǎn)擊登陸 把用戶輸入的數(shù)據(jù)獲取過來(lái)然后開啟一個(gè)線程去啟動(dòng)gloox的client服務(wù)

收到消息以后把MessageSession發(fā)送給主界面,當(dāng)界面點(diǎn)擊發(fā)送按鈕的時(shí)候調(diào)用MessageSession::Send發(fā)送消息?

3.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:10

遇到問題了

雖然基本的消息發(fā)送接收已經(jīng)完成了,但是最關(guān)鍵的語(yǔ)音部分還是有問題

之前我看google的文檔有點(diǎn)誤解了google的意思,我以為libjingle是一個(gè)xmpp的語(yǔ)音插件

所以先去找了gloox庫(kù)來(lái)實(shí)現(xiàn)xmpp相關(guān)的內(nèi)容,等功能完善了再來(lái)看libjingle,沒想到libjingle是整個(gè)xmpp解決方案

完全就是gtalk的底層

所以把libjingle找出來(lái)研究了一番,問題很嚴(yán)重,里面采用的語(yǔ)音GISP庫(kù)是不開源的,需要另外下載

那就沒法移植到手機(jī)上了,但還是抱著學(xué)習(xí)的態(tài)度歷經(jīng)千辛萬(wàn)苦到網(wǎng)上把那個(gè)庫(kù)找過來(lái)了

編譯libjingle成功,運(yùn)行call example,一旦打入或者打出電話程序直接異常終止了

難道GISP已經(jīng)過期了?

無(wú)奈繼續(xù)到網(wǎng)上找資料

1、gloox已經(jīng)準(zhǔn)備在下個(gè)版本中集成jingle了,但今年10月份才發(fā)布了1.0版本,這要什么時(shí)候才能等到下個(gè)版本啊。。。

2、有個(gè)德國(guó)人用libjingle+speex語(yǔ)音庫(kù)做了一個(gè)demo叫myjingle,可惜相關(guān)的資源下載地址全部失效了

http://www.bluehands.de/software/beat/myjingle/



實(shí)在沒辦法的話自己動(dòng)手來(lái)實(shí)現(xiàn)libjingle+speex吧

4.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:11

自己動(dòng)手編譯libjingle

編譯的過程中有幾點(diǎn)需要注意:

庫(kù)有沖突,需要把項(xiàng)目屬性->C/C++->代碼生成->運(yùn)行庫(kù) 改成多線程調(diào)試(/MTd)

使用libjingle中example里的xmppthread類進(jìn)行登錄測(cè)試,不成功,直接報(bào)Logged out,截包發(fā)現(xiàn)除了查了下DNS其他壓根什么都沒法出去

使用pcp那個(gè)例子登錄可以成功,里面沒有采用xmppthread類,而是自己的main函數(shù)中寫了個(gè)類似xmppthread過程

但會(huì)把主線程堵死,我想把這個(gè)過程放到另外一個(gè)線程中而不影響程序的主線程

另外開個(gè)線程執(zhí)行pcp的main,成功

登錄成功

5.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:11

研究了兩天的libjingle

了解了sigslot消息機(jī)制,智能指針,多看看這種高手的作品收獲頗多啊

這里是google文檔的一個(gè)粗譯文?http://cyclone.blog.ubuntu.org.cn/2008/01/23/libjingle-create-a-program/

大概懂了libjingle的運(yùn)行機(jī)制,自己重新用mfc+libjingle寫客戶端,已經(jīng)可以監(jiān)聽好友的上線下線狀態(tài)了

但不知道要怎么發(fā)消息,例子里面只提供了文件傳輸和語(yǔ)言,真想不通為了不提供一個(gè)最基本的文本消息收發(fā)的例子

然后找了一整個(gè)下午相關(guān)的資料,翻遍了libjingle的源碼,也沒找到任何發(fā)消息相關(guān)的類、方法

難道libjingle連最基本的消息收發(fā)都要自己寫?

貌似是的,自己集成一個(gè)talk類開始動(dòng)工吧

自己寫了一個(gè)MessageTask類來(lái)截獲消息

主要是重寫XmppTask這兩個(gè)函數(shù)就可以了

bool MessageTask::HandleStanza(const XmlElement * stanza) {
if (stanza->Name() != QN_MESSAGE)
return false;
QueueStanza(stanza);
return true;
}?

int MessageTask::ProcessStart() {
const XmlElement * stanza = NextStanza();
if (stanza == NULL)
return STATE_BLOCKED;
TextMessage msg;?
msg.from_jid = Jid(stanza->Attr(QN_FROM));
const XmlElement * body_element = stanza->FirstNamed(QN_BODY);
if( body_element == NULL)
return STATE_BLOCKED;
msg.body = body_element->BodyText();
SignalRecieveMessage(msg);
return STATE_START;
}

其中TextMessage也是自己寫的一個(gè)容器類

發(fā)消息的話調(diào)用下面就可以了

buzz::XmlElement *message = new buzz::XmlElement(buzz::QN_MESSAGE);
message->AddAttr(buzz::QN_FROM,pump.client()->jid().Str());
message->AddAttr(buzz::QN_TO,status.jid().BareJid().Str());
message->AddAttr(buzz::QN_TYPE,buzz::STR_CHAT);
buzz::XmlElement* bodymsg = new buzz::XmlElement(buzz::QN_BODY);
bodymsg->AddText("I'm here");
message->AddElement(bodymsg);
pump.client()->SendStanza(message);?

真想不通,難道google為了保證文本消息這塊的超強(qiáng)可定制性干脆就不寫了留給別人去寫??

這可是XMPP最基本的功能

6.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:12

libjingle基本消息發(fā)送功能已經(jīng)完成了,正準(zhǔn)備開始往手機(jī)上移至這部分功能了

結(jié)果。。。

我的目的就是想做一個(gè)通用的xmpp協(xié)議客戶端,不只是gtalk,還有校內(nèi)等等所有的xmpp協(xié)議服務(wù)器都能登錄

我測(cè)試了一下,發(fā)現(xiàn)libjingle除了gtalk服務(wù)器,其他一概無(wú)法登錄

網(wǎng)上也有說改saslplainmechanism.h文件的方法來(lái)支持其他服務(wù)器

我試了一下沒用,根本就沒調(diào)用到里面的功能就已經(jīng)中斷了

先是talk.renren.com來(lái)回一個(gè)stream:stream頭就沒下文了

然后是jabber.org,進(jìn)行PLAIN驗(yàn)證的時(shí)候出錯(cuò)了,錯(cuò)誤內(nèi)容:SEC_I_INCOMPLETE_CREDENTIALS

發(fā)現(xiàn)libjingle里面寫著這么一句// We don't support client authentication in schannel.



昨天和gloox那邊通信過了,他們下個(gè)版本中準(zhǔn)備支持jingle,但是沒準(zhǔn)備支持語(yǔ)音

語(yǔ)音的話還是得自己寫,為了保證客戶端的通用性我只能又回頭用gloox了

繞了一個(gè)大圈,回到了原點(diǎn)

7.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:12

重新到網(wǎng)上把最新的gloox1.0下下來(lái)

仔細(xì)的測(cè)試了一下,功能確實(shí)很強(qiáng)大,很方便,很易用

我的做法是開個(gè)子線程來(lái)運(yùn)行g(shù)loox的消息循環(huán),在handle函數(shù)中調(diào)用sendmessage把內(nèi)容發(fā)給主線程

這里采用sendmessage的原因就是保證線程安全

雖然效率是沒有postmessage高,但至少不會(huì)出問題

pc上的測(cè)試完善以后就開始動(dòng)手去移植到wince上了

莫名其妙M8 SDK的time.h里面居然沒有time這個(gè)函數(shù)

只能自己寫了個(gè)mytime.h和mytime.cpp手動(dòng)寫了time函數(shù)加到項(xiàng)目中

接著全部編譯錯(cuò)誤清了以后來(lái)了鏈接錯(cuò)誤

error LNK2019: 無(wú)法解析的外部符號(hào) DnsRecordListFree

等等幾個(gè)dns相關(guān)的函數(shù)全都出問題了

奇怪,到wince6和wince5的sdk目錄下都找了一下,都有windns.h這個(gè)文件,但沒有dnsapi.lib這個(gè)庫(kù)

MSDN上是說在dnsapi.lib里的,難道是wince上收縮到其他庫(kù)里面了?幾乎把其他所有的庫(kù)都加進(jìn)去了還是一樣報(bào)錯(cuò)

奇怪了,難道wince只提供了dns相關(guān)函數(shù)的定義頭文件,沒有l(wèi)ib的實(shí)現(xiàn)?



找到原因了,根據(jù)readme.wince的說明把config.win里面全部的設(shè)置項(xiàng)全部去掉了,其中就有一項(xiàng)HAVE_WINDNS_H是關(guān)鍵

去掉以后就編譯成功了,但編譯出來(lái)的只有dll沒有l(wèi)ib

對(duì)比我新建的動(dòng)態(tài)庫(kù)項(xiàng)目和他自帶的庫(kù)項(xiàng)目發(fā)現(xiàn)時(shí)少了DLL_EXPORT這個(gè)預(yù)處理宏

加上以后再等個(gè)幾分鐘編譯,終于成功了

8.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:13

成功把gloox1.0在wince平臺(tái)下編譯,這里注意一點(diǎn)gloox動(dòng)態(tài)鏈接庫(kù)編譯方式的時(shí)候有個(gè)bug,會(huì)提示gloox.h里面的那些常量 無(wú)法解析的外部符號(hào) 錯(cuò)誤

沒找到原因,簡(jiǎn)單的做法是在自己的項(xiàng)目里添加gloox.cpp

萬(wàn)事ok,寫了個(gè)簡(jiǎn)單的窗口開始進(jìn)行wince上的登錄測(cè)試

問題一大堆

首先,因?yàn)閣ince上編譯的時(shí)候把TLS支持給去掉了,不去掉會(huì)出錯(cuò),而去掉了又沒法登錄gtalk服務(wù)器。。。

然后登錄renren的時(shí)候,因?yàn)楹缶Y不是服務(wù)器地址,所以要這樣寫

JID login_jid;
login_jid.setUsername(這里寫校內(nèi)全名賬號(hào));
login_jid.setServer("talk.renren.com");
login_jid.setResource("xmppforwince");
j = new Client(login_jid,m_sPassWord,m_iPort);
j->setServer("talk.renren.com");?

//?

不支持TLS的問題,是因?yàn)閣ince6不支持兩個(gè)函數(shù)?

InitializeSecurityContextA?

CertVerifyCertificateChainPolicy?

嘗試了一下用第三方庫(kù)去代理系統(tǒng)本身的TLS功能,GUNTLS庫(kù)?

但對(duì)windows開放支持不是太好,主要是linux平臺(tái)的東西,要研究又得浪費(fèi)很多時(shí)間?

所有又把眼光放回著兩個(gè)函數(shù)身上,因?yàn)楸容^奇怪的是wince6并不是完全沒有這兩個(gè)函數(shù)?

在頭文件里面都寫著的,但奇怪的是庫(kù)文件里面沒有,所以是導(dǎo)致的鏈接錯(cuò)誤?

我想會(huì)不會(huì)可能系統(tǒng)本身的dll里已經(jīng)帶了呢?

于是把wince6內(nèi)核解包,然后用010Editor工具搜?

果然找到了InitializeSecurityContextA函數(shù)在schannel.dll里面?

可是任然沒有CertVerifyCertificateChainPolicy這個(gè)函數(shù)?

我看了下CertVerifyCertificateChainPolicy這個(gè)函數(shù)主要是進(jìn)行證書認(rèn)證返回一個(gè)bool?

就干脆把它注釋掉了,應(yīng)該影響不會(huì)太大?

然后用動(dòng)態(tài)載入dll的方法去使用InitializeSecurityContextA函數(shù)?

HINSTANCE hInst;
hInst = LoadLibrary(L"schannel.dll");
typedef SECURITY_STATUS (_stdcall *INITPROC)(PCredHandle phCredential,
PCtxtHandle phContext,?
SEC_CHAR SEC_FAR* pszTargetName,?
ULONG fContextReq,
ULONG Reserved1,?
ULONG TargetDataRep,?
PSecBufferDesc pInput,?
ULONG Reserved2,?
PCtxtHandle phNewContext,?
PSecBufferDesc pOutput,
ULONG SEC_FAR* pfContextAttr,?
PTimeStamp ptsExpiry?
);
INITPROC Initlsc = (INITPROC)GetProcAddress(hInst,L"InitializeSecurityContextA");
ASSERT(Initlsc);
error = Initlsc( (PCtxtHandle)&m_credHandle,
(PCtxtHandle)0,
hname,
request,
0,
SECURITY_NETWORK_DREP,
0,
0,
&m_context,
&obufs,
&return_flags,
NULL );
FreeLibrary(hInst);?

好啦 這下gloox庫(kù)終于能在wince6上支持TLS了

9.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:13

由于gloox本身對(duì)于服務(wù)器地址和域名不同的情況支持不好

比如gtalk就是,服務(wù)器地址是talk.google.com而域是gmail.com

所以我準(zhǔn)備自己來(lái)對(duì)gloox進(jìn)行改造一下

把JID這個(gè)類徹底改了一下,就只需要username這個(gè)屬性存儲(chǔ)全部用戶名,而廢掉domain屬性

因?yàn)閱渭兊男薷膸讉€(gè)提交domain的地方會(huì)導(dǎo)致身份驗(yàn)證加密那邊會(huì)運(yùn)算出錯(cuò)

等等等等改了好多地方,終于完美的支持了gtalk和人人網(wǎng)的登錄了

然后整體程序的框架也出來(lái)了

現(xiàn)在主要是3個(gè)窗口:登錄、主窗口、聊天

因?yàn)間loox的handle機(jī)制,就是首先對(duì)你關(guān)心的事件進(jìn)行注冊(cè)

然后再實(shí)現(xiàn)相關(guān)的借口,一些handle函數(shù)

當(dāng)發(fā)生事件時(shí),比如好友發(fā)來(lái)消息的時(shí)候,gloox就會(huì)自動(dòng)調(diào)用messagehandle事件

所以只需要把自己的代碼寫在handle函數(shù)里讓gloox線程調(diào)用就可以了

我之前的想法是另外寫個(gè)類專門做handle的容器,然后再在handle事件發(fā)生時(shí)用消息的形式通知前臺(tái)窗口

后來(lái)覺得這樣太麻煩了,所以直接讓窗口類繼承了那些handle接口,直接處理

首先登錄窗口就不需要了,登錄窗口只是收集用戶輸入的登錄數(shù)據(jù)然后告訴主窗口

主窗口去啟動(dòng)一個(gè)后臺(tái)線程運(yùn)行g(shù)loox

本來(lái)是準(zhǔn)備把消息的處理的messagehandle直接注冊(cè)到聊天窗口上去

但后來(lái)發(fā)現(xiàn)這樣做會(huì)導(dǎo)致永遠(yuǎn)手不到別人發(fā)的第一條消息

原因是注冊(cè)太慢,新建聊天窗口的過程太慢,導(dǎo)致消息已經(jīng)過了,還沒有注冊(cè)handle函數(shù)

所以改成了全部由主窗口去接受所有人發(fā)的消息,用一個(gè)容量類裝著,這個(gè)容器類里面主要是個(gè)map<string,list<msg>>

可以通過用戶的JID去找到所有的聊天記錄

新建聊天窗口的時(shí)候直接從map容器里面讀取之前的消息,新收到的消息會(huì)有主窗口來(lái)處理,如果是當(dāng)前聊天窗口的,就發(fā)送過來(lái),不是就先儲(chǔ)存起來(lái)

10.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:13

基于gloox的xmpp for m8初步已經(jīng)完工了

現(xiàn)在已經(jīng)可以很方便的添加好友,聊天

下一步是做文件傳輸,但一開始就碰釘子了

gloox1.0里面提供的文件傳輸功能好像是xmpp協(xié)議本身的擴(kuò)展

而gtalk支持的文件傳輸是jingle,雖然jingle也被xmpp作為擴(kuò)展被接受,但是這是兩個(gè)不同的東西

所以貌似gloox現(xiàn)在還無(wú)法給gtalk發(fā)文件

用psi試驗(yàn)了一下,確實(shí)psi無(wú)法和gtalk 人人桌面之前相互發(fā)送文件

但是psi自身之前是可以的,這說明不需要服務(wù)器的特殊支持,而只是客戶端都同時(shí)支持就能夠發(fā)現(xiàn)了

所以就算不能讓xmpp for m8和gtalk 人人桌面之前文件傳輸?shù)幕ネ?br />
但至少可以讓都用xmpp for m8登陸的人之前傳輸文件,當(dāng)然啦,還以讓登陸psi或者其他第三方xmpp客戶端之間發(fā)送文件

但國(guó)內(nèi)基本上沒什么人用,所以可以忽略



下面是文件傳輸試驗(yàn)過程中遇到的一些問題字節(jié)處理方便的問題和解決方案

最開始我是使用ofstream進(jìn)行文件讀寫的,收到數(shù)據(jù)以后然后用ofstream<<data.c_str()的形式把字節(jié)流寫入文件

但問題是傳輸文本文件沒有問題,但傳輸圖片的時(shí)候,本來(lái)13K的圖片就剩下了4K

后來(lái)想明白了,是因?yàn)?lt;<這種流寫入的形式碰到0就會(huì)停止,而實(shí)際上還沒寫完data

所以改成了ofstream.write(data.c_str(),data.length())的形式寫入

文件大小沒有問題了,傳過來(lái)以后也是13K,但圖片確依然打不開

我用ultraedit仔細(xì)對(duì)比了源文件和接受后的文件,發(fā)現(xiàn)里面的10前面全被加了一個(gè)13

看樣子是ofstream進(jìn)行了自動(dòng)的回車符替換了

然后知道是因?yàn)樾枰褂枚M(jìn)制文件讀取的方式才能防止回車符自動(dòng)被替換打開文件的時(shí)候加上這個(gè)屬性fstream::binary

但結(jié)果依然不行,文本文件傳輸沒有問題,但圖片文件寫入的時(shí)候還是會(huì)導(dǎo)致編碼莫名其妙被篡改了

難道是因?yàn)閡tf-8和ANSI的問題?但因?yàn)槲业某绦蛑芯幋a轉(zhuǎn)換的模塊沒法轉(zhuǎn)換中間含有0的字符串

所以只能放棄用ofstream改用

FILE *mStream

fwrite(data.c_str(), data.length(),1, mStream);

fclose(mStream);

這種形式,終于完美的傳輸了文件

-----------------------------------------------------------

上面是接受,下面是發(fā)送了

例子里面看上去也挺復(fù)雜的

gloox首先得綁定一下自己的IP,然后再gloox的主消息循環(huán)里面也寫了一堆代碼

但運(yùn)行的時(shí)候有好幾點(diǎn)要注意的

首先是gtalk的特殊性,會(huì)在綁定資源以后改寫你的resouce,比如你要綁定的是"myresource"

而綁定成功后會(huì)改寫成myresource0F91240D的形式

這個(gè)在gloox中有處理,會(huì)自動(dòng)改寫成服務(wù)器返回的resouce

但在例子中就有問題了,這句

f->addStreamHost( j->jid(), "211.103.98.203", 6666 );

在運(yùn)行的時(shí)候jid的resouce還沒有被改寫,這時(shí)候就會(huì)造成503錯(cuò)誤

所以我把這句放在了onConnect里面

然后是發(fā)送給對(duì)方的jid需要是全名的,需要包括資源名在內(nèi)的,如果只寫了bare,那么會(huì)報(bào)501錯(cuò)誤

解決了上面的問題就可以成功發(fā)送文件了

11.Re:[轉(zhuǎn)貼]制作自己的xmpp/gtalk客戶端?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:14

之前一篇文章寫完后,發(fā)現(xiàn)只能兩個(gè)客戶端在同一網(wǎng)段內(nèi)才能收發(fā)文件

原來(lái)bytestream這個(gè)協(xié)議沒有穿透能力

如果需要跨網(wǎng)跨防火墻進(jìn)行傳輸文件就必須要文件中轉(zhuǎn)站(這不是廢話嘛,不然不都用飛鴿去了)

socket5 bytestream 大概的工作原理是這樣

首先進(jìn)行一些前戲,發(fā)送文件方和接受方溝通溝通,協(xié)商了好了以后,發(fā)送方就會(huì)發(fā)起一個(gè)iq,內(nèi)容如下?

<iq to='lomiou@jabber.org/proxy.netlab.cz' from=zhuliye@gmail.com/gtalk583984' id='uid:4b32d84e:000072ae' type='set' xmlns='jabber:client'>
<query xmlns='http://jabber.org/protocol/bytestreams' sid='uid:4b32d84e:0000701f' mode='tcp'>
<streamhost jid=zhuliye@gmail.com/gtalk583984' host='10.10.10.113' port='7777'/>
<streamhost jid='proxy.eu.jabber.org' host='91.121.109.155' port='7777'/>
</query></iq>

其中可以有多個(gè)streamhost節(jié)點(diǎn),就是告訴接收方有這么些個(gè)文件中轉(zhuǎn)服務(wù)器可以使用

首先別忘了把自己的jid 和ip地址寫上去,因?yàn)槟銈兛赡芴幱谕痪W(wǎng)段,就沒必要使用中轉(zhuǎn)服務(wù)器了

然后另外再找一些可用的中轉(zhuǎn)服務(wù)器

這里需要利用server discovery來(lái)尋找,具體請(qǐng)參考http://xmpp.org/extensions/xep-0065.html

找到以后把相關(guān)信息填上作為一個(gè)streamhost節(jié)點(diǎn),多幾個(gè)比較好,一個(gè)出問題其他的還能頂上



然后接收方收到這個(gè)xml流就會(huì)對(duì)streamhost一一嘗試連接,直到找到一個(gè)可以連得通的

然后就會(huì)回復(fù)下面的內(nèi)容給發(fā)送方
<iq from='bottlerun@jabber.org/proxy.netlab.cz' to='bottlerun@gmail.com/xmppform850286462' xml:lang='en' type='result' id='uid:4b32d84e:000072ae'>
<query xmlns='http://jabber.org/protocol/bytestreams'>
<streamhost-used jid='proxy.eu.jabber.org'/></query></iq>

這里就一個(gè)streamhost,就是告訴發(fā)送方自己的選擇,然后發(fā)送方和接收方就會(huì)同時(shí)和這個(gè)streamhost建立連接,一邊發(fā)一邊收了



但使用SOCKS5Bytestream有個(gè)細(xì)節(jié)要注意,不使用中轉(zhuǎn)直接發(fā)的話很正常,但如果用了中轉(zhuǎn)的話就會(huì)出現(xiàn)一個(gè)問題

發(fā)送方是先把數(shù)據(jù)發(fā)送給中轉(zhuǎn)服務(wù)器,而中轉(zhuǎn)服務(wù)器再發(fā)送給接收方的,這里就會(huì)形成一個(gè)異步

發(fā)送方把數(shù)據(jù)發(fā)送完畢以后,按例子中就直接關(guān)閉連接了,而這時(shí)候接收方確還沒有接受完

但又接受到發(fā)送方的斷開連接的通知,因此就會(huì)導(dǎo)致傳輸出錯(cuò)

所以我改成了:發(fā)送方發(fā)送完畢后不接受,接收方直到接受

而這樣還是會(huì)有問題,發(fā)送方如果不在發(fā)送完畢后斷開連接,就不知道該在什么時(shí)候斷開了

因?yàn)榻邮辗浇邮芡戤呉院?#xff0c;即時(shí)關(guān)閉連接,發(fā)送方也不會(huì)受到任何通知(這里我也很奇怪,為什么發(fā)送方斷開連接的時(shí)候,接收方也會(huì)斷開,但接收方斷開的時(shí)候發(fā)送方?jīng)]任何通知)

就會(huì)導(dǎo)致發(fā)送方一直處于發(fā)送中狀態(tài)

最后的做法是,在發(fā)送方使用send發(fā)送數(shù)據(jù)以后再調(diào)用一次recv(1),這樣就可以檢測(cè)到接收方是否已經(jīng)關(guān)閉了

12.制作自己的xmpp/gtalk客戶端12之In-Band和Out-of-Band?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:15

今天一直在看xmpp協(xié)議相關(guān)的擴(kuò)展協(xié)議文件?http://xmpp.org/extensions

想找更多的關(guān)于jingle的資料,搞明白了一些事情

之前有點(diǎn)奇怪,jingle可以用來(lái)傳輸數(shù)據(jù),包括多媒體,文件共享等等

但socket5 bytestream也是實(shí)現(xiàn)這個(gè)功能,那xmpp協(xié)議同時(shí)要這兩個(gè)擴(kuò)展干嘛?只是提供更豐富的連接方式嗎?

后來(lái)搞明白,socket5 bytestream和jingle是兩個(gè)不同的概念

jingle主要的作用是利用ICE和STUN等技術(shù)實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)的連接的一種解決方案

而連接方式和傳輸內(nèi)容是分離的,socket5 bytestream就是其中一種tcp的連接方式,另外還有UDP、in-band等方式

而內(nèi)容也可以是各種數(shù)據(jù),文件 多媒體數(shù)據(jù)等等

理論上不需要任何服務(wù)器的額外支持,也不需要像單純的使用socket5 bytestream那樣需要中轉(zhuǎn)服務(wù)器

只需要兩個(gè)客戶端都支持jingle,就可以實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)傳輸

如果連不上的話也可以利用第三方的stun服務(wù)器進(jìn)行連接



這里又多出一個(gè)概念I(lǐng)n-Band,可以翻譯成“帶內(nèi)”,和它對(duì)應(yīng)的是 Out-Of-Band“帶外”

http://xmpp.org/extensions/xep-0047.html

所謂In-Band就是把需要傳輸?shù)臄?shù)據(jù)轉(zhuǎn)換成字節(jié)碼的形式用Xmpp協(xié)議的形式比如 iq 或者 message節(jié)點(diǎn)發(fā)出去

就是用的XMPP協(xié)議走的通道傳輸附加數(shù)據(jù),所以稱為帶內(nèi)

而“帶外”就是socket5 bytestream這種形式,先利用xmpp進(jìn)行協(xié)商,然后另外去建立一個(gè)socket連接

進(jìn)行數(shù)據(jù)傳輸,這種一般是利用第三方的proxy中轉(zhuǎn)服務(wù)器,好處是不占用xmpp服務(wù)器的資源

因?yàn)榇蠹叶加肐n-Band方式來(lái)收發(fā)文件的話,會(huì)把XMPP服務(wù)器拖垮的

所以文檔中寫到

Generally, in-band bytestreams SHOULD be used only as a last resort. SOCKS5 Bytestreams will almost always be preferable.?
A server MAY rate limit a connection, depending on the size and frequency of data packets.?
A server MAY disconnect a connection that sends overly large packets as defined by server policy.?
It is RECOMMENDED to use a 'block-size' of 4096.?


看了一下gloox目錄下有InBandBytestream相關(guān)的類,以及一個(gè)ibb_excample,一會(huì)試試看怎么樣



現(xiàn)在我的程序文件傳輸基本上用socket5 bytestream解決了

接下來(lái)是語(yǔ)言了,剛剛和gloox協(xié)議庫(kù)的開發(fā)者交流了一下,下一個(gè)版本正在開發(fā)中并將支持jingle

但是需要等到明年2月到5月才能發(fā)布

看了一下jingle那么多復(fù)雜的技術(shù)ICE STUN等等

要自己來(lái)實(shí)現(xiàn)有點(diǎn)不太可能了,而現(xiàn)在正在開發(fā)的gloox源碼中雖然已經(jīng)有了不少jingle相關(guān)的類

但聽gloox開發(fā)者說目前還沒法用

所以我想先試試看In-Band方式來(lái)實(shí)現(xiàn)試試傳輸語(yǔ)言數(shù)據(jù)吧

這樣首先就放棄了和其他客戶端的通用性,當(dāng)然目前好像也只有g(shù)talk支持jingle吧,

其他的客戶端我看連文件傳輸都沒怎么支持好

比如psi的文件發(fā)送居然不支持中轉(zhuǎn)服務(wù)器,同樣的也不支持jingle,照樣發(fā)布的好好的

上次看到一篇文章說語(yǔ)言每秒鐘能壓縮到5K就夠了

如果In-Band支持不了那么大流量的話也可以進(jìn)行一些功能上的縮減

比如把實(shí)時(shí)的語(yǔ)音換成對(duì)講機(jī)的形式,按住鍵說一句話,對(duì)方等傳完的聽完了再按住鍵回復(fù)一句話這樣子

當(dāng)然啦,如果In-Band實(shí)在沒法支持也可以利用傳輸文件用的那些個(gè)服務(wù)器來(lái)進(jìn)行數(shù)據(jù)中轉(zhuǎn)

根據(jù)今天和別人手機(jī)對(duì)發(fā)消息的經(jīng)驗(yàn)來(lái)看,速度還是不錯(cuò)的,GPRS本身速度也是個(gè)限制

但問題是延遲比較大,所以還是實(shí)時(shí)性會(huì)比較差



如果網(wǎng)絡(luò)方面的問題都解決了,接下來(lái)就是要去解決語(yǔ)言的采集、壓縮和播放了

13.NAT穿越原理——STUN?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:16

NAT穿越原理——STUN
知道了jingle是采用STUN技術(shù)來(lái)實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)的連接,因此到網(wǎng)上把STUN相關(guān)的資料找了過來(lái)?

轉(zhuǎn)自:http://www.yuanma.org/data/2007/0323/article_2446.htm?

STUN是RFC3489規(guī)定的一種NAT穿透方式,它采用輔助的方法探測(cè)NAT的IP和端口。毫無(wú)疑問的,它對(duì)穿越早期的NAT起了巨大的作用,并且還將繼續(xù)在ANT穿透中占有一席之地。?

STUN的探測(cè)過程需要有一個(gè)公網(wǎng)IP的STUN server,在NAT后面的UAC必須和此server配合,互相之間發(fā)送若干個(gè)UDP數(shù)據(jù)包。UDP包中包含有UAC需要了解的信息,比如NAT外網(wǎng) IP,PORT等等。UAC通過是否得到這個(gè)UDP包和包中的數(shù)據(jù)判斷自己的NAT類型。?

假設(shè)有如下UAC(B),NAT(A),SERVER(C),UAC的IP為IPB,NAT的IP為 IPA ,SERVER的 IP為IPC1 、IPC2。請(qǐng)注意,服務(wù)器C有兩個(gè)IP,后面你會(huì)理解為什么需要兩個(gè)IP。?

(1)NAT的探測(cè)過程:(吃個(gè)芒果先,呵呵,老媽給的)?

STEP1:B向C的IP1的pot1端口發(fā)送一個(gè)UDP 包。C收到這個(gè)包后,會(huì)把它收到包的源IP和port寫到UDP包中,然后把此包通過IP1和port1發(fā)還給B。這個(gè)IP和port也就是NAT的外網(wǎng) IP和port(如果你不理解,那么請(qǐng)你去看我的BLOG里面的NAT的原理和分類),也就是說你在STEP1中就得到了NAT的外網(wǎng)IP。?

熟悉NAT工作原理的朋友可以知道,C返回給B的這個(gè)UDP包B一定收到(如果你不知道,去讀下我的其它文章)。如果在你的應(yīng)用中,向一個(gè)STUN服務(wù)器發(fā)送數(shù)據(jù)包后,你沒有收到STUN的任何回應(yīng)包,那只有兩種可能:1、STUN服務(wù)器不存在,或者你弄錯(cuò)了port。2、你的NAT拒絕一切UDP包從外部向內(nèi)部通過(我們公司的NAT就是)。?

當(dāng)B收到此UDP后,把此UDP中的IP和自己的IP做比較,如果是一樣的,就說明自己是在公網(wǎng),下步NAT將去探測(cè)防火墻類型,我不想多說。如果不一樣,說明有NAT的存在,系統(tǒng)進(jìn)行STEP2的操作。?

STEP2:B向C的IP1發(fā)送一個(gè)UDP包,請(qǐng)求C通過另外一個(gè)IP2和PORT(不同與SETP1的IP1)向B返回一個(gè)UDP數(shù)據(jù)包(現(xiàn)在知道為什么C要有兩個(gè)IP了吧,雖然還不理解為什么,呵呵)。?

我們來(lái)分析一下,如果B收到了這個(gè)數(shù)據(jù)包,那說明什么?說明NAT來(lái)著不拒,不對(duì)數(shù)據(jù)包進(jìn)行任何過濾,這也就是STUN標(biāo)準(zhǔn)中的full cone NAT。遺憾的是,full cone nat太少了,這也意味著你能收到這個(gè)數(shù)據(jù)包的可能性不大。如果沒收到,那么系統(tǒng)進(jìn)行STEP3的操作。?

STEP3:B向C的IP2的port2發(fā)送一個(gè)數(shù)據(jù)包,C收到數(shù)據(jù)包后,把它收到包的源IP和port寫到UDP包中,然后通過自己的IP2和port2把此包發(fā)還給B。?

和step1一樣,B肯定能收到這個(gè)回應(yīng)UDP包。此包中的port是我們最關(guān)心的數(shù)據(jù),下面我們來(lái)分析:?

如果這個(gè)port和step1中的port一樣,那么可以肯定這個(gè)NAT是個(gè)CONE NAT,否則是對(duì)稱NAT。道理很簡(jiǎn)單:根據(jù)對(duì)稱NAT的規(guī)則,當(dāng)目的地址的IP和port有任何一個(gè)改變,那么NAT都會(huì)重新分配一個(gè)port使用,而在step3中,和step1對(duì)應(yīng),我們改變了IP和port。因此,如果是對(duì)稱NAT,那這兩個(gè)port肯定是不同的。?

如果在你的應(yīng)用中,到此步的時(shí)候PORT是不同的,恭喜你,你的STUN已經(jīng)死了。如果不同,那么只剩下了restrict cone 和port restrict cone。系統(tǒng)用step4探測(cè)是是那一種。?

STEP4:B向C的IP2的一個(gè)端口PD發(fā)送一個(gè)數(shù)據(jù)請(qǐng)求包,要求C用IP2和不同于PD的port返回一個(gè)數(shù)據(jù)包給B。?

我們來(lái)分析結(jié)果:如果B收到了,那也就意味著只要IP相同,即使port不同,NAT也允許UDP包通過。顯然這是restrict cone NAT。如果沒收到,沒別的好說,port restrict NAT.?

(2)SIP怎么使用STUN?

個(gè)人認(rèn)為這是個(gè)很不值得提的問題,不過有許多人問我,還是簡(jiǎn)要提一下。其實(shí)這是個(gè)很簡(jiǎn)單的問題,SIP通過STUN得到NAT的外網(wǎng)IP和SIP的信令監(jiān)聽端口的外網(wǎng)port,替換SIP注冊(cè)包中的contact頭中的IP和port,然后注冊(cè)。這樣就可以確保當(dāng)有人呼叫你的的時(shí)候注冊(cè)服務(wù)器能找到你。需要提醒你的是,NAT發(fā)現(xiàn)一個(gè)連接超過一段時(shí)間后沒有活動(dòng),它就會(huì)關(guān)閉這個(gè)影射,因此你必須間隔一端時(shí)間發(fā)送一個(gè)數(shù)據(jù)包出去以keep alive。?

另外,當(dāng)你要和別人建立RTP通訊的時(shí)候,不要忘記把你的SDP中的IP和PORT改成公網(wǎng)IP和PORT。?

也許文章到這里就可以完了,不過很遺憾,顯然我們還有工作沒有完成,那就是對(duì)稱NAT。在我后面的文章中,我會(huì)對(duì)對(duì)稱NAT對(duì)一些探討,希望你關(guān)注我的BLOG,謝謝。

14.制作自己的xmpp/gtalk客戶端13之語(yǔ)言壓縮——牛X的speex?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:16

要實(shí)現(xiàn)voip需要解決的幾個(gè)問題

語(yǔ)言的采集、壓縮編碼、傳輸、解碼、播放

前面已經(jīng)討論過了傳輸可以先嘗試用In-Band或者類似文件中轉(zhuǎn)的方式試試,暫時(shí)不考慮比較難實(shí)現(xiàn)的jingle

昨天也運(yùn)行了一下In-Band的例子,用gtalk的服務(wù)器也能傳輸數(shù)據(jù),每個(gè)包大概限制在4K的樣子

而奇怪的psi不支持這種傳輸方式,自己用兩個(gè)客服端互相發(fā)沒問題

暫時(shí)先用In-Band作為語(yǔ)言傳輸方式試試吧,因?yàn)楹?jiǎn)單,不需要第三方支持,也不需要穿透NAT之類的

但大規(guī)模應(yīng)用的肯定要把google的服務(wù)器給拖垮了吧

所以只是作為一個(gè)目前試驗(yàn)階段的載體



之前在研究libjingle的時(shí)候?qū)诱业搅薓yjingle的源碼,是德國(guó)人寫的一個(gè)MFC對(duì)jingle的簡(jiǎn)單封裝

說是簡(jiǎn)單。。。其實(shí)很復(fù)雜,我看了老半天也沒怎么看懂,語(yǔ)音那塊太復(fù)雜了

但里面有一點(diǎn)非常不錯(cuò),就是替換掉了libjingle本身用的GISP收費(fèi)語(yǔ)音庫(kù),而是用了免費(fèi)的speex庫(kù)

今天又把speex庫(kù)拿出來(lái)研究了一番

充分體會(huì)到了什么叫神奇啊

我先用windows自帶的錄音機(jī)分別錄了一段說話和一段唱歌,兩個(gè)文件都是10秒鐘,大小都是450多K左右,325kpbs

然后用speex嘗試不同的壓縮率

采用默認(rèn)的壓縮編碼方式,8kHz 質(zhì)量 8 ,壓縮完以后是50K左右,然后解碼后播放

不管是說話還是唱歌,都非常清晰,完全聽不出有任何任何壓縮的痕跡

然后換成16kHz 質(zhì)量8,壓縮完以后是27K的樣子(不要問我16kHz為什么壓縮后比8kHz要小,我也沒明白),解碼后播放

依然都很清晰

再換成32kHz 質(zhì)量2,壓縮后只有8K多(天哪!真小),解碼后播放

會(huì)有雜音,但是聲音本身基本沒什么很大的變化,在每個(gè)字收尾的時(shí)候特別是唱歌時(shí)候拖同一個(gè)音比較長(zhǎng)的時(shí)候會(huì)有點(diǎn)噪音(怪不得說speex不適合壓縮歌曲,而只適合壓縮說話內(nèi)容),但依然還是算很清晰的,完全是可以接受的范圍

至少比手機(jī)打電話時(shí)候的音質(zhì)要好

最后換成32kHz 質(zhì)量0,壓縮后只有5K,解碼后播放

這里就很明顯的聽得出來(lái)壓縮的痕跡了,雜音很重,聲音也很多走樣了,雖然還是能明白說話的內(nèi)容,但體驗(yàn)太差了,放棄



而另外有個(gè)屬性bitrate沒太理解,感覺調(diào)了對(duì)大小和音質(zhì)都影響不大

根據(jù)上面的結(jié)果,采用32kHz 質(zhì)量2來(lái)壓縮,完全夠voip使用了

這里來(lái)計(jì)算一下,10秒的聲音數(shù)據(jù),被壓縮到8K,也就是說每秒只有1K不到

之前有聽說比較成熟的GSM,也就是現(xiàn)在我們的手機(jī)傳輸量就是1K/S左右

語(yǔ)言數(shù)據(jù)數(shù)據(jù)是1K,再加上一些傳輸協(xié)議的消耗,怎么也就是1K多點(diǎn)

現(xiàn)在手機(jī)的GPRS速度,幾K還是很輕松能達(dá)到的,我用的E網(wǎng),更是經(jīng)常能達(dá)到20K速度,最快的時(shí)候甚至能突破30

所以基于2G手機(jī)的GPRS來(lái)實(shí)現(xiàn)VOIP,傳輸速度絕對(duì)不會(huì)算是個(gè)瓶頸

主要還是高延遲,體驗(yàn)方面可能會(huì)比較差



下面要做的是自己寫程序來(lái)實(shí)現(xiàn)編碼,之前測(cè)試是用speex提供的程序

然后把speex移植到wince上,好像speex本身就是跨平臺(tái)產(chǎn)品

(本來(lái)就是把一堆0101運(yùn)算成另一堆0101的程序,沒涉及到任何和系統(tǒng)有關(guān)的東西,當(dāng)然很容易跨平臺(tái)啦)

還有就是語(yǔ)言采集和播放,到網(wǎng)上找了一個(gè)源碼利用waveInAddBuffer相關(guān)的函數(shù),還挺好用的

而且在手機(jī)上也運(yùn)行成功了

那么多人罵微軟,卻都看不到微軟的優(yōu)點(diǎn)啊,pc上的程序,幾乎只要進(jìn)行很少的修改,甚至不用修改,就可以直接用wince的sdk編譯通過

這才是大公司大手筆啊,通用性這么高,大大減少了開發(fā)者的時(shí)間,而且文檔,函數(shù)都是通用的,學(xué)習(xí)也很方便

15.基于XMPP協(xié)議的網(wǎng)絡(luò)游戲開發(fā)?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:17

今天突然就想到的點(diǎn)子

之前看到google app engine已經(jīng)提供xmpp協(xié)議的支持的了,我想了好久也沒想到可以用這個(gè)干嗎

服務(wù)器上隨時(shí)開著一個(gè)gtalk賬號(hào),客戶端發(fā)送消息過去,服務(wù)器進(jìn)行一些處理然后再可以回復(fù)一些消息

就這樣可以干嘛呢,一些服務(wù)提供?輸出一個(gè)列表,告訴客戶端輸入1可以看什么,輸入2可以干嘛,輸入m返回主界面?

客戶端通過向某個(gè)服務(wù)器上開著的好友發(fā)送消息來(lái)更新自己的微博?

總舉得這些個(gè)功能有點(diǎn)雞肋

但前端時(shí)間看到說google wave也是基于xmpp協(xié)議的,只不過不像gtalk,xmpp協(xié)議只是作為底層,用于當(dāng)做消息的載體

而更高一層另外還有協(xié)議

所以我突然想到能不能我也來(lái)把xmpp協(xié)議作為一個(gè)載體,另外去開發(fā)一層更高層的協(xié)議實(shí)現(xiàn)游戲通信呢

大概原理是這樣

用戶采用gtalk賬號(hào)登陸游戲客戶端(因?yàn)楝F(xiàn)在gae只支持gtalk賬號(hào))

登陸成功后列出房間列表,用戶選擇房間1,則自動(dòng)加“room1@gmail.com”為好友

room1@gmail.com收到用戶添加好友的消息,就知道有用戶進(jìn)房間了

room1@gmail.com就把當(dāng)前房間所有的游戲桌信息通過xmpp消息的形式發(fā)送給用戶(用戶是幾個(gè)幾個(gè)在一個(gè)桌子上玩的)

并且還可以發(fā)送一些其他消息,比如所有在線的好友列表(既當(dāng)前房間的在線玩家),發(fā)送給該用戶

客戶端把收到的該房間所有的游戲桌狀態(tài)列表給用戶看,用戶選擇一個(gè)游戲桌選擇進(jìn)入,客戶端發(fā)送一條消息告訴room1@gmail.com用戶選擇的房間

room1@gmail.com就把用戶選擇的游戲桌上所有的玩家列表發(fā)送給用戶

當(dāng)所有的玩家都把準(zhǔn)備完畢的消息告訴room1@gmail.com以后,room1@gmail.com就會(huì)給每個(gè)人發(fā)送一條消息告訴大家游戲開始

到這里為止,服務(wù)器的任務(wù)就OK了,一直到游戲結(jié)束前,服務(wù)器都不需要再和這個(gè)游戲桌上的用戶交互

玩家之間自己相互發(fā)送消息就可以了

比如飛行棋,玩家1擲骰子點(diǎn)數(shù)是3,然后就分別發(fā)3條消息給3個(gè)對(duì)手,告訴對(duì)方自己的點(diǎn)數(shù)

并且把選擇走的棋子發(fā)消息告訴3個(gè)對(duì)手,只需要這6條消息,就完成了一個(gè)玩家的操作過程

然后其他幾個(gè)玩家的客戶端根據(jù)收到的消息來(lái)繪制界面就行了

游戲結(jié)束后,玩家發(fā)一條消息告訴room1@gmail.com已經(jīng)結(jié)束游戲,room1@gmail.com再把最新的房間內(nèi)游戲桌信息發(fā)送給客戶就行了



這里的優(yōu)點(diǎn)很明顯:

用戶和服務(wù)器端的交互很少,服務(wù)器只負(fù)責(zé)幫用戶找到玩家,接下來(lái)只需要玩家之間相互通信就可以了

大大減少了服務(wù)器的負(fù)擔(dān)(當(dāng)然沒有減輕gtalk服務(wù)器的負(fù)擔(dān),不過gtalk應(yīng)該還是能抗住的)

成本很簡(jiǎn)單,初期運(yùn)營(yíng)的時(shí)候google app engine免費(fèi)的服務(wù)器會(huì)非常方便,當(dāng)然gtalk也是免費(fèi)的



缺點(diǎn)也很明顯:

對(duì)游戲有要求,只能是那種對(duì)實(shí)時(shí)性要求不高的游戲,比如飛行棋,撲克牌,象棋,五子棋等等

因?yàn)閤mpp傳輸需要消耗的時(shí)間還是挺長(zhǎng)的



還有個(gè)問題就是room1@gmail.com的好友是有上限的,所以我想到的做法是用戶加入房間既加為好友,用戶退出房間既刪除好友

這樣保持所有好友都是在線的,好友上限正好是房間上限,一個(gè)房間幾百個(gè)人還是夠了的

但不知道這么頻繁的增刪好友會(huì)不會(huì)被gtalk給盯上啊

16.制作自己的xmpp/gtalk客戶端14之語(yǔ)言的采集和編碼?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:17

一直嘗試著自己去手動(dòng)寫speex的編碼和解碼

因?yàn)槲矣X得沒有必要搞跟speex自帶的編碼解碼程序那么復(fù)雜

這里我使用的是speex1.0.5的源碼版本

首先把libspeex項(xiàng)目用vs2008直接打開編譯一下就可以了,如果要編譯那兩個(gè)編碼解碼的項(xiàng)目需要下載ogg庫(kù),是一種文件格式庫(kù)

拿到所有的頭文件和lib文件拷貝到程序目錄下面

用windows錄音機(jī)錄一個(gè)幾秒鐘的語(yǔ)言文件

然后編寫語(yǔ)言編碼代碼如下

FILE *fin,*fout;
short in[MAX_FRAME_SIZE];
float input[MAX_FRAME_SIZE];
char cbits[MAX_FRAME_SIZE];
int nbBytes;
void *state;
SpeexBits bits;
state = speex_encoder_init(&speex_nb_mode);//設(shè)置壓縮模式
int quality=8;
int frame_size;
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE,&frame_size );//這個(gè)值獲取到一般都是160
speex_encoder_ctl(state, SPEEX_SET_QUALITY, &quality);//設(shè)置壓縮質(zhì)量
fin = fopen("hello.wav", "rb");//打開語(yǔ)言文件
fout = fopen("encode.speex","wb");//創(chuàng)建要輸出的編碼文件
int format,rate,channels,size;
char file_type[12];
fread(file_type, 1, 12, fin);//把wav文件頭12個(gè)字節(jié)讀出來(lái)
read_wav_header(fin,&rate,&channels,&format,&size);//分析wav頭文件,獲取相關(guān)的信息,默認(rèn)rate是22050,channels是1,format是16
speex_bits_init(&bits);
while (1)
{
fread(in, sizeof(short), frame_size, fin);//讀取一段出來(lái)
if (feof(fin))
break;
speex_bits_reset(&bits);//初始化SpeexBits?
speex_encode_int(state, in, &bits);//最關(guān)鍵的一句,進(jìn)行編碼,輸出到bits
nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_SIZE);//把bits拷貝到cbits數(shù)組
fwrite(&nbBytes, sizeof(int), 1, fout);//將把該段編碼后的大小寫入文件,按我這種配置編碼后是38
fwrite(cbits, 1, nbBytes, fout);//將編碼后的該段內(nèi)容寫入文件
}
speex_encoder_destroy(state);//清理
speex_bits_destroy(&bits);
fclose(fin);
fclose(fout);?

下面是解碼代碼,跟上面一樣的就不多說了

FILE *fin,*fout;
float output_frame[MAX_FRAME_SIZE];
char cbits[MAX_FRAME_SIZE];
short char_out[MAX_FRAME_SIZE];
void *dec_state;
SpeexBits bits;
speex_bits_init(&bits);
dec_state = speex_decoder_init(&speex_nb_mode);
int quality=8;
int frame_size;
speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE,&frame_size );
speex_decoder_ctl(dec_state, SPEEX_SET_QUALITY, &quality);
fin = fopen("encode.speex", "rb");
fout = fopen("decode.wav","wb");
int format,rate,channels,size;
format = 16;
channels = 1;
rate = 22050;
size = 0;
write_wav_header(fout, rate, channels, format, size);//寫入文件頭
speex_bits_init(&bits);
while (1)
{
int this_frame_size;
fread(&this_frame_size, sizeof(int), 1, fin);//讀取該段大小
fread(cbits, 1, this_frame_size, fin);//讀取編碼
if (feof(fin))
break;
speex_bits_read_from(&bits, cbits, this_frame_size);//將編碼內(nèi)容寫入bits
speex_decode_int(dec_state, &bits, char_out);//解碼
fwrite(char_out, sizeof(short), frame_size, fout);
}
speex_bits_destroy(&bits);
speex_decoder_destroy(dec_state);
fclose(fin);
fclose(fout);

這里是把事先錄好的聲音文件轉(zhuǎn)碼,然后再把轉(zhuǎn)碼文件解碼

接下來(lái)要做的就是做成實(shí)時(shí)錄音轉(zhuǎn)碼,然后再試試解碼并播放了

錄音要用到waveInAddBuffer和相關(guān)的函數(shù),功能是把音頻數(shù)據(jù)輸出到指定內(nèi)存塊

而播放要用到waveOutWrite相關(guān)的函數(shù),功能是把內(nèi)存中的音頻數(shù)據(jù)發(fā)送給聲卡進(jìn)行播放

用這兩個(gè)函數(shù)的時(shí)候一定要用緩存技術(shù),我的做法是建立10個(gè)WAVEHDR結(jié)構(gòu)

初始化的時(shí)候先把這10個(gè)結(jié)構(gòu)都填上數(shù)據(jù),然后再不斷的循環(huán)去讀取音頻數(shù)據(jù)

for(;;){
while (pWaveHdr[nhdr]->dwFlags & WHDR_DONE){
printf("do some output: %d!\n", nhdr);
int offset, writed=0;
int length = pWaveHdr[nhdr]->dwBytesRecorded;
for (offset = 0; writed >= 0 && offset < length; offset += writed){
writed = fwrite(pWaveHdr[nhdr]->lpData+offset, 1, length-offset, fp);
printf("write: %d\n", writed);
}
error = waveInAddBuffer(hWaveIn, pWaveHdr[nhdr], sizeof(WAVEHDR));?
if (error != MMSYSERR_NOERROR){
printf("waveInAddBuffer error\n");
return -1;
}
nhdr = (nhdr+1)%HDRCOUNT;
}
}

這里就利用pWaveHdr[nhdr]->dwFlags這個(gè)標(biāo)志,因?yàn)閣aveInAddBuffer和waveOutWrite都是異步的

就靠判斷pWaveHdr[nhdr]->dwFlags是不是等于WHDR_DONE來(lái)得知是否執(zhí)行完畢

播放聲音也是一樣,先在初始化的時(shí)候先調(diào)用waveOutPrepareHeader再把dwFlags 標(biāo)志全置為WHDR_DONE,

for(;;){
while (pWaveHdr[nhdr]->dwFlags & WHDR_DONE){
printf("do some output: %d!\n", nhdr);?
if(feof(fp))
break;
error = waveOutWrite(waveout, pWaveHdr[nhdr], sizeof(WAVEHDR));
if (error != MMSYSERR_NOERROR){
printf("waveOutWrite \n");
return -1;
}
int size = fread(pWaveHdr[nhdr]->lpData,1,frame_size,fp);
pWaveHdr[nhdr]->dwBufferLength =size;
nhdr = (nhdr+1)%HDRCOUNT;
}
}

17.制作自己的xmpp/gtalk客戶端15之語(yǔ)音功能移植到wince上?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:18

PC上將語(yǔ)音采集、編碼、解碼、播放功能全做好以后開始往wince平臺(tái)移植了

移植的過程困難重重啊

首先就是采集,我之前有一篇文章還夸微軟大公司,產(chǎn)品通用性好呢

結(jié)果奇怪的是,我前一天把語(yǔ)音采集用到的相關(guān)wavein的那段代碼在wince上運(yùn)行還好好的,錄音完美

但第二天怎么試都不行了,只錄下來(lái)了雪花聲,根本沒錄下來(lái)

試了很多方法,網(wǎng)上也找了很多源碼,但就是怎么都不行,嘗試了各種方法整整一天

最后沒辦法了想用directsound試試,不過后來(lái)又想起來(lái)M8的SDK里面有提供錄音機(jī)相關(guān)的COM接口IRecord

可以錄音,但可定制性太差了,那個(gè)接口就是會(huì)自動(dòng)把錄音結(jié)果保存到一個(gè)固定目錄下生成一個(gè)文件

不過還好中途讀取的聲音會(huì)以消息的形式發(fā)送給windows,我拿到消息進(jìn)行編碼就可以了

而他自動(dòng)生成的錄音文件我只能在每次聊完以后刪掉了



采集終于算是解決了,然后編碼的時(shí)候碰到一個(gè)另一個(gè)大麻煩

手機(jī)的CPU浮點(diǎn)運(yùn)算能力太差了,在PC上,對(duì)400多K 10秒鐘的一個(gè)WAV文件用8的質(zhì)量進(jìn)行編碼大概是700毫秒,0質(zhì)量是180毫秒

而直接移植到手機(jī)上同樣的文件進(jìn)行編碼,8質(zhì)量需要130秒(2分鐘多),0質(zhì)量需要40多秒

天哪!10秒鐘的語(yǔ)音數(shù)據(jù)需要130秒來(lái)編碼,這還得了,離實(shí)際需求差遠(yuǎn)了

說明speex里面基本上都是浮點(diǎn)運(yùn)算

無(wú)奈只能到網(wǎng)上找資料,看有沒有辦法能提速,而且不只是提一點(diǎn)點(diǎn)速度,也看到有不少人說到這個(gè)問題

最后在speex官方網(wǎng)站上終于找到了解決方法,我之前用的是1.0.5版的speex

而1.2beta3版中加入了禁用浮點(diǎn)相關(guān)API的設(shè)置,我真慶幸我是在不是在1.0.5版發(fā)布之后1.2版發(fā)布之前來(lái)開發(fā)這個(gè)軟件的

(有這個(gè)感嘆是因?yàn)間loox,我現(xiàn)在是在1.0版之后和1.1版之前發(fā)布這個(gè)軟件的,而gloox要1.1版才能支持jingle,所以在那之前我只能自己想把法解決語(yǔ)言傳輸問題)

把最新的1.2rc1版源碼下載下來(lái),在宏定義里面加上DISABLE_FLOAT_API和DISABLE_VBR禁用掉浮點(diǎn)運(yùn)算

用WM5的SDK編譯以后再重新編譯了一下測(cè)試用的程序

速度果然是突飛猛進(jìn)啊,采用speex_uwb_mode質(zhì)量8編碼同一個(gè)文件是2秒,0質(zhì)量只需要900毫秒

基本上能滿足要求了



接下來(lái)編寫了一大堆代碼,終于可以實(shí)現(xiàn)電腦上說話手機(jī)上接受了,并且GPRS也沒問題,說明帶寬完全夠了

但現(xiàn)在因?yàn)槭褂玫膰?guó)外的中轉(zhuǎn)服務(wù)器進(jìn)行收發(fā),速度慢到無(wú)法想象。。。

測(cè)試了一下,大概延時(shí)在20S都30S之間,也就是說你說句話,對(duì)方20秒后能接受

然后又試了試In-Band方式,延時(shí)大概10S左右

但至少有點(diǎn)GPRS和普通網(wǎng)絡(luò)的延時(shí)幾乎一樣,說明帶寬已經(jīng)完全不算個(gè)問題了

但由于禁用掉了浮點(diǎn)運(yùn)算,音質(zhì)要比PC上壓縮的差,雜音比較多

但能聽清楚對(duì)方說什么,可能還要試試看speex的雜音消除功能

18.制作自己的xmpp/gtalk客戶端16之gloox雙向socket5proxy數(shù)據(jù)傳輸?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:18

本來(lái)是打算另外建立一個(gè)窗口,建立一個(gè)新的SIProfileFT單獨(dú)對(duì)語(yǔ)言的數(shù)據(jù)進(jìn)行管理

結(jié)果發(fā)現(xiàn)gloox對(duì)多個(gè)SIProfileFT支持不太好,因此暫時(shí)還是把語(yǔ)言傳輸?shù)墓δ芙Y(jié)合到文件傳輸當(dāng)中

通過文件類型這一個(gè)屬性來(lái)區(qū)分是語(yǔ)音還是文件,自己瞎編了一個(gè)類型叫binary/speex-voice-stream

另外解碼和編碼還是非常耗時(shí)的,為了不對(duì)主線程影響,單獨(dú)建立了一個(gè)線程用來(lái)解碼編碼和播放



因?yàn)椴捎妙愃莆募鬏數(shù)墓δ軄?lái)發(fā)送語(yǔ)言,因此我最開始的想法是建立兩個(gè)連接一個(gè)用來(lái)收,一個(gè)用來(lái)發(fā)

后來(lái)發(fā)現(xiàn)自己很傻,這不是socket連接嘛,本來(lái)就支持雙向,一個(gè)連接就夠了

然后昨天pc上寫了個(gè)收發(fā)測(cè)試程序,果然成功了,雙方既能發(fā)又能收

結(jié)果今天把wince上接受語(yǔ)言的功能做的差不多,準(zhǔn)備做發(fā)送的時(shí)候,不管怎么發(fā)數(shù)據(jù),另一方就是收不到

用單步跟蹤進(jìn)去,發(fā)現(xiàn)對(duì)方其實(shí)是收到了數(shù)據(jù)的,只不過因?yàn)閷?duì)方是連接發(fā)起者,所以ConnectionSOCKS5Proxy的狀態(tài)m_s5state一直處于S5StateDisconnected

然后就把收到的數(shù)據(jù)給丟棄了,所以就導(dǎo)致了發(fā)起方只能發(fā)送數(shù)據(jù),而不能接收數(shù)據(jù)

可以理解,因?yàn)檫@個(gè)類本來(lái)就是給文件傳輸做的,而文件傳輸?shù)陌l(fā)起方是不需要接受數(shù)據(jù)的

但奇怪的是,昨天我是怎么試驗(yàn)成功了,我把源碼盡量改回昨天的樣子,但還是不行,真見鬼了

看樣子以后還是多做手記,把當(dāng)時(shí)詳細(xì)的過程寫清楚

不然老碰到這樣的問題,上次在wince上錄音就是,第一次錄音成功后以后再也沒成功過

沒辦法只能自己手動(dòng)試試看來(lái)改改gloox的源碼

找到connectionsocks5proxy.cpp里面的ConnectionSOCKS5Proxy::handleReceivedData方法

這里有個(gè)switch判斷狀態(tài),并且沒有對(duì)S5StateDisconnected的處理

所以自己手動(dòng)在switch的最后面加上

case S5StateDisconnected:
m_handler->handleReceivedData( this, data );?

應(yīng)該沒什么影響



接下來(lái)再解決了一些語(yǔ)言編碼方面的問題后,基本的語(yǔ)音通話功能就算完成了

把軟件發(fā)給群上面一些人幫忙測(cè)試了,完全沒有問題

GPRS也很流暢,除了延遲會(huì)比較夸張以外

19.制作自己的xmpp/gtalk客戶端17之語(yǔ)音延遲問題?[Re: netboy]Copy to clipboard
Posted by:?netboy
Posted on:?2010-04-26 10:19

這里說的語(yǔ)音延遲問題不是網(wǎng)絡(luò)延遲,那個(gè)取決于網(wǎng)絡(luò)狀況,基本上是固定的,除非換個(gè)傳輸方法

這里說的語(yǔ)音延遲問題造成的原因是這樣:

A發(fā)送說了十秒鐘的話,網(wǎng)絡(luò)延遲是3秒

那么正常情況B會(huì)在3秒后開始聽到這句話,并在13秒的時(shí)候聽完

但如果這時(shí)候在第8秒的時(shí)候,B的網(wǎng)絡(luò)卡了1秒(這種情況出現(xiàn)很正常)

那么A說的后面5秒的內(nèi)容,B會(huì)在9~14秒聽到

那么這里問題就出來(lái)了,如果多卡幾次,B聽到的內(nèi)容延遲就會(huì)越來(lái)越大,緩沖區(qū)里面的數(shù)據(jù)也會(huì)越來(lái)越多

但是后面收到的數(shù)據(jù)又必須等到之前收到的數(shù)據(jù)被播放完以后再播放

所以結(jié)果就是延遲會(huì)越來(lái)越長(zhǎng)

那么解決這個(gè)問題有下面這些辦法

1、因?yàn)槲椰F(xiàn)在的這款軟件本來(lái)就是采用中轉(zhuǎn)式的傳輸,本來(lái)就延遲很慢,很難滿足正常通話要求,干脆換成對(duì)講機(jī)的形式,就不會(huì)有這種情況出現(xiàn)了,按住一個(gè)鍵說話,松開話就被發(fā)送出去了,這樣本來(lái)就是異步的

JS:我還是覺得對(duì)講機(jī)不太友好,爭(zhēng)取努力解決延遲問題,實(shí)在不行的話作為最后的選擇吧

2、丟棄掉那些延遲的包,就比如說剛才的問題,B在9秒同時(shí)收到了A在5秒和6秒說的內(nèi)容,這時(shí)候直接把5秒的包丟了,播放6秒的內(nèi)容,用這種方法來(lái)趕上對(duì)方的說話速度

JS:這種方法固然能解決延遲越來(lái)越長(zhǎng)的問題,但問題是某些內(nèi)容被丟棄了,用戶體驗(yàn)會(huì)很差,老是莫名其妙少了一句話,會(huì)讓人抓狂的

3、如果積累了很多過多的包,則不播放那些沒聲音的包。這個(gè)方法就是利用人說話的空隙時(shí)間,接收方收到了過多的包,則說明出現(xiàn)了網(wǎng)絡(luò)延遲的問題,這時(shí)候去分析包,如果沒有聲音,就干脆不播放直接丟棄,去播放后面的包,以此來(lái)趕上說話放的速度。

上面的方法中我最終選擇了第三種,因?yàn)槭紫炔粫?huì)影響用戶體驗(yàn),只丟棄那些沒聲音的包來(lái)空出時(shí)間,利用對(duì)方不說話那段時(shí)間把速度趕上來(lái)

誰(shuí)會(huì)無(wú)止境的說上幾個(gè)小時(shí)呢是吧

但也有弊端,就是背景太過嘈雜的話,就不好分辨了,無(wú)法得知對(duì)方對(duì)方是不是在說話,但這個(gè)問題暫時(shí)不考慮吧

最開始我是想去把包解碼然后分析wave數(shù)據(jù),求這個(gè)包的平均值,如果平均值低于某個(gè)零界則認(rèn)為是無(wú)聲包,丟棄

要做到這個(gè)功能其實(shí)還挺簡(jiǎn)單的,因?yàn)閣ave數(shù)據(jù)還是很好看懂的

不過后來(lái)找到了更好的辦法,那就是speex本身提供的 靜音檢測(cè)VAD 這個(gè)選項(xiàng)來(lái)做

靜音檢測(cè)(VAD)將檢測(cè)被編碼的音頻數(shù)據(jù)是語(yǔ)音還是靜音或背景噪聲。這個(gè)特性在用變比特率(VBR)進(jìn)行編碼是總是開啟的,所以選項(xiàng)設(shè)置只對(duì)非變比特率(VBR)起作用。在這種情況下,Speex檢測(cè)非語(yǔ)音周期并對(duì)用足夠的比特?cái)?shù)重新生成的背景噪聲進(jìn)行編碼。這個(gè)叫“舒適噪聲生成(CNG)”。

int dtx = 1;
speex_encoder_ctl(state, SPEEX_SET_VAD, &dtx);

我跟蹤看了一下,不開啟這個(gè)選項(xiàng)的時(shí)候,每個(gè)包都是固定大小,如果開啟的話,有的包會(huì)是15字節(jié),有的則只有2字節(jié)

所以我想當(dāng)積累的過多的包時(shí),直接丟棄掉只有2字節(jié)的包,當(dāng)然現(xiàn)在還是在理論階段,能不能成功還得試驗(yàn)

另外還有兩個(gè)與此相關(guān)的功能 變比特率(VBR)和 非連續(xù)傳輸(DTX)

變比特率是比較重要的功能,默認(rèn)情況下speex壓縮后每個(gè)包大小都是固定的,如果采用了變比特率那么會(huì)根據(jù)每個(gè)段內(nèi)實(shí)際的語(yǔ)音內(nèi)容而壓縮出不同長(zhǎng)度的內(nèi)容

非連續(xù)性傳輸(DTX)是靜音檢測(cè)(VAD)/變比特率(VBR)操作的額外選項(xiàng),它能夠在背景噪聲固定時(shí),完全的停止傳輸。如果是基于文件的操作,由于我們不能停止對(duì)文件的寫入,會(huì)有5個(gè)比特被用到這種幀內(nèi)(相對(duì)于250bps)。

如果這三個(gè)選項(xiàng)開啟,能夠極大的減少編碼后的數(shù)據(jù)長(zhǎng)度,我測(cè)試了一下,大概減少了一倍左右

不過可惜,因?yàn)閣ince上因?yàn)樾阅茉蛭野迅↑c(diǎn)運(yùn)算禁用掉了,而變比特率完全是基于浮點(diǎn)運(yùn)算的,因此也得禁用掉

不過只開啟靜音檢測(cè)和非連續(xù)性傳輸?shù)脑捯材芤欢康臏p少傳輸量



pc上測(cè)試沒有問題后我就去看wince平臺(tái)上表現(xiàn)怎么樣了

結(jié)果發(fā)現(xiàn)根本就完全沒反應(yīng),加了VAD和DTX特性后和沒加效果一樣

后來(lái)想起來(lái)因?yàn)镸8上的浮點(diǎn)運(yùn)算能力有限,所以禁用掉了浮點(diǎn)運(yùn)算,而VBR是基于浮點(diǎn)運(yùn)算的,因此得一起禁用

而在到網(wǎng)上找了下資料發(fā)現(xiàn)VAD和DTX都是基于VBR的

這下難道又進(jìn)死胡同啦,難道wince平臺(tái)上就沒法使用VAD特性?

我重新把speex說明書上面關(guān)于CPU性能優(yōu)化那段拿了出來(lái)好好看了一下

The single that will affect the CPU usage of Speex the most is whether it is compiled for floating point or fixed-point. If your
CPU/DSP does not have a floating-point unit FPU, then compiling as fixed-point will be orders of magnitudes faster. If there
is an FPU present, then it is important to test which version is faster. On the x86 architecture, floating-point is generally
faster, but not always. To compile Speex as fixed-point, you need to pass –fixed-point to the configure script or define the
FIXED_POINT macro for the compiler. As of 1.2beta3, it is now possible to disable the floating-point compatibility API,
which means that your code can link without a float emulation library. To do that configure with –disable-float-api or define
the DISABLE_FLOAT_API macro. Until the VBR feature is ported to fixed-point, you will also need to configure with
–disable-vbr or define DISABLE_VBR.?

這才想起來(lái)好像當(dāng)時(shí)在編譯speex1.2rc1版時(shí)確實(shí)看到一個(gè)宏定義叫fixed-point,當(dāng)時(shí)也沒在意

說不定以M8上這么強(qiáng)大的CPU運(yùn)行定點(diǎn)數(shù)也完全夠呢

于是把DISABLE_FLOAT_API和DISABLE_VBR特性刪掉以后再次編譯了一遍libspeex

然后再次運(yùn)行wince上的程序,發(fā)現(xiàn)速度很快,幾乎和禁用掉浮點(diǎn)運(yùn)算速度差不多

而且因?yàn)橛辛薞BR的特性,VAD和DTX都運(yùn)行得很好

我拿了一個(gè)826k 19秒的一個(gè)wav文件做測(cè)試,因?yàn)闉榱藴y(cè)試靜音檢測(cè)功能,所以19秒中只稍微講了幾句話,其他都是沒有聲音

統(tǒng)一都采用了speex_uwb_mode的壓縮方式

平臺(tái) speex版本 不開啟任何特性 不開啟任何特性 開啟VAD和DTX 開啟VAD和DTX 開啟VAD和DTX和VBR 開啟VAD和DTX和VBR?
質(zhì)量8 質(zhì)量2 質(zhì)量8 質(zhì)量2 質(zhì)量8 質(zhì)量2?
PC 1.0.5 50K 17K 32K 12K 24K 24K?
WINCE 1.2rc1 40K 16K 19K 8K 16K 16k?



這里測(cè)試結(jié)果可以看出,不管是高質(zhì)量還是低質(zhì)量,VAD和DTX這兩個(gè)屬性都可以減少壓縮后的數(shù)據(jù)量

而VBR這個(gè)屬性在高品種的時(shí)候可以減少數(shù)據(jù)量,但低品質(zhì)的時(shí)候反而增加了數(shù)據(jù)量

而且在wince上加入了VBR以后運(yùn)行速度明顯要慢一兩秒

最后再汗一個(gè)800K壓縮到8K,壓縮了100倍,而解壓后仍然很清晰,技術(shù)的力量真強(qiáng)大啊

總結(jié)

以上是生活随笔為你收集整理的制作自己的xmpp/gtalk客户端的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产高清免费在线观看 | 黄色成年人视频 | 涩涩97| 欧美成人乱码一二三四区免费 | 97影院在线午夜 | 国产伦精品一区二区三区妓女下载 | 欧美精品一区二区三区在线 | 亚洲一区二区三区高清在线 | 亚洲天堂三级 | 九九激情视频 | 白石茉莉奈黑人 | 五月婷婷一区二区 | 精品一区二区三区入口 | 人人爽人人爽人人爽 | 成都4电影免费高清 | 嫩草免费视频 | 隔壁人妻偷人bd中字 | 少妇在线 | 三年大全国语中文版免费播放 | 青青草亚洲| 亚洲天堂手机在线 | 丰满肉肉bbwwbbww | 久久大香焦 | 好色先生tv官网 | 在线观看成人网 | 日本亚洲一区二区三区 | 男女男精品视频网站 | 青娱乐超碰| 综合久久色 | 亚洲视频456 | 国产精品无人区 | 国产日韩欧美精品一区二区 | 国产免费久久 | 热热热色| 超碰97免费在线 | 欧亚成人av | 国产色在线视频 | ass极品国模人体欣赏 | 国产香蕉97碰碰碰视频在线观看 | 一级片视频网站 | 最近中文字幕在线视频 | 欧美视频日韩视频 | 在线不卡国产 | 尤物久久 | 播色网 | 四虎网站在线观看 | 日韩精品一区二区在线看 | 黄色综合网 | 亚洲AV无码成人精品区明星换面 | 青青视频免费 | av网址免费观看 | 最新中文字幕第一页 | 欧美一级做a爰片免费视频 成人激情在线观看 | 日产精品久久久久 | 苏晴忘穿内裤坐公交车被揉到视频 | 黄色动漫在线免费观看 | 中文字幕在线播放日韩 | 深夜福利91 | 99久久精品一区二区成人 | 亚洲熟妇国产熟妇肥婆 | 91三级视频| www国产精品视频 | 色干干| 国产91精品久久久 | 久久国产视频精品 | wwwyoujizz日本| 午夜激情电影院 | 风韵少妇性饥渴推油按摩视频 | 中文字幕观看视频 | 人妻久久一区二区三区 | 麻豆91网站| 丁香婷婷六月 | 秋霞国产精品 | 精品国产999 | 天堂在线91 | 国产一区自拍视频 | 俄罗斯一级片 | 丰满少妇被猛烈进入高清播放 | 伊人精品视频在线观看 | 中文字幕一区二区免费 | 亚洲一区电影在线观看 | 男生和女生差差的视频 | 欧美性受xxxx黑人 | 国产123区在线观看 91国产一区二区 | 一区二区三区四区久久 | 黄网在线看 | 成人影视免费 | 欧美又大又硬又粗bbbbb | 日韩av线观看 | 欧美韩国一区 | 精品一区二区三区四区 | 亚洲成肉网 | 黄色片子一级 | 欧美色淫 | 天堂中文字幕免费一区 | 91精品国产综合久久久蜜臀九色 | 黄色激情小说视频 | 国产精品suv一区二区88 | 午夜精品久久久久久久99热浪潮 |