实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析
本文由ELab技术团队分享,原题“浅谈WebRTC技术原理与应用”,有修订和改动。
1、基本介绍
WebRTC(全称 Web Real-Time Communication),即网页即时通信。 是一个支持网页浏览器进行实时语音对话或视频对话的技术方案。从前端技术开发的视角来看,是一组可调用的API标准。
在WebRTC发布之前,开发实时音视频交互应用的成本是非常昂贵,需要考虑的技术问题很多,如音视频的编解码问题,数据传输问题,延时、丢包、抖动、回音的处理和消除等,如果要兼容浏览器端的实时音视频通信,还需要额外安装插件。
2010年5月:Google以6820万美元收购VoIP软件开发商Global IP Solutions的GIPS引擎,并改为名为“WebRTC”(见《了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化》)。旨在建立一个互联网浏览器间的实时通信的平台,让 WebRTC技术成为 H5标准之一。
2012年1月:谷歌已经把这款软件集成到Chrome浏览器中,Opera初步集成WebRTC。
2013年 6月:Mozilla Firefox[5]发布22.0版本正式集成及支持WebRTC。
2017年11月:W3C WebRTC 1.0 草案正式定稿。
2021年1月:WebRTC 被 W3C 和 IETF 发布为正式标准(见《WebRTC 1.0: Real-Time Communication Between Browsers》)。
(本文已同步发布于:http://www.52im.net/thread-3804-1-1.html)
2、重要意义
WebRTC的出现、发展和被业内标准组织(如W3C)等普遍认可,对于当下和未来大前端技术发展具有重要的意义。
降低在web端的音视频交互开发门槛:
- 1)以往的音视频交互开发对于Web开发者而言具有一定技术门槛;
- 2)现在借助于WebRTC,Web开发者通过调用JS接口,可快速的实现音视频交互应用。
避免依赖、插件造成的次生问题:
- 1)以往的音视频交互应用构建依赖于各种插件、软件和服务器等;
- 2)现在借助于主流浏览器即可形成端到端的音视频交互。
统一化和标准化对传统音视频交互环境差异性的规避:
- 1)以往音视频交互需要面对不同的 NAT 、防火墙对媒体 P2P 的建立带来了很大的挑战;
- 2)现在WebRTC 中有P2P 打洞的开源项目 libjingle ,支持 STUN,TURN 等协议。
更高效优化的算法、技术对于音视频交互性能的提升:
- 1)WebRTC 通过NACK、FEC技术,避免了经过服务端路由中转,减少了延迟和带宽消耗;
- 2)还有 TCC + SVC + PACER + JitterBuffer 等技术对于音视频流畅性进行了优化。
3、技术特征
WebRTC内容丰富,主要的技术特征包含以下几点。
1)实时通讯:
WebRTC是一项实时通讯技术,允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。
2)无依赖/插件:
WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。
3)协议栈 众多:
WebRTC并不是单一的协议,包含了媒体、加密、传输层等在内的多个协议标准以及一套基于 JavaScript的 API,它包括了音视频的采集、编解码、网络传输、显示等功能。通过简单易用的 JavaScript API ,在不安装任何插件的情况下,让浏览器拥有了 P2P音视频和数据分享的能力。
WebRTC依赖众多协议栈图:

