WebRTC Android API
WebRTC For Android相關(guān)的API有VideoCapturerAndroid, VideoRenderer, MediaStream, PeerConnection 和 PeerConnectionFactory等盼砍。通過(guò)這些功能完善列另、說(shuō)明詳細(xì)的API,可以顯示任何想要顯示的本地音視頻流和遠(yuǎn)程音視頻流毒涧。下面我們將逐一講解昧港。
類(lèi)圖
PeerConnectionFactory
PeerConnectionFactory是WebRTC Android API最核心的類(lèi)扔罪。理解這個(gè)類(lèi)并了解它如何使用是深入了解Android WebRTC開(kāi)發(fā)的關(guān)鍵始腾。
首先需要初始化PeerConnectionFactory,如下:
// First, we initiate the PeerConnectionFactory with // our application context and some options. PeerConnectionFactory.initializeAndroidGlobals( context, initializeAudio, initializeVideo, videoCodecHwAcceleration);
為了理解這個(gè)方法呕寝,需要了解每個(gè)參數(shù)的意義:
context
應(yīng)用上下文勋眯,或者上下文相關(guān)的,和其他地方傳遞的一樣。
initializeAudio
是否初始化音頻的布爾值凡恍。
initializeVideo
是否初始化視頻的布爾值志秃。跳過(guò)這兩個(gè)就允許跳過(guò)請(qǐng)求API的相關(guān)權(quán)限,例如DataChannel應(yīng)用嚼酝。
videoCodecHwAcceleration
是否允許硬件加速的布爾值浮还。
initializeAndroidGlobals()返回布爾值,true表示一切OK闽巩,false表示有失敗钧舌。
如果一切ok,可以使用PeerConnectionFactory 的構(gòu)造方法創(chuàng)建工廠:
PeerConnectionFactory peerConnectionFactory = new PeerConnectionFactory();
有了peerConnectionFactory實(shí)例涎跨,就可以從用戶設(shè)備獲取視頻和音頻洼冻,最終將其渲染到屏幕上。
VideoCapturerAndroid & CameraEnumerationAndroid
VideoCapturerAndroid是VideoCapturer接口的實(shí)現(xiàn)隅很,封裝了一系列Camera API撞牢,為訪問(wèn)攝像頭設(shè)備的流信息提供了方便。要?jiǎng)?chuàng)建VideoCapturerAndroid的實(shí)例叔营,首先需要通過(guò)CameraEnumerationAndroid類(lèi)獲取攝像頭設(shè)備基本信息屋彪,如數(shù)量、名稱绒尊。如下:
// 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實(shí)例畜挥,就可以創(chuàng)建從本地設(shè)備獲取到的包含視頻流信息的MediaStream,從而發(fā)送給另一端婴谱。但做這些之前蟹但,我們首先研究下如何將自己的視頻顯示到應(yīng)用上面。
VideoSource & VideoTrack
從VideoCapturer實(shí)例中獲取一些有用信息谭羔,或者要達(dá)到最終目標(biāo)————為連接端獲取合適的媒體流华糖,或者僅僅是將它渲染給用戶,我們需要了解VideoSource 和 VideoTrack類(lèi)口糕。
VideoSource允許方法開(kāi)啟缅阳、停止設(shè)備捕獲視頻磕蛇。這在為了延長(zhǎng)電池壽命而禁止視頻捕獲的情況下比較有用景描。
VideoTrack 是簡(jiǎn)單的添加VideoSource到MediaStream 對(duì)象的一個(gè)封裝。
我們通過(guò)代碼看看它們是如何一起工作的秀撇。capturer是VideoCapturer的實(shí)例超棺,videoConstraints是MediaConstraints的實(shí)例。
// 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 來(lái)獲取麥克風(fēng)棠绘,audioConstraints是 MediaConstraints的一個(gè)實(shí)例。
// 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
通過(guò)把VideoRenderer.Callbacks的實(shí)現(xiàn)作為參數(shù)傳入VideoRenderer的構(gòu)造方法,WebRTC允許實(shí)現(xiàn)自己的渲染氧苍。另外夜矗,它提供了一種非常好的默認(rèn)方式VideoRendererGui。簡(jiǎn)而言之让虐,VideoRendererGui是一個(gè)GLSurfaceView 紊撕,使用它可以繪制自己的視頻流。我們通過(guò)代碼看一下它是如何工作的赡突,以及如何添加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);
也可以通過(guò)SurfaceViewRenderer創(chuàng)建VideoRenderer的實(shí)例并添加到VideoTrack。SurfaceViewRenderer是一個(gè)SurfaceView并實(shí)現(xiàn)了VideoRenderer.Callbacks接口惭缰。
SurfaceViewRenderer localRender = (SurfaceViewRenderer) findViewById(R.id.local_video_view);
VideoRenderer renderer = new VideoRenderer(localRender);
localVideoTrack.addRenderer(renderer);
MediaConstraints
MediaConstraints是MediaStream中音頻和視頻軌道的各種約束浪南。對(duì)于大多數(shù)需要MediaConstraints的方法,一個(gè)簡(jiǎn)單的MediaConstraints實(shí)例就可以做到漱受。
MediaConstraints audioConstraints = new MediaConstraints();
MediaStream
現(xiàn)在可以在本地看見(jiàn)自己了络凿,接下來(lái)就要想辦法讓對(duì)方看見(jiàn)自己。這需要?jiǎng)?chuàng)建MediaStream昂羡,然后將其添加到PeerConnection 傳送給對(duì)方喷众。接下來(lái)我們就研究如何添加本地的VideoTrack 和AudioTrack來(lái)創(chuàng)建一個(gè)合適的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);
我們現(xiàn)在有了包含視頻流和音頻流的MediaStream實(shí)例紧憾,而且在屏幕上顯示了我們的臉龐〉角В現(xiàn)在就該把這些信息傳送給對(duì)方了。
PeerConnection
現(xiàn)在我們有了自己的MediaStream赴穗,就可以開(kāi)始連接遠(yuǎn)端了憔四。這可以通過(guò)PeerConnection實(shí)現(xiàn)。創(chuàng)建PeerConnection很簡(jiǎn)單般眉,只需要PeerConnectionFactory的協(xié)助即可了赵。
PeerConnection peerConnection = peerConnectionFactory.createPeerConnection( iceServers, constraints, observer);
參數(shù)的作用如下:
iceServers
連接到外部設(shè)備或者網(wǎng)絡(luò)時(shí)需要用到這個(gè)參數(shù)。在這里添加STUN 和 TURN 服務(wù)器就允許進(jìn)行連接甸赃,即使在網(wǎng)絡(luò)條件很差的條件下柿汛。
constraints
MediaConstraints的一個(gè)實(shí)例,應(yīng)該包含offerToRecieveAudio 和 offerToRecieveVideo
observer
PeerConnection.Observer的一個(gè)實(shí)例埠对。
PeerConnection 包含了addStream络断、addIceCandidate、createOffer项玛、createAnswer貌笨、getLocalDescription、setRemoteDescription 和其他類(lèi)似方法襟沮。我們快速瀏覽一下這幾個(gè)重要的方法锥惋,看它們是如何工作的昌腰。
addStream
這個(gè)是用來(lái)將MediaStream 添加到PeerConnection中的,如同它的命名一樣。如果你想要對(duì)方看到你的視頻膀跌、聽(tīng)到你的聲音遭商,就需要用到這個(gè)方法。
addIceCandidate
一旦內(nèi)部IceFramework發(fā)現(xiàn)有candidates允許其他方連接你時(shí)捅伤,就會(huì)創(chuàng)建IceCandidates 株婴。當(dāng)通過(guò)PeerConnectionObserver.onIceCandidate傳遞數(shù)據(jù)到對(duì)方時(shí),需要通過(guò)任何一個(gè)你選擇的信號(hào)通道獲取到對(duì)方的IceCandidates暑认。使用addIceCandidate 添加它們到PeerConnection困介,以便PeerConnection可以通過(guò)已有信息試圖連接對(duì)方。
createOffer/createAnswer
這兩個(gè)方法用于原始通話的建立蘸际。如你所知座哩,在WebRTC中,已經(jīng)有了caller和callee的概念粮彤,一個(gè)是呼叫根穷,一個(gè)是應(yīng)答。createOffer是caller使用的导坟,它需要一個(gè)sdpObserver屿良,它允許獲取和傳輸會(huì)話描述協(xié)議Session Description Protocol (SDP)給對(duì)方,還需要一個(gè)MediaConstraint惫周。一旦對(duì)方得到了這個(gè)請(qǐng)求尘惧,它將創(chuàng)建一個(gè)應(yīng)答并將其傳輸給caller。SDP是用來(lái)給對(duì)方描述期望格式的數(shù)據(jù)(如video递递、formats喷橙、codecs、encryption登舞、resolution贰逾、 size等)。一旦caller收到這個(gè)應(yīng)答信息菠秒,雙方就相互建立的通信需求達(dá)成了一致疙剑,如視頻、音頻践叠、解碼器等言缤。
setLocalDescription/setRemoteDescription
這個(gè)是用來(lái)設(shè)置createOffer和createAnswer產(chǎn)生的SDP數(shù)據(jù)的,包含從遠(yuǎn)端獲取到的數(shù)據(jù)酵熙。它允許內(nèi)部PeerConnection 配置鏈接以便一旦開(kāi)始傳輸音頻和視頻就可以開(kāi)始真正工作轧简。
PeerConnection.Observer
這個(gè)接口提供了一種監(jiān)測(cè)PeerConnection事件的方法驰坊,例如收到MediaStream時(shí)匾二,或者發(fā)現(xiàn)iceCandidates 時(shí),或者需要重新建立通訊時(shí)。這個(gè)接口必須被實(shí)現(xiàn)察藐,以便你可以有效處理收到的事件皮璧,例如當(dāng)對(duì)方變?yōu)榭梢?jiàn)時(shí),向他們發(fā)送信號(hào)iceCandidates分飞。