[GTalk] 出来也有段时间了,因为是 [Google] 出品的,所以也吸引了一定的眼球,首先提供的功能是即时通讯和语音,和 [Skype] 有的一拼,语音质量还可以。其[开发者]页面中说明了它用的是 [Jabber] 协议,所以其他的 Jabber 客户端都可以连得上去,比如 [Gaim]。接下来说说语音,一般多媒体的支持都需要两个部分,第一部分可以叫做信令(Signaling),这一部分让两个客户端能够互相联系起来、各自支持的编解码器、采取什么方式进行数据传输等等。另一方面就是真正的语音数据传输,现在 IP 网络上的多媒体一般都是使用 [RTP/RTCP],是由 [IETF] 的 [AVT] 工作组制定,已经广泛使用。
GTalk 的语音协议使用的库是 [libjingle],其信令协议的实现和 [XEP-0166 Jingle](原来叫[JEP-166 Jingle],以下不再赘述) 以及其他相关的标准 [XEP-0167 Jingle Audio Content Description Format]、[XEP-0176 Jingle ICE Transport] 等略有不同,可能是因为先有的 libjingle,然后 Google 和 Jabber 合作将其规范化,从 Jingle 作者的 email 就可以看出来,有好几个是 Google 的,其中还有 Gaim 的头 Sean Egan。Jingle 的协议现在还在更新中,等最后稳定下来以后,GTalk 肯定也会跟上的。这些是从公开的文档中看到的。
通过抓包发现以下过程:
- 打电话的人发起 Jabber 请求,要求进行语音通讯:
-
<iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="143">
-
<session xmlns="http://www.google.com/session" type="initiate" id="2482103147"
-
initiator="xxx@gmail.com/Talk.v927553D771">
-
<description xmlns="http://www.google.com/session/phone">
-
<payload-type xmlns="http://www.google.com/session/phone" id="103" name="ISAC"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="97" name="IPCMWB"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="4" name="G723"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="100" name="EG711U"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="101" name="EG711A"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="0" name="PCMU"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="8" name="PCMA"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="13" name="CN"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="102" name="iLBC"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="117" name="red"/>
-
<payload-type xmlns="http://www.google.com/session/phone" id="106"
-
name="audio/telephone-event"/>
-
</description>
-
</session>
-
</iq>
其中,
id就是后来 RTP 传输中的负载类型(Payload Type)。 -
- 然后双方进行 [ICE-Interactive Connectivity Establishment] 检查。ICE 是一个方法,它利用 [STUN] 和 [TURN] 来检查两端是否能够进行连接。比如两端处于 [NAT] 之后,那么语音数据必须得要穿过 NAT 才能到达对端。
ICE 的原理这里不进行详细解释,只是简单说一下,以后还会单独进行探讨。首先双方要使用 STUN/TURN 协议拿到本端的一些包含协议类型、IP 以及端口的候选项(Candidate,分 local、stun 以及 relay 几种不同网络类型),还有用户名和密码,然后各自把本端的候选项发给对方,然后把本端和对端的候选项两两配对,检查是否可以连通。下面是一些例子:-
<iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="145">
-
<session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
-
initiator="xxx@gmail.com/Talk.v927553D771">
-
<candidate name="rtp" address="192.168.1.100" port="3625" username="IC2jv/pMuZWWgNUI"
-
password="Fw6vDd/2qyg388CR" preference="1" protocol="udp" type="local"
-
network="0" generation="0"/>
-
</session>
-
</iq>
-
-
<iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="146">
-
<session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
-
initiator="xxx@gmail.com/Talk.v927553D771">
-
<candidate name="rtp" address="xx.xx.xx.xx" port="10423" username="tvZ7nbIYRbKLRQQM"
-
password="QNr79Ut1UCLmgGGe" preference="0.9" protocol="udp" type="stun"
-
network="0" generation="0"/>
-
</session>
-
</iq>
-
-
<iq to="yyy@gmail.com/Talk.v95CFB74394" type="set" id="147">
-
<session xmlns="http://www.google.com/session" type="candidates" id="2482103147"
-
initiator="xxx@gmail.com/Talk.v927553D771">
-
<candidate name="rtp" address="216.239.37.126" port="19295" username="YmSTEgsiCHHXpeVA"
-
password="isGiNLyAX9puDcN1" preference="0.5" protocol="udp" type="relay"
-
network="0" generation="0"/>
-
</session>
-
</iq>
类型为 local 是本地地址,类型为 stun 的是 NAT 的外部地址,类型为 replay 的是双方通过这个地址进行数据转发,而不是直接连接。
其中有一个值得注意的地方就是,最初的 STUN 服务器从哪里来?按理来讲,任何 STUN 服务器都可以的,但是 GTalk 用的是自己的,在进行 ICE 检查获取本地候选项之前,向
216.239.37.126发送了一个 HTTP 请求:-
/* 请求 */
-
GET /create_session HTTP/1.1
-
Connection: Keep-Alive
-
Content-Length: 0
-
Host: 216.239.37.126
-
User-Agent: Google Talk
-
X-Google-Relay-Auth: xxxxxxxxxxxxxxxxxxxxxxxxx
-
X-Talk-Google-Relay-Auth: yyyyyyyyyyyyyyyyyyyyyyyyyyy
-
-
/* 响应 */
-
Content-Type: text/plain
-
Date: Wed, 16 Aug 2006 12:54:12 GMT
-
Server: MediaProxy
-
Content-Length: 197
-
-
relay.ip=216.239.37.126
-
relay.udp_port=19295
-
relay.tcp_port=19294
-
relay.ssltcp_port=443
-
stun.ip=216.239.37.126
-
stun.port=19302
-
username=xxxxxxxxxxx
-
password=yyyyyyyyyyy
-
magic_cookie=xxxxxx
这个服务器是 Google 的 relay server,从这里可以拿到相应的 stun 端口和 relay 端口。
-
- 如果双方的 ICE 检查通过,找到了互相连接的通路,那么接电话一方正式接受:
-
<iq to="xxx@gmail.com/Talk.v927553D771" type="set" id="345"
-
from="yyy@gmail.com/Talk.v95CFB74394">
-
<session type="accept" id="2482103147"
-
initiator="xxx@gmail.com/Talk.v927553D771"
-
xmlns="http://www.google.com/session">
-
<description xml:lang="en" xmlns="http://www.google.com/session/phone">
-
<payload-type id="103" name="ISAC"/>
-
<payload-type id="97" name="IPCMWB"/>
-
<payload-type id="4" name="G723"/>
-
<payload-type id="100" name="EG711U"/>
-
<payload-type id="101" name="EG711A"/>
-
<payload-type id="0" name="PCMU"/>
-
<payload-type id="8" name="PCMA"/>
-
<payload-type id="13" name="CN"/>
-
<payload-type id="102" name="iLBC"/>
-
</description>
-
</session>
-
</iq>
-
- 然后就在约定好的 RTP 链接上进行语音数据传输,其编解码器也是使用商定好的负载类型,象上面给出的例子中,双方提供的是一致的,那么就选择第一个,也就是 [url=][ISAC][/url],我们还看到 GTalk 还支持 [iLBC]。
- 结束的时候将发送:
从上面的过程可以看出来,ICE 是其中比较重要的一部分。这将在以后会谈到。
所以要和 GTalk 进行互连,要做以下几个部分(如果不使用 libjingle 的话):
- 一般 Jabber 协议支持(XML 解析、协议处理等等)
- 上述
session部分的协议 - ICE 的支持,里面牵涉到 ICE 本身的一些方法以及 STUN/TURN 协议
- RTP/RTCP,传输方面的支持
- 编解码器(Codec),至少应该有 iLBC,(Jingle 协议中是 speex)
其中 Jabber/RTP/iLBC 有现成的东西,直接使用就可以,可能要处理的就是剩下的三部分,如果有现成的库就更好了。