同时WebRTC 并不是一个孤立的协议,它拥有灵活的信令,可以便捷的对接现有的SIP 和电话网络的系统。
4、兼容覆盖
目前大部分主流浏览器都正常兼容WebRTC:
▲ 上图引用自《WebRTC实时音视频技术的整体架构介绍》
更详细的浏览器及版本兼容情况,可以看看下图:
主流浏览器都支持 WebRTC 标准 API ,因此也让浏览器之间无插件化的音视频互通成为可能, 大大降低了音视频开发的门槛,开发者只需要调用 WebRTC API 即可快速构建出音视频应用。
5、技术框架
如下图所示:的技术框架描述了WebRTC的核心内容和面向不同开发者的API设计。
WebRTC技术框架图:
▲ 上图引用自《零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能》
从图中可看到,WebRTC主要面向三类开发者的API设计:
- 1)对于Web开发者的API:框架包含了基于JavaScript 、 经过W3C认证了的一套API标准,使得web开发者可以基于这套API开发基于WebRTC的即时通讯应用;
- 2)对于浏览器厂商的API:框架同样包含了基于C++的底层WebRTC接口,对于浏览器厂商底层的接入十分友好;
- 3)浏览器厂商可自定义的部分:框架中还包含浏览器厂商可自定义的音视频截取等扩展部分。
6、技术核心
从上节框架中可以看到,WebRTC主要有音频、视频引擎和传输三部分组成,其中又包含众多的协议和方法等。
1)Voice Engine(音频引擎):
- a、Voice Engine包含iSAC/iLBC Codec(音频编解码器,前者是针对宽带和超宽带,后者是针对窄带);
- b、NetEQ for voice(处理网络抖动和语音包丢失);
- c、Echo Canceler(回声消除器)/ Noise Reduction(噪声抑制)。
2)Video Engine(视频引擎):
- a、VP8 Codec(视频图像编解码器);
- b、Video jitter buffer(视频抖动缓冲器,处理视频抖动和视频信息包丢失);
- c、Image enhancements(图像质量增强)。
3)Transport。
7、技术原理
7.1 基本情况
WebRTC主要的技术特征:
- 1)SRTP:安全的实时传输协议,用于音视频流传输;
- 2)Multiplexing:多路复用;
- 3)P2P:STUN+TURN+ICE,用于NAT网络和防火墙穿越;
- 4)DTLS:安全传输可能还会用到DTLS(数据报安全传输),用于加密传输和密钥协商;
- 5)UDP:整个WebRTC通信是基于UDP的。
限于篇幅,本文以下章节将不细致介绍音视频采集、编码和处理等内容,仅介绍实时通讯的建立过程原理的核心内容。
7.2 公网IP映射:明确网络定位信息
WebRTC是基于浏览器端到端的连接(P2P)实现的.
由于不需要服务器中转,所以获取连接对象的网络地址的方式,是借助于ICE、STUN、TURN等辅助内网穿透技术(NAT)得到对应主机的公网网络地址和端口等网络定位信息。
明确网络定位是建立端与端直接通讯的基础。
NAT穿透原理图:
STUN服务器用于辅助内网穿透得到对应主机的公网网络地址和端口信息图:
▲ 上图引用自《WebRTC实时音视频技术的整体架构介绍》
7.3 信令服务器:网络协商与信息交换
信令服务器的作用是基于双工通信来中转信息。
中转信息包括公网IP映射后的网络定位信息,比如:公网IP、端口和媒体数据流等。
概念图:
信令服务器信息交互过程图:

