直播系统源码可以说是近年来最火的互联网项目,各大直播系统源码如雨后春笋般先后兴起,转眼间主播这一行业也成为最赚钱的代名词。那我们就来从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搭建直播系统源码的全部内容了。