WebRTC Android API

WebRTC Android API

WebRTC For Android相关的API有VideoCapturerAndroid, VideoRenderer, MediaStream, PeerConnection 和 PeerConnectionFactory等。通过这些功能完善、说明详细的API,可以显示任何想要显示的本地音视频流和远程音视频流。下面我们将逐一讲解。

类图

WebRTC Android API类图

PeerConnectionFactory

PeerConnectionFactory是WebRTC Android API最核心的类。理解这个类并了解它如何使用是深入了解Android WebRTC开发的关键。
首先需要初始化PeerConnectionFactory,如下:
// First, we initiate the PeerConnectionFactory with // our application context and some options. PeerConnectionFactory.initializeAndroidGlobals( context, initializeAudio, initializeVideo, videoCodecHwAcceleration);

为了理解这个方法,需要了解每个参数的意义:

context
    应用上下文,或者上下文相关的,和其他地方传递的一样。

initializeAudio
    是否初始化音频的布尔值。

initializeVideo
    是否初始化视频的布尔值。跳过这两个就允许跳过请求API的相关权限,例如DataChannel应用。

videoCodecHwAcceleration
    是否允许硬件加速的布尔值。

initializeAndroidGlobals()返回布尔值,true表示一切OK,false表示有失败。

如果一切ok,可以使用PeerConnectionFactory 的构造方法创建工厂:
PeerConnectionFactory peerConnectionFactory = new PeerConnectionFactory();

有了peerConnectionFactory实例,就可以从用户设备获取视频和音频,最终将其渲染到屏幕上。

VideoCapturerAndroid & CameraEnumerationAndroid

VideoCapturerAndroid是VideoCapturer接口的实现,封装了一系列Camera API,为访问摄像头设备的流信息提供了方便。要创建VideoCapturerAndroid的实例,首先需要通过CameraEnumerationAndroid类获取摄像头设备基本信息,如数量、名称。如下:

// Returns the number of camera devices
CameraEnumerationAndroid.getDeviceCount();

// Returns the name of the camera with camera index. Returns null if the
// camera can not be used.
CameraEnumerationAndroid.getDeviceName(0);

// Returns the front face device name
CameraEnumerationAndroid.getNameOfFrontFacingDevice();
// Returns the back facing device name
CameraEnumerationAndroid.getNameOfBackFacingDevice();
// Creates a VideoCapturerAndroid instance for the device name
VideoCapturerAndroid.create(name);

有了包含摄像流信息的VideoCapturerAndroid实例,就可以创建从本地设备获取到的包含视频流信息的MediaStream,从而发送给另一端。但做这些之前,我们首先研究下如何将自己的视频显示到应用上面。

VideoSource & VideoTrack

从VideoCapturer实例中获取一些有用信息,或者要达到最终目标————为连接端获取合适的媒体流,或者仅仅是将它渲染给用户,我们需要了解VideoSource 和 VideoTrack类。

VideoSource允许方法开启、停止设备捕获视频。这在为了延长电池寿命而禁止视频捕获的情况下比较有用。

VideoTrack 是简单的添加VideoSource到MediaStream 对象的一个封装。

我们通过代码看看它们是如何一起工作的。capturer是VideoCapturer的实例,videoConstraints是MediaConstraints的实例。

// First we create a VideoSource
VideoSource videoSource = 
    peerConnectionFactory.createVideoSource(capturer, videoConstraints);

// Once we have that, we can create our VideoTrack
// Note that VIDEO_TRACK_ID can be any string that uniquely
// identifies that video track in your application
VideoTrack localVideoTrack = 
    peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);

AudioSource/AudioTrack

AudioSource和AudioTrack与VideoSource和VideoTrack相似,只是不需要AudioCapturer 来获取麦克风,audioConstraints是 MediaConstraints的一个实例。

// First we create an AudioSource
AudioSource audioSource =
    peerConnectionFactory.createAudioSource(audioConstraints);

// Once we have that, we can create our AudioTrack
// Note that AUDIO_TRACK_ID can be any string that uniquely
// identifies that audio track in your application
AudioTrack localAudioTrack =
    peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource);

VideoRenderer

通过把VideoRenderer.Callbacks的实现作为参数传入VideoRenderer的构造方法,WebRTC允许实现自己的渲染。另外,它提供了一种非常好的默认方式VideoRendererGui。简而言之,VideoRendererGui是一个GLSurfaceView ,使用它可以绘制自己的视频流。我们通过代码看一下它是如何工作的,以及如何添加renderer 到 VideoTrack。

// To create our VideoRenderer, we can use the 
// included VideoRendererGui for simplicity
// First we need to set the GLSurfaceView that it should render to
GLSurfaceView videoView = (GLSurfaceView) findViewById(R.id.glview_call);