7.4 会话描述协议SDP:统一的媒体协商方式
SDP的作用:
- 1)不同端/浏览器对于媒体流数据的编码格式各异,如VP8、VP9等,参与会话的各个成员的能力不对等、用户环境与配置不一致等;
- 2)WebRTC通讯还需要确定和交换本地和远程音频和视频媒体信息,例如分辨率和编解码器功能。交换媒体配置信息的信令通过使用会话描述协议 (SDP) 交换Offer和Anwser来进行;
- 3)SDP的交换一定是先于音视频流交换的。其内容包括会话基本信息、媒体信息描述等。
//SDP的结构体
Session description(会话级别描述)
v= (protocol version)
o= (originator and session identifier)
s= (session name)
c=* (connection information -- not required ifincluded inall media)
One or moreTime descriptions ("t="and "r="lines; see below)
a=* (zero or moresession attribute lines)
Zero or moreMedia descriptions
Time description
t= (timethe session is active)
Media description(媒体级别描述), ifpresent
m= (media name and transport address)
c=* (connection information -- optional ifincluded at session level)
a=* (zero or moremedia attribute lines)
一个SDP例子如下:
v=0 //代表版本,目前一般是`v=0`.
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0 //会话处于活动状态的时间
a=group:BUNDLE audio video //:描述服务质量,传输层复用相关信息
m=audio 1 RTP/SAVPF103 104 0 8 106 105 13 126 //...
a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh81
7.5 一对一连接建立过程
以建立一对一的Web RTC连接过程为例来简要讲解。
一对一过程图:
简要过程图:
如上图所示,解释一下:
- 1)交换SDP,获取各自媒体配置信息;
- 2)STUN服务器交换网络地址和端口等网络信息;
- 3)Turn中转音视频媒体流数据。
工作流程图:
如上图所示,解释一下:
- 1)A和B双方先调用 getUserMedia 打开本地摄像头,作为本地待输出媒体流;
- 2)向信令服务器发送加入房间请求;
- 3)Peer B 接收到 Peer A 发送的 offer SDP 对象,并通过PeerConnection的SetLocalDescription方法保存 Answer SDP 对象并将它通过信令服务器发送给 Peer A;
- 4)在 SDP 信息的 offer/answer 流程中,Peer A 和 Peer B 已经根据 SDP 信息创建好相应的音频 Channel 和视频 Channel,并开启Candidate 数据的收集,Candidate数据(本地IP地址、公网IP地址、Relay服务端分配的地址);
- 5)当 Peer A 收集到 Candidate 信息后通过信令服务器发送给 Peer B。同样的过程 Peer B 对 Peer A 也会再发送一次。
7.6 多对多的建立
多对多建立点到点连接概念图,以三个用户点对点的连接为例:

7.7 WebRTC的主要JavaScrip接口
getUserMedia():访问数据流,例如来自用户的相机和麦克风
//请求媒体类型
const constraints = {
video: true
audio:true
};
const video = document.querySelector('video');
//挂载流到相应dom展示本地媒体流
function handleSuccess(stream) {
video.srcObject = stream;
}
function handleError(error) {
console.error('getUserMedia error: ', error);
}
//利用摄像头捕获多媒体流
navigator.mediaDevices.getUserMedia(constraints).
then(handleSuccess).catch(handleError);
RTCPeerConnection:通过加密和带宽管理工具启用音频或视频通话
// 允许 RTC 服务器配置。
const server = {
"iceServers":
[{ "urls": "stun:stun.stunprotocol.org"}]
};
// 创建本地连接
const localPeerConnection = newRTCPeerConnection(servers);
// 收集Candidate 数据
localPeerConnection.onicecandidate=function(event){
...
}
// 监听到媒体流接入时的操作
localPeerConnection.ontack=function(event){
...
}
RTCDataChannel:支持通用数据的点对点通信,常用于数据点到点的传输
const pc = newRTCPeerConnection();
const dc = pc.createDataChannel("my channel");
//接受数据
dc.onmessage = function(event) {
console.log("received: "+ event.data);
};
//打开传输
dc.onopen = function() {
console.log("datachannel open");
};
//关闭传输
dc.onclose = function() {
console.log("datachannel close");
};
8、应用案例
这里以WebRTC的多人视频案例为实践来大致演示一下。
8.1 设计框架
多人视频基本框架图:

