WebRtc是谷歌2010年收购GlobalIPSolutions公司而获得的一项实时语音对话或视频对话的技术。之后谷歌将其开源,有很好的跨平台性。官方网址:https://webrtc.org/

最近由于公司项目需求,刚刚接触webrtc,由于国内这方面的资料少之又少,学习起来也有点困难。这一个月来对webrtc也稍微有点了解吧,特此写个博客纪念下,结合自己写的小Demo给刚入坑的新人一点建议。


使用webrtc###

1. Maven

<dependency><groupId>org.webrtc</groupId><artifactId>google-webrtc</artifactId><version>1.0.20723</version><type>pom</type>
</dependency>

2. Gradle

dependencies {implementation 'org.webrtc:google-webrtc:1.0.20723'
}

最新版本请到官方版本发布地址查看:https://bintray.com/google/webrtc/google-webrtc


需要的权限###

<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-featureandroid:glEsVersion="0x00020000"android:required="true"/><uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

注意:安卓6.0以上请自行处理CAMERA、RECORD_AUDIO、WRITE_EXTERNAL_STORAGE等危险权限。


介绍Webrtc一些关键类###

1. PeerConnectionFactory
webrtc核心类,用于创建其他关键类,稍后在做介绍。在使用PeerConnectionFactory之前,请先初始化,类似这样。

PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(getApplicationContext()).setEnableVideoHwAcceleration(true).createInitializationOptions());

PeerConnectionFactory.InitializationOptions作为PeerConnectionFactory初始化传入参数,该类采用构造模式,可以对初始化参数进行一些配置。初始化之后就可以创建PeerConnectionFactory实例了。

PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
mPeerConnectionFactory = new PeerConnectionFactory(options);

2. VideoCapturer
视频捕捉器的一个顶级接口,它的的子接口为CameraVideoCapturer,封装了安卓相机的使用方法,使用它们可以轻松的获取设备相机数据,切换摄像头,获取摄像头数量等。该对象的创建如下。

private CameraVideoCapturer createVideoCapture(Context context) {CameraEnumerator enumerator;if (Camera2Enumerator.isSupported(context)) {enumerator = new Camera2Enumerator(context);} else {enumerator = new Camera1Enumerator(true);final String[] deviceNames = enumerator.getDeviceNames();for (String deviceName : deviceNames) {if (enumerator.isFrontFacing(deviceName)) {CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);if (videoCapturer != null) {return videoCapturer;}}}for (String deviceName : deviceNames) {if (!enumerator.isFrontFacing(deviceName)) {CameraVideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);if (videoCapturer != null) {return videoCapturer;}}}return null;}

3. VideoSource/VideoTrack
VideoSource为视频源,通过核心类PeerConnectionFactory创建,VideoTrack是对VideoSource的包装,可以方便的将视频源在本地进行播放,添加到MediaStream中进行网络传输。

 CameraVideoCapturer mVideoCapturer = createVideoCapture(this);VideoSource videoSource = mPeerConnectionFactory.createVideoSource(mVideoCapturer);VideoTrack mVideoTrack = mPeerConnectionFactory.createVideoTrack("videtrack", videoSource);

4. AudioSource/AudioTrack
AudioSource/AudioTrack和上面的VideoSource/VideoTrack类似,从名字上面就知道是对音频的获取和处理了,AudioSource的创建很简单,直接用PeerConnectionFactory创建就可以了。

AudioSource audioSource = mPeerConnectionFactory.createAudioSource(new MediaConstraints());
AudioTrack mAudioTrack = mPeerConnectionFactory.createAudioTrack("audiotrack", audioSource);

AudioSource 创建的时候需要传入MediaConstraints这个对象的实例,其用于对媒体的一些约束限制,创建的时候可以直接使用默认的。如果你想自己定义,就需要自己填入相应的键值对了。

MediaConstraints audioConstraints = new MediaConstraints();
//回声消除
audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
//自动增益
audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
//高音过滤
audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
//噪音处理
audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));

5. MediaStream
音视频的媒体流,通过PeerConnectionFactory创建,用于PeerConnection通过网络传输发送给另一方。在媒体流传输之前,需要将前面获取的VideoTrack和AudioTrack添加进去。

MediaStream mMediaStream = mPeerConnectionFactory.createLocalMediaStream("localstream");
mMediaStream.addTrack(mVideoTrack);
mMediaStream.addTrack(mAudioTrack);

6. PeerConnection
用于p2p网络传输,双方信令的交换。webrtc是基于p2p的,因此在双方通信之前需要服务器帮助传递信令,并且需要添加STUN和TURN服务器网络穿透。在双方通道打开之后就可以将媒体流发送给另一方了。下面是PeerConnection的创建,并将媒体流添加到其中用于网络传输。

PeerConnection peerConnection = mPeerConnectionFactory.createPeerConnection(iceServers, pcConstraints, this);
peerConnection.addStream(mMediaStream);

