天天看點

基于WebRTC搭建直播系統源碼

直播系統源碼可以說是近年來最火的網際網路項目,各大直播系統源碼如雨後春筍般先後興起,轉眼間主播這一行業也成為最賺錢的代名詞。那我們就來從0開始搭建一個直播系統源碼吧。

WebRTC

WebRTC,名稱源自網頁實時通信(Web Real-Time Communication)。是一個支援網頁浏覽器進行實時語音對話或視訊對話的技術,谷歌于2010年收購獲得。2011年5月開放了工程的源代碼,成為下一代視訊通話的标準。

優點

WebRTC作為一個面向網頁浏覽器的實時語音視訊技術,主要有以下幾個優點:

具有良好的通用性,幾乎在任何平台都可以正常使用。

其使用的Interactive Connectivity Establishment(ICE)能讓各個裝置之間自動比對目前最好的通訊方式,這是很多别的技術都不具備的。

具備全雙工的能力,即雙向通訊(P2P),不僅可作為單向直播使用還能完成電子視訊會議的雙向音視訊對話。

為Google旗下,具有良好的發展前景,最重要的:開源。

開始使用

導包

這裡沒有直接使用官方的原生庫進行編譯,因為太麻煩了,網上已經有組織提供了編譯好的版本可以供我們直接使用,對庫的提供者不是很了解,不知道是屬于什麼性質的,但是幾乎市面上所有的Android端都是采用該庫是以應該沒有什麼問題。

快速開始

以下步驟都是經過分類和優化後整理出來的,加上注釋,大多都能讀懂,是以就不詳細解釋了。如有不清楚的地方可以留言問我。

初始化,Peer連接配接工廠類:

//初始化 關鍵
PeerConnectionFactory.initializeAndroidGlobals(context, true, true, true)
factory = PeerConnectionFactory()
           

獲得Media,簡單了解就是需要傳輸的音視訊流:

//擷取視訊源
val videoCapture = VideoCapturerAndroid.create(CameraEnumerationAndroid.getNameOfBackFacingDevice())
val videoSource = factory.createVideoSource(videoCapture, MediaConstraints())
//擷取音頻源
val audioSource = factory.createAudioSource(MediaConstraints())
//擷取封裝MediaTrack
val videoTrack = factory.createVideoTrack("ARDAMSv0", videoSource)
val audioTrack = factory.createAudioTrack("ARDAMSa0", audioSource)
//封裝媒體流
localMs = factory.createLocalMediaStream("ARDAMS")
localMs?.addTrack(videoTrack)
localMs?.addTrack(audioTrack)
//預覽
preview?.invoke(localMs!!)
           

配置ICE,進行網絡連接配接:

//Ice NAT穿透
val iceList = ArrayList<PeerConnection.IceServer>()
iceList.add(PeerConnection.IceServer("stun:23.21.150.121"))
iceList.add(PeerConnection.IceServer("stun:stun.l.google.com:19302"))
//媒體限制
val constraints = MediaConstraints()
constraints.mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"))
constraints.mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"))
constraints.optional.add(MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"))
pc = factory.createPeerConnection(iceList, constraints, Observer())
pc?.addStream(localMs)
           

這裡使用的是stun方式,ICE邏輯判斷邏輯很複雜,主要分為兩種方式:STUN、TURN。

STUN是将本地位址轉換成外部可通路的公網位址,說白了有點像内網穿透的意思。

TURN則是需要自己搭建,由公共的中介伺服器配置設定位址。

建立Offer:

WebRTC模型中Peer之間需要進行信令交換,而承載信令的載體就是Offer/Answer,這裡因為是實作的直播系統源碼推流端,是以建立的是Offer,如果是觀看端則需要建立Answer。

信令交換:

private inner class Observer : SdpObserver, PeerConnection.Observer {
//建立offer成功
  override fun onCreateSuccess(p0: SessionDescription?) {
    log("offer:${p0?.description}")
    pc?.setLocalDescription(Observer(), p0)
    val jsonObject = JSONObject()
    jsonObject.put("id", "presenter")
    jsonObject.put("sdpOffer", p0?.description)
    SocketUtils.sendMsg(jsonObject.toString())
    log("json:$jsonObject")
  }

//建立offer失敗
  override fun onCreateFailure(p0: String?) {
    log("error: create offer $p0")
  }

//當網絡可用即Ice穿透成功
  override fun onIceCandidate(p0: IceCandidate?) {
    val jsonObject = JSONObject()
    jsonObject.put("id", "onIceCandidate")
    val ice = JSONObject()
    ice.put("sdpMid", p0?.sdpMid)
    ice.put("sdpMLineIndex", p0?.sdpMLineIndex)
    ice.put("usernameFragment", p0?.sdp?.substringAfter("ufrag ")?.substring(0, 4))
    ice.put("candidate", p0?.sdp)
    jsonObject.put("candidate", ice)
    SocketUtils.sendMsg(jsonObject.toString())
    log("iceCandidate:$p0")
    log("json:$jsonObject")
  }
}
           

通過Socket獲得:

private fun setRemoteSdp(sdp: String) {
      val answer = SessionDescription(SessionDescription.Type.ANSWER, sdp)
      pc?.setRemoteDescription(Observer(), answer)
  }

  private fun setRemoteIce(ice: EventIceCandidate) {
      ice.candidate?.let {
          pc?.addIceCandidate(IceCandidate(
                  it.sdpMid,
                  it.sdpMLineIndex,
                  it.candidate
          ))
      }
  }
           

顯示畫面

gl_view.preserveEGLContextOnPause = true
  gl_view.keepScreenOn = true
  VideoRendererGui.setView(gl_view) {
      RtcClient(this).preview = { localMs ->
          // local and remote render
          val localRender = VideoRendererGui.createGui(
                  LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED,
                  LOCAL_WIDTH_CONNECTED, LOCAL_HEIGHT_CONNECTED,
                  RendererCommon.ScalingType.SCALE_ASPECT_FILL,
                  false)
          localMs.videoTracks[0].addRenderer(localRender)
      }
  }
           

主要流程

直播端

初始化,Peer連接配接工廠類。

擷取Media,建立GL渲染器,進入顯示就緒狀态。

配置ICE并監聽,當Candidate收集完成發送給遠端端。

建立Offer,當Offer建立完成發送給遠端端。

接收遠端端發送的ICE資訊,并設定給PeerConnection對象。

接收遠端端傳回的Answer,并設定給PeerConnection對象。

建立連接配接,開始直播。

觀看端

初始化,Peer連接配接工廠類。

擷取Media,建立GL渲染器,進入顯示就緒狀态。

配置ICE并監聽,當Candidate收集完成發送給遠端端。

接收遠端端發送的ICE資訊,并設定給PeerConnection對象。

接收遠端端發送的Offer,并設定給PeerConnection對象。

建立Answer,當Answer建立完成發送給遠端端。

建立連接配接,開始直播。

以上就是基于WebRTC搭建直播系統源碼的全部内容了。

繼續閱讀