// Then we set that view, and pass a Runnable
// to run once the surface is ready
VideoRendererGui.setView(videoView, runnable);

// Now that VideoRendererGui is ready, we can get our VideoRenderer
VideoRenderer renderer = VideoRendererGui.createGui(x, y, width, height);

// And finally, with our VideoRenderer ready, we
// can add our renderer to the VideoTrack.
localVideoTrack.addRenderer(renderer);

也可以通过SurfaceViewRenderer创建VideoRenderer的实例并添加到VideoTrack。SurfaceViewRenderer是一个SurfaceView并实现了VideoRenderer.Callbacks接口。

SurfaceViewRenderer localRender = (SurfaceViewRenderer) findViewById(R.id.local_video_view);

VideoRenderer renderer = new VideoRenderer(localRender);

localVideoTrack.addRenderer(renderer);

MediaConstraints

MediaConstraints是MediaStream中音频和视频轨道的各种约束。对于大多数需要MediaConstraints的方法,一个简单的MediaConstraints实例就可以做到。

MediaConstraints audioConstraints = new MediaConstraints();

MediaStream

现在可以在本地看见自己了,接下来就要想办法让对方看见自己。这需要创建MediaStream,然后将其添加到PeerConnection 传送给对方。接下来我们就研究如何添加本地的VideoTrack 和AudioTrack来创建一个合适的MediaStream。

// We start out with an empty MediaStream object, 
// created with help from our PeerConnectionFactory
// Note that LOCAL_MEDIA_STREAM_ID can be any string
MediaStream mediaStream = peerConnectionFactory.createLocalMediaStream(LOCAL_MEDIA_STREAM_ID);

// Now we can add our tracks.
mediaStream.addTrack(localVideoTrack);
mediaStream.addTrack(localAudioTrack);

我们现在有了包含视频流和音频流的MediaStream实例,而且在屏幕上显示了我们的脸庞。现在就该把这些信息传送给对方了。

PeerConnection

现在我们有了自己的MediaStream,就可以开始连接远端了。这可以通过PeerConnection实现。创建PeerConnection很简单,只需要PeerConnectionFactory的协助即可。

PeerConnection peerConnection = peerConnectionFactory.createPeerConnection( iceServers, constraints,  observer);

参数的作用如下:

iceServers
    连接到外部设备或者网络时需要用到这个参数。在这里添加STUN 和 TURN 服务器就允许进行连接,即使在网络条件很差的条件下。

constraints
    MediaConstraints的一个实例,应该包含offerToRecieveAudio 和 offerToRecieveVideo

observer
     PeerConnection.Observer的一个实例。

PeerConnection 包含了addStream、addIceCandidate、createOffer、createAnswer、getLocalDescription、setRemoteDescription 和其他类似方法。我们快速浏览一下这几个重要的方法,看它们是如何工作的。
addStream
这个是用来将MediaStream 添加到PeerConnection中的,如同它的命名一样。如果你想要对方看到你的视频、听到你的声音,就需要用到这个方法。

addIceCandidate
一旦内部IceFramework发现有candidates允许其他方连接你时,就会创建IceCandidates 。当通过PeerConnectionObserver.onIceCandidate传递数据到对方时,需要通过任何一个你选择的信号通道获取到对方的IceCandidates。使用addIceCandidate 添加它们到PeerConnection,以便PeerConnection可以通过已有信息试图连接对方。

createOffer/createAnswer
这两个方法用于原始通话的建立。如你所知,在WebRTC中,已经有了caller和callee的概念,一个是呼叫,一个是应答。createOffer是caller使用的,它需要一个sdpObserver,它允许获取和传输会话描述协议Session Description Protocol (SDP)给对方,还需要一个MediaConstraint。一旦对方得到了这个请求,它将创建一个应答并将其传输给caller。SDP是用来给对方描述期望格式的数据(如video、formats、codecs、encryption、resolution、 size等)。一旦caller收到这个应答信息,双方就相互建立的通信需求达成了一致,如视频、音频、解码器等。

setLocalDescription/setRemoteDescription
这个是用来设置createOffer和createAnswer产生的SDP数据的,包含从远端获取到的数据。它允许内部PeerConnection 配置链接以便一旦开始传输音频和视频就可以开始真正工作。

PeerConnection.Observer

这个接口提供了一种监测PeerConnection事件的方法,例如收到MediaStream时,或者发现iceCandidates 时,或者需要重新建立通讯时。这个接口必须被实现,以便你可以有效处理收到的事件,例如当对方变为可见时,向他们发送信号iceCandidates。

调用顺序

发起呼叫
发起呼叫
接受呼叫
接受呼叫
关闭连接
关闭连接

Demo

AppRTCDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容