参数说明如下:
iceServers连接到外网和网络穿用到的,添加STUN和TURN服务器可以帮助你连接。
constraints是一个MediaConstrains的实例。应该包含offerToRecieveAudio和offerToRecieveVideo。
observer是一个PeerConnectionObserver的实例,对PeerConnection的一些连接状态的监听。


信令交换###

在实现媒体流的网络传输之前,需要交换双方信令,将连接通道打开,下面介绍一下webrtc的信令交换机制。

  • A向B发起建立连接的请求,通过PeerConnection的createOffer()方法创建一个offer信令,创建成功后调用SdpObserver监听中的onCreateSuccess()回调函数,调用PeerConnection的setLocalDescription方法设置自己的offer信令,同时将offer信令通过服务器转发给B。
peerConnection.createOffer(sdpObserver, sdpMediaConstraints);//SdpObserver
@Override
public void onCreateSuccess(SessionDescription sessionDescription) {peerConnection.setLocalDescription(this, sessionDescription);JSONObject jsonObject = new JSONObject();try {jsonObject.put("type", sessionDescription.type.canonicalForm());jsonObject.put("description", sessionDescription.description);} catch (JSONException e) {e.printStackTrace();}mSocket.emit("SdpInfo", jsonObject.toString());
}
  • B收到A的offer信令后,创建一个SessionDescription(SDP描述符包含媒体信息,如分辨率、编解码能力等)对象将A的offer信令解析出来,并调用PeerConnection的setRemoteDescription方法设置A的SDP描述符,然后B通过PeerConnection的createAnswer()方法创建一个answer信令,创建成功后调用SdpObserver监听中的onCreateSuccess()回调函数,调用PeerConnection的setLocalDescription方法设置自己的answer信令,同时将answer信令通过服务器转发给A。
@Override
public void call(Object... args) {
if (mPeer == null) {mPeer = new Peer();}try {JSONObject jsonObject = new JSONObject(args[0].toString());SessionDescription description = new SessionDescription(SessionDescription.Type.fromCanonicalForm(jsonObject.getString("type")),jsonObject.getString("description"));mPeer.peerConnection.setRemoteDescription(mPeer, description);if (!isOffer) {mPeer.peerConnection.createAnswer(mPeer, sdpConstraints);}} catch (JSONException e) {e.printStackTrace();}
}
  • A收到B的answer信令后,解析B的answer信令再调用PeerConnection的setRemoteDescription方法设置B的SDP描述符。这样双方的信令交换就算完成了。

在非局域网下,信令的交换还需要借助于STUN和TURN服务器网络穿透,创建PeerConnection的时候需要传入iceServers这个参数,这里面存放的就是穿透地址变换的服务器地址了,类似的,Ice穿透也需要信令的交换,过程大致如下。

  • 当A和B创建好配置了iceServers的PeerConnection实例后,当网络候可用时,回调PeerConnection.Observer的onIceCandidate()函数,在回调函数里面将IceCandidate对象发送给对方。
  • 在收到对方的IceCandidate信令后,解析出来并用PeerConnection的addIceCandidate()方法设置对方的信令。
@Override
public void onIceCandidate(IceCandidate iceCandidate) {try {JSONObject jsonObject = new JSONObject();jsonObject.put("label", iceCandidate.sdpMLineIndex);jsonObject.put("id", iceCandidate.sdpMid);jsonObject.put("candidate", iceCandidate.sdp);mSocket.emit("IceInfo", jsonObject.toString());} catch (JSONException e) {e.printStackTrace();}}@Override
public void call(Object... args) {try {JSONObject jsonObject = new JSONObject(args[0].toString());IceCandidate candidate = null;candidate = new IceCandidate(jsonObject.getString("id"),jsonObject.getInt("label"),jsonObject.getString("candidate"));mPeer.peerConnection.addIceCandidate(candidate);} catch (JSONException e) {e.printStackTrace();}
}

现在,双方的连接通道就完全打开了,PeerConnection.Observer就会调用onAddStream()响应函数,里面包含对方的媒体流Mediastream,将媒体流播放就可以了。

 @Overridepublic void onAddStream(MediaStream mediaStream) {remoteVideoTrack = mediaStream.videoTracks.get(0);remoteVideoTrack.addRenderer(new VideoRenderer(remoteView));}

播放媒体流###

媒体流的播放需要用到webrtc封装的控件SurfaceViewRenderer,它继承于安卓的SurfaceView。
在播放之前,需要对该控件初始化和配置一些属性。

localView = findViewById(R.id.localVideoView);//创建EglBase对象mEglBase = EglBase.create();//初始化localViewlocalView.init(mEglBase.getEglBaseContext(), null);localView.setKeepScreenOn(true);localView.setMirror(true);localView.setZOrderMediaOverlay(true);localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);localView.setEnableHardwareScaler(false);

注意:SurfaceViewRenderer的初始化需要在主线程

初始化完成后,将localView包装成VideoRenderer对象并添加到VideoTrack中就可以进行播放了。