X-GOOGLE-TOKEN
X-Google-Token Mysteries
嗨,兄弟,最近在搞Gtalk的东西,search到你的bl
嗨,兄弟,最近在搞Gtalk的东西,search到你的blog, 首先表示感谢。
然后有些小问题。
看你的blog里Jabber请求好像都是明文,而我抓到的包,貌似全是加密的, 我也用pigin选择不使用SSL加密的方式发送请求,可是一样是密文。是不是现在的Jabber/XMPP强制使用加密方式?
另外如果我想过滤出语音包,如何能够获得remote host的ip address呢?貌似在voice请求的时候会发送一个http请求(Create_session),然后应答的http中提供的是reply.ip等信息。。。。
Tks & Regards,
Bo
确实是加密的
XMPP 使用 SSL/TLS 对消息进行加密,但当时 GTalk 为什么没用,我不记得了。Pidgin 可以直接在 Help/Debug Window 中看到所有的调试信息或者启动的时候使用 -d 参数也可以。
语音通道通常和 XMPP 不是一个(也就是 Out of Band),其中协商过程就是 Jingle (XEP-166)协议。而当时的 GTalk 使用的是自己的协议,与 Jingle 并不符合。不知道现在如何。发出的 HTTP 请求 create_session 只是 GTalk 自己的做法,去拿到相关的 STUN Server 以及 Relay Server 信息。通道找到以后会在 XMPP 的消息中体现出来的。当时的这篇文章没有把这部分的具体信息写出来。
我觉得可以直接看 Jingle 协议,以这个为准是最主要的。希望对你有所帮助。
thanks
这么快就回复了!!Thanks a lot
其实由于Gtalk是使用加密传输的,所以现在已经开始研究GMail/Gtalk, 也就是嵌入到GMail页面里面的chat,它支持voice chat 和 vedio chat, 但是不使用Jabber/XMPP,而是改用http,但是不知道voice&vedio是否仍使用Jingle协议。我现在的目的是如何从所有的ip消息中找出所有gtalk的语音/视频包。现在遇到一个问题,就是不知道remote端的ip和port,不知道remote ip & port是通过什么方式通知到gtalk的。
小弟从来没有接触过这些东东,兄台如有所了解,望告知!不胜感激。
Thanks & Regards,
Bo
抱歉
很抱歉,WEB 界面的 GTalk 没有研究过,对其后面的机制不是很清楚,帮不上什么忙了。不过 GTalk 使用的是 Libjingle,可以直接研究它的源代码。Pidgin 现在也是直接支持 GTalk 的音频和视频,可以参考 XMPP 相关的代码。
另外,找出语音视频包应该比较简单,基本上包最多的就是,通常来讲不是加密的,从中可以知道其地址和端口,但是怎么得到的就不好说了。
Post new comment