Android WebRTC+SRS/ZLM视频通话(5):Android使用WebRTC从SRS/ZLMediaKit拉流
来自奔三人员的焦虑日志
接着上一章内容,继续来记录Android是如何使用WebRTC从SRS/ZLMediaKit拉流播放。WebRTC是一种实现实时音视频通信的技术,而SRS(SRS Streaming Cluster)和ZLMediaKit则是两种常用的流媒体服务。 Android 平台上,可以使用 WebRTC 从 SRS/ZLMediaKit 中拉取流并进行播放。
WebRTC推拉流的区别
推流:WebRTC 中的推流通常指将本地音视频流发送到远端。推流涉及到本地设备上的音视频采集、编码、传输等过程。
拉流:WebRTC 中的拉流通常指从远端获取音视频流并进行播放。拉流涉及到 RTCPeerConnection 对象的建立和音视频解码等过程。拉流可以用于实现实时音视频播放、音视频录制等场景。
总的来说,WebRTC 的推拉流都是通过 PeerConnection 对象进行实现,具体的实现细节会有一些不同。其中推流涉及到本地设备的音视频采集和编码等过程,而拉流则是接收远端的音视频流进行解码和播放。
注意:这里暂不考虑NAT可穿透服务器,详情可了解STUN/TURN 服务器的搭建和使用
别看一堆文字就头大,实际上也就是两行代码的事,注意初始化时PeerConnection!!.addTransceiver方法的参数设置即可。去掉视频、音频采集等代码,剩下的就是交换sdp的API地址变一下就好。
//拉流
if (!isPublish) {
peerConnection!!.addTransceiver(
MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,
RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)
)
peerConnection!!.addTransceiver(
MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO,
RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY)
)
}
//推流
else {
peerConnection!!.addTransceiver(
MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,
RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)
)
peerConnection!!.addTransceiver(
MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO,
RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY)
)
}
这里我已经封装成工具类,详情看WebRTCUtil
页面代码
跟推流类似,我们新增一个预览页面、播放地址文本和一个开始拉流按钮,具体看下面代码:
//拉流地址
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier.weight(1f)
) {
Text(text = playUrl.value)
}
Box(
modifier = Modifier
.clickable {
doPlay()//开始播放
}
.width(80.dp)
.background(
Color.White,
RoundedCornerShape(5.dp)
)
.border(
1.dp,
Color(0xFF000000),
shape = RoundedCornerShape(5.dp)
)
.padding(5.dp),
contentAlignment = Alignment.Center
) {
Text(text = "拉流")
}
}
//拉流部分
Box(
modifier = Modifier
.fillMaxWidth()
.height(300.dp)
) {
surfaceViewRenderer2 = mSurfaceViewRenderer2(mEglBase, webRtcUtil2!!)
AndroidView({ surfaceViewRenderer2!! }) { videoView ->
CoroutineScope(Dispatchers.Main).launch {
//根据视频大小缩放surfaceViewRenderer控件
var screenSize = "480-640"
var screenSizeD = 720 / 1280.0
val screenSizeS: Array<String> =
screenSize.split("-").toTypedArray()
screenSizeD =
screenSizeS[0].toInt() / (screenSizeS[1].toInt() * 1.0)
var finalScreenSizeD = screenSizeD
var vto = videoView.viewTreeObserver
vto.addOnPreDrawListener {
var width: Int = videoView.measuredWidth
var height: Int = (finalScreenSizeD * width).toInt()
//获取到宽度和高度后,可用于计算
var layoutParams = videoView.layoutParams
layoutParams.height = height
videoView.layoutParams = layoutParams
true
}
}
}
}
@Composable
fun mSurfaceViewRenderer2(mEglBase: EglBase, webRtcUtil2: WebRTCUtil): SurfaceViewRenderer {
val context = LocalContext.current
val surfaceViewRenderer = remember {
SurfaceViewRenderer(context).apply {
id = R.id.surface_view_2
}
}
//Makes MapView follow the lifecycle of this composable
val lifecycleObserver = rememberMapLifecycleObserver(surfaceViewRenderer, mEglBase, webRtcUtil2)
val lifecycle = LocalLifecycleOwner.current.lifecycle
DisposableEffect(lifecycle) {
lifecycle.addObserver(lifecycleObserver)
onDispose {
lifecycle.removeObserver(lifecycleObserver)
}
}
return surfaceViewRenderer
}
private var webRtcUtil2: WebRTCUtil? = null
private var playUrl =
mutableStateOf("https://192.168.1.172/index/api/webrtc?app=live&stream=test&type=play")
private var surfaceViewRenderer2: SurfaceViewRenderer? = null
/**
* 开始播放
*/
private fun doPlay() {
if (webRtcUtil2 != null) {
webRtcUtil2!!.destroy()
}
webRtcUtil2 = WebRTCUtil(this@MainActivity)
webRtcUtil2!!.create(
mEglBase,
surfaceViewRenderer2,
isPublish = false,
isShowCamera = true,
playUrl = playUrl.value,
callBack = object : WebRTCUtil.WebRtcCallBack {
override fun onSuccess() {}
override fun onFail() {}
})
}
主要新增这几个,详情可到Gitee拉取完整Demo
运行效果
第五章到这里就结束了,下节继续记录Android如何往SRS推拉流,占用您的垃圾时间了,实在对不住
THE END
感谢查阅
玉念聿辉:编辑