mVideoTrack.addRenderer(new VideoRenderer(localView));

Demo###

demo里面包含了用IoSocket简单写的java服务器(webrtc文件夹),里面的地址改成自己电脑的本机ip4地址即可测试。

demo地址:demo传送门

附上demo运行效果图

至此,安卓webrtc一对一视频聊天就介绍完了,第一次写博客,对webrtc的理解也不是很深,有不正确的地方还请各位批评指出,谢谢。

基于WebRtc实现安卓视频一对一聊天相关推荐

  1. 【复】基于 WebRTC 的音视频在线监考模块的设计与实现(上)

    文章目录 前言 什么是 WebRTC? WebRTC 架构 WebRTC 通讯内容 WebRTC 通讯协议 WebRTC 连接建立过程 后记 前言 最近在做关于考试系统的项目,其中有一项需求分析是要做 ...

  2. 基于WebRTC实现音视频及数据通信

    文章目录 前言 一.WebRTC的组成? 二.信令交换的方式 三.会话描述 四.客户端应用 1.HTML 2.JavaScript 五.效果演示 六.项目地址 总结 前言 刚写了篇基于WebRTC使用 ...

  3. 基于 WebRTC 的 RTSP 视频实时预览

    WebRTC相关视频讲解: 什么是WebRTC WebRTC入门到精通该怎么学? WebRTC框架剖析 音视频流媒体高级开发:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高 ...

  4. 基于WebRtc在H5视频聊天、视频教学、视频会议、视频直播、白板互动低延时方案

    随移动互联应用加快,4G,5G网络上马,低延时网络视频应改越来越走近生活,在教学,会议,在线医疗,招聘交友及时视频要求高等场景需求越来越大,传统基于rtmp直播应用已经大量应用在各个方向,由于rtmp ...

  5. 智能会议系统(10)---WebRtc在H5视频聊天

    基于WebRtc在H5视频聊天.视频教学.视频会议.视频直播.白板互动低延时方案 随移动互联应用加快,4G,5G网络上马,低延时网络视频应改越来越走近生活,在教学,会议,在线医疗,招聘交友及时视频要求 ...

  6. EasyRTC实现基于WebRTC技术实现的即时通信类应用

    WebRTC简介 WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API.它于2011年6月1 ...

  7. 基于webrtc技术的远程桌面控制系统(二)

    现有主流浏览器基本上都已经支持webrtc,可以基于js实现非常简洁的webrtc连接建立,我么采用了mqtt协议进行信令传输,方便设备管理.采用了开源emqx作为mqtt服务器,架构非常简介高效,可 ...

  8. 基于WebRTC实现1v1音视频聊天室

    一. 前言 WebRTC(Web Real-Time Communication)旨在将实时通信功能引入到浏览器,用户无需安装其他任何软件或插件即可在浏览器间进行实时通信功能.本文介绍基于 WebRT ...

  9. 基于webrtc的视频聊天室(一)之千里之行始于足下

    在不采用流媒体的情况下,也能够实现视频聊天室:可这需要在客户端建立多个连接,对客户端要求很高(上行带宽以及浏览器编解码速度),所以引入 kurento 流媒体服务器来做中转,或许后续不仅仅只是做中转. ...

最新文章

  1. 关于SQL视图的创建和使用方法
  2. 什么是groupid和artifactId?
  3. 120. Triangle 三角形最小路径和
  4. [HAOI2008]玩具取名
  5. 「一本通 4.1 练习 2」简单题
  6. 如果要做小程序创业,哪种方式最赚钱?
  7. php stream encoding,PHP之mb_check_encoding使用方法分享
  8. .NET单点登录实现方法----两种
  9. 《推荐系统笔记(十六)》tf-idf与基于内容的推荐(简单的酒店推荐)
  10. excel 使用排序工具实现每隔一行加一行空行
  11. jQuery的对象访问函数(get,index,size,each)
  12. 深入学习华为云IOT云平台与LiteOS轻量级物联网系统
  13. 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix
  14. emmc5.1, ufs2.0, ufs3.0
  15. 网页美学设计原则(上)
  16. 修改 nginx 的默认端口
  17. 化学系女生的工程师之路
  18. 艺赛旗(RPA)RPA8.0 解决滑动验证码完整流程
  19. 菜鸟说有线网络连接故障
  20. 周易测算网站H5源码在线起名运势测算网站系统源码

热门文章

  1. STM32F103系列GPIO的一些基本概念和知识
  2. C语言统计数字出现次数
  3. android tuner 教程,安卓调谐器(Android Tuner)
  4. 安兔兔跑分UX视频兼容性分值为0
  5. 面试:如何应对人事的面试
  6. js: 动画 筋斗云导航栏 仿淘宝关闭二维码
  7. Variable Generator/dense/kernel already exists, disallowed.
  8. html弹性盒子垂直排列,css3弹性盒子布局
  9. 学会了使用计算机之后作文,我学会了计算机
  10. 腾讯云5000亿元、阿里云2000亿元,都是投的啥?