8.2 关键代码
8.2.1)媒体捕获:
获取浏览器视频权限,捕获本地视频媒体流,在Video元素中附加媒体流,显示本地视频结果。代码如下。
//摄像头兼容性处理
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
// 获取本地音频和视频流
navigator.mediaDevices.getUserMedia({
"audio": false,
"video": true
}).then( (stream)=> {
//显示自己的输出流,挂到页面Video元素上
document.getElementById("myVido").srcObject=stream
})
捕获本地视频媒体流的显示结果截图:
为每个新的客户端连接创建RTCPeerConnection对象:
// stun和turn服务器 const iceServer = {
"iceServers": [{
urls:"stun:stun.l.google.com:19302"
}]
};
//为点到点的连接创建RTCPeerConnection
const peerRTCConn=newRTCPeerConnection(iceServer);
8.2.2)网络协商:
主要任务就是:创建对等连接,收集ICE候选,等待媒体流接入时挂载到dom。
交互式连通性建立(Interactive Connectivity Establishment — ICE)是一个允许实时对等端发现对方并且彼此连接的框架。此技术允许对等方发现有关彼此拓扑的足够信息,从而有可能在彼此之间找到一条或多条通信路径。ICE 代理负责:收集本地IP,端口元组候选、在同级之间执行连接检查和发送连接保持活动。(关于ICE的介绍,见《P2P技术之STUN、TURN、ICE详解》)
// 发送ICE候选到其他客户端 peerRTCConn.onicecandidate = function(event){
if(event.candidate) {
//向信令服务器转发收集到的ICE候选 socket.send(JSON.stringify({
"event": "relayICECandidate",
"data": {
'iceCandidate': {
'sdpMLineIndex': event.candidate.sdpMLineIndex,
'candidate': event.candidate.candidate
}
},
"fromID":signalMsg['data']['peerId']
}));
}
}
//有媒体流介入就挂载dom peerRTCConn.ontrack=function(event){
let v=document.createElement("video")
v.autoplay=true
v.style="width:200px"
document.getElementById("peer").appendChild(v)
v.srcObject=event.streams[0]
}
8.1.3)媒体协商:
发起时创建Offer。peer利用setLocalDescription方法将会话信息加到RTCPeerConnection(),并由信令服务器中转。其他Peer会返回相应的Answer。SDP过程:
//新加入节点发起offer if(canOffer){
peerRTCConn.createOffer(
function(localDescription) {
peerRTCConn.setLocalDescription(localDescription,
function() {
//发送描述信息给信令服务器 socket.send(JSON.stringify({
"event":"relaySessionDescription",
"data":localDescription,
"fromID":peerId
}))
},
function() { alert("offer failed"); }
);
},
function(error) {
console.log("error sending offer: ", error);
}
)
}
响应时创建Answer。会话描述包括音视频信息等内容,当发起者向响应者发出offer类型的描述后,响应者会返回answer类型的描述:
//创建Answer会话
peer.createAnswer(
function(_remoteDescription) {
peer.setLocalDescription(_remoteDescription,
function() {
//发送描述信息给信令服务器 socket.send(JSON.stringify({
"event":"relaySessionDescription",
"data":_remoteDescription,
"callerID":signalMsg['fromId'],
"fromID":signalMsg['fromId']
})) },
function() { alert("answer failed"); }
);
},
function(error) {
console.log("error creating answer: ", error);
});
当收到ICE候选共享后,会把ICE候选添加到远程对等点描述中:
//对应的RTCPeerConnection
const peer = peers[signalMsg["fromID"]];
//ICE候选添加到远程对等点描述
peer.addIceCandidate(newRTCIceCandidate(signalMsg["data"].iceCandidate));
多人视频结果截图<本地模拟效果>:

8.2.4)信令中转:
信令服务部分关键代码:
wss.on('connection', function(ws) {
ws.on('message', function(message) {
let meeageObj=JSON.parse(message)
//交换ICE候选 if (meeageObj['event'] =='relayICECandidate') { wss.clients.forEach(function (client) {
console.log("send iceCandidate")
client.send(JSON.stringify({
"event": "iceCandidate",
"data": meeageObj['data'],
"fromID": meeageObj['fromID']
}));
});
}
//交换SDP
if (meeageObj['event'] =='relaySessionDescription') {
console.log(meeageObj["fromID"],meeageObj["data"].type)
wss.clients.forEach(function(client) {
if(client!=ws) {
client.send(JSON.stringify({
"event": "sessionDescription",
"fromId":meeageObj["fromID"],
"data": meeageObj["data"],
}));
}
});
}
})
})
9、小结一下
WebRTC的优点主要是:
1)方便:对于用户来说,在WebRTC出现之前想要进行实时通信就需要安装插件和客户端,但是对于很多用户来说,插件的下载、软件的安装和更新这些操作是复杂而且容易出现问题的,现在WebRTC技术内置于浏览器中,用户不需要使用任何插件或者软件就能通过浏览器来实现实时通信。对于开发者来说,在Google将WebRTC开源之前,浏览器之间实现通信的技术是掌握在大企业手中,这项技术的开发是一个很困难的任务,现在开发者使用简单的HTML标签和JavaScript API就能够实现Web音/视频通信的功能。
2)免费:虽然WebRTC技术已经较为成熟,其集成了最佳的音/视频引擎,十分先进的codec,但是Google对于这些技术不收取任何费用。
3)强大的打洞能力:WebRTC技术包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透技术,并支持代理。
WebRTC的缺点主要是:
1)缺乏服务器方案的设计和部署。
2)传输质量难以保证。WebRTC的传输设计基于P2P,难以保障传输质量,优化手段也有限,只能做一些端到端的优化,难以应对复杂的互联网环境。比如对跨地区、跨运营商、低带宽、高丢包等场景下的传输质量基本是靠天吃饭,而这恰恰是国内互联网应用的典型场景。
3)WebRTC比较适合一对一的单聊,虽然功能上可以扩展实现群聊,但是没有针对群聊,特别是超大群聊进行任何优化。
4)设备端适配,如回声、录音失败等问题层出不穷。这一点在安卓设备上尤为突出。由于安卓设备厂商众多,每个厂商都会在标准的安卓框架上进行定制化,导致很多可用性问题(访问麦克风失败)和质量问题(如回声、啸叫)。
5)对Native开发支持不够。WebRTC顾名思义,主要面向Web应用,虽然也可以用于Native开发,但是由于涉及到的领域知识(音视频采集、处理、编解码、实时传输等)较多,整个框架设计比较复杂,API粒度也比较细,导致连工程项目的编译都不是一件容易的事。
10、参考资料
[3] 访谈WebRTC标准之父:WebRTC的过去、现在和未来
[4] 良心分享:WebRTC 零基础开发者教程(中文)[附件下载]
[6] 新手入门:到底什么是WebRTC服务器,以及它是如何联接通话的?
[9] 基于开源WebRTC开发实时音视频靠谱吗?第3方SDK有哪些?
[10] 开源实时音视频技术WebRTC在Windows下的简明编译教程
[11] 网页端实时音视频技术WebRTC:看起来很美,但离生产应用还有多少坑要填?
[12] 了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化
[13] 零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能
[14] P2P技术详解(一):NAT详解——详细原理、P2P简介
[15] P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)
(本文已同步发布于:http://www.52im.net/thread-3804-1-1.html)
实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析的更多相关文章
- 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!
概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...
- 了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化
本文原文由声网WebRTC技术专家毛玉杰分享. 1.前言 有人说 2017 年是 WebRTC 的转折之年,2018 年将是 WebRTC 的爆发之年,这并非没有根据.就在去年(2017年),WebR ...
- 一起来试玩!在线可编程交互的实时音视频 Web SDK 入门教程
在与开发者长期的沟通中,我们发现,尽管声网为开发者提供了丰富翔实的 SDK 技术文档,但对于初次接触声网 SDK 的开发者来说,在第一眼看到文档的时候,可能会被大量新概念和复杂的 API 接口淹没.S ...
- 实时音视频互动系列(下):基于 WebRTC 技术的实战解析
在 WebRTC 项目中,又拍云团队做到了覆盖系统全局,保证项目进程流畅.这牵涉到主要三大块技术点: 网络端.服务端的开发和传输算法 WebRTC 协议中牵扯到服务端的应用协议和信令服务 客户端iOS ...
- 音视频入门-13-使用开源库生成PNG图片
* 音视频入门文章目录 * RGB-to-PNG 回顾 上一篇 [手动生成一张PNG图片] 根据 [PNG文件格式详解] 一步一步地手动实现了将 RGB 数据生成了一张 PNG 图片. 有许多开源的 ...
- iOS WebRTC 点对点实时音视频流程介绍
前言 公司某个项目需要接入音视频即时通讯, 功能类似微信的拨打视频通话,语音通话的场景.那么对于音视频通讯会用到什么技术呢?没错,它就是 WebRTC . 什么是WebRTC WebRTC,名称源自网 ...
- 音视频入门-09-RGB&YUV互转-使用开源库
* 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...
- 音视频入门-05-RGB-TO-BMP使用开源库
* 音视频入门文章目录 * RGB-TO-BMP 回顾 将 RGB 数据转成 BMP 图片: 了解 BMP 文件格式 准备 BMP 文件头信息 准备 BMP 信息头 BMP 存储 RGB 的顺序是 B ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- Qcon 实时音视频专场:实时互动的最佳实践与未来展望
互动直播.线上会议.在线医疗和在线教育是实时音视频技术应用的重要场景,而这些场景对高可用.高可靠.低延时有着苛刻的要求,很多团队在音视频产品开发过程中会遇到各种各样的问题.例如:流畅性,如果在视频过程 ...
随机推荐
- nginx实现资源文件动静分离的记录
Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和静态页面物理分离.严格意义上说应该是动态请求跟静态请求分开,可以理解成使用 Nginx 处理静态页面,Tomcat ...
- Windows10关闭系统自动更新--专业版
当你正在跑项目,cpu负荷,内存负荷,这时候Windows服务模块没有人情味滴突然来个更新撑爆你的磁盘读写,那感觉简直炸锅 像这样: 什么?加个固态就好了 你要是上了固态,就不应该看到这篇文章,相见即 ...
- My SQL 下载和安装图文解说
一.下载My SQL 官网下载地址:https://downloads.mysql.com/archives/installer/ 选择需要下载的版本,点击download.本文选择下载的版本是8.0 ...
- Flask常用插件
Flask特点: 1.小而精的代表 2.基于Werkzeug工具箱编写的轻量级web开发框架,它主要面向需求简单,项目周期短的Web小应用 3.灵活,核心思想是Flask只完成基本的功能,别的功能都是 ...
- 2.12 Linux两种远程管理工具(PuTTY和SecureCRT)
通过<Linux远程管理协议>一节可以知道,Linux远程管理服务器多基于 SSH 协议.本节给大家介绍 2 种常见的基于 SSH 协议的远程管理工具,分别是 PuTTY 和 Secure ...
- Chapter12 动态内存与智能指针
目录 12.1.0 介绍 12.1.1 shared_ptr类 make_shared函数 shared_ptr的拷贝和引用 shared_ptr自动销毁所管理的对象- -shared_ptr还会自动 ...
- docker实现redis集群
1.主从模式(Master-Slave) 1.1主从复制原理 主从复制是redis的一种基本的集群方式,它通过将一个Redis节点(主节点)的数据复制到一个或多个其他Redis节点来实现数据的冗余和备 ...
- python3的json数据库-TinyDB初入门
无意间看到TinyDB这个词汇,就去查了一下,就发现了它的官方网站 这里 然后就是按照他说的步骤去做. 第1步 安装 pip3 install tinydb 安装成功后,创建一个文件名字叫做 tes ...
- 基于python搭建FTP服务
使用python搭建FTP服务非常容易,且非常稳定,更重要的是可以实现一些精细化的控制,例如精细的访问权限配置,详细的日志记录等工作 这里是使用了pyftpdlib模块 1. 安装 pip insta ...
- Vscode之常用插件
code runner 可以直接在编辑器中运行代码,查看结果,非常方便,一键运行. PHP Intelephense PHP代码提示工具,支付代码提示.查找定义.类搜索等功能,非常强大. php de ...