gpt4 book ai didi

Android WebRTC 不适用于不同的网络 - 无视频

转载 作者:行者123 更新时间:2023-12-05 07:25:20 25 4
gpt4 key购买 nike

我正在尝试通过 webrtc 将视频从 Raspberry Pi 流式传输到 android 设备。我正在使用 firebase (firestore) 作为信号。我可以在连接到同一个 wifi 时运行设置,但是当使用不同的网络时它会失败。

设备 - RPI

客户端1) Web 客户端(托管在 firebase 上)2) 安卓应用

在设备和客户端之间的同一网络(wifi)上,两个客户端都能够播放视频和音频。

但是当设备和客户端在不同的网络上时,web 客户端可以显示视频,但 Android 应用程序无法显示视频。

信号正常工作,设备上的摄像头和麦克风已启动,冰候选物已成功交换。我还在 android 上添加了远程流(调用了 onAddStream)。但是没有视频和音频在播放。

安卓对等连接客户端

    class PeerConnectionClient(private val activity: MainActivity, private val fSignalling: FSignalling) {

internal var isVideoRunning = false

private val rootEglBase by lazy {
EglBase.create()
}

private val peerConnectionFactory: PeerConnectionFactory by lazy {
val initializationOptions = PeerConnectionFactory.InitializationOptions.builder(activity).createInitializationOptions()
PeerConnectionFactory.initialize(initializationOptions)

val options = PeerConnectionFactory.Options()
val defaultVideoEncoderFactory = DefaultVideoEncoderFactory(rootEglBase.eglBaseContext, true, true)
val defaultVideoDecoderFactory = DefaultVideoDecoderFactory(rootEglBase.eglBaseContext)
PeerConnectionFactory.builder()
.setOptions(options)
.setVideoEncoderFactory(defaultVideoEncoderFactory)
.setVideoDecoderFactory(defaultVideoDecoderFactory)
.createPeerConnectionFactory()
}

private val iceServersList = mutableListOf("stun:stun.l.google.com:19302")

private var sdpConstraints: MediaConstraints? = null
private var localAudioTrack: AudioTrack? = null

private var localPeer: PeerConnection? = null

private var gotUserMedia: Boolean = false
private var peerIceServers: MutableList<PeerConnection.IceServer> = ArrayList()

init {
peerIceServers.add(PeerConnection.IceServer.builder(iceServersList).createIceServer())

// activity.surface_view.release()
activity.surface_view.init(rootEglBase.eglBaseContext, null)
activity.surface_view.setZOrderMediaOverlay(true)

createPeer()
}

private fun createPeer() {
sdpConstraints = MediaConstraints()


val audioconstraints = MediaConstraints()
val audioSource = peerConnectionFactory.createAudioSource(audioconstraints)
localAudioTrack = peerConnectionFactory.createAudioTrack("101", audioSource)
gotUserMedia = true

activity.runOnUiThread {
if (localAudioTrack != null) {
createPeerConnection()
// doCall()
}
}

}

/**
* Creating the local peerconnection instance
*/
private fun createPeerConnection() {
val constraints = MediaConstraints()
constraints.mandatory.add(MediaConstraints.KeyValuePair("offerToReceiveAudio", "true"))
constraints.mandatory.add(MediaConstraints.KeyValuePair("offerToReceiveVideo", "true"))
constraints.optional.add(MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"))

val rtcConfig = PeerConnection.RTCConfiguration(peerIceServers)
// TCP candidates are only useful when connecting to a server that supports
// ICE-TCP.
rtcConfig.enableDtlsSrtp = true
rtcConfig.enableRtpDataChannel = true
// rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED
// rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE
// rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE
// rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY
// Use ECDSA encryption.
// rtcConfig.keyType = PeerConnection.KeyType.ECDSA
localPeer = peerConnectionFactory.createPeerConnection(rtcConfig, constraints, object : PeerObserver {
override fun onIceCandidate(p0: IceCandidate) {
super.onIceCandidate(p0)
onIceCandidateReceived(p0)
}

override fun onAddStream(p0: MediaStream) {
activity.showToast("Received Remote stream")
super.onAddStream(p0)
gotRemoteStream(p0)
}

})

addStreamToLocalPeer()
}

/**
* Adding the stream to the localpeer
*/
private fun addStreamToLocalPeer() {
//creating local mediastream
val stream = peerConnectionFactory.createLocalMediaStream("102")
stream.addTrack(localAudioTrack)
localPeer!!.addStream(stream)
}

/**
* This method is called when the app is initiator - We generate the offer and send it over through socket
* to remote peer
*/
/*private fun doCall() {
localPeer!!.createOffer(object : mySdpObserver {
override fun onCreateSuccess(p0: SessionDescription) {
super.onCreateSuccess(p0)
localPeer!!.setLocalDescription(object: mySdpObserver {}, p0)
Log.d("onCreateSuccess", "SignallingClient emit ")
}
}, sdpConstraints)
}*/

private fun onIceCandidateReceived(iceCandidate: IceCandidate) {
//we have received ice candidate. We can set it to the other peer.
if (localPeer == null) {
return
}

val message = JSONObject()
message.put("type", "candidate")
message.put("label", iceCandidate.sdpMLineIndex)
message.put("id", iceCandidate.sdpMid)
message.put("candidate", iceCandidate.serverUrl)

fSignalling.doSignalingSend(message.toString())
}

private fun gotRemoteStream(stream: MediaStream) {
isVideoRunning = true
//we have remote video stream. add to the renderer.
val videoTrack = stream.videoTracks[0]
videoTrack.setEnabled(true)
activity.runOnUiThread {
try {
// val remoteRenderer = VideoRenderer(surface_view)
activity.surface_view.visibility = View.VISIBLE
// videoTrack.addRenderer(remoteRenderer)
videoTrack.addSink(activity.surface_view)
} catch (e: Exception) {
e.printStackTrace()
}
}
}

fun onReceivePeerMessage(data: JSONObject) {
if (data.getString("type") == "offer") {
// val sdpReturned = SdpUtils.forceChosenVideoCodec(data.getString("sdp"), "H264")
val sdpReturned = data.getString("sdp")
// data.remove("sdp")
// data.put("sdp", sdpReturned)

val sessionDescription = SessionDescription(SessionDescription.Type.OFFER, sdpReturned)

localPeer?.setRemoteDescription(object: mySdpObserver { }, sessionDescription)

localPeer?.createAnswer(object : mySdpObserver {
override fun onCreateSuccess(p0: SessionDescription) {
super.onCreateSuccess(p0)
localPeer!!.setLocalDescription( object : mySdpObserver {}, p0)

val description = JSONObject()
description.put("type", p0.type.canonicalForm())
description.put("sdp", p0.description)

this@PeerConnectionClient.fSignalling.doSignalingSend(description.toString())
}

override fun onCreateFailure(p0: String) {
super.onCreateFailure(p0)
activity.showToast("Failed to create answer")
}

}, MediaConstraints())

} else if (data.getString("type") == "candidate") {
val iceCandidates = IceCandidate(data.getString("id"), data.getInt("label"), data.getString("candidate"))
localPeer?.addIceCandidate(iceCandidates)
}
}

internal fun close() {
isVideoRunning = false
localPeer?.close()
localPeer = null
}
}

我的印象是,如果 Web 客户端能够在不同的网络(移动热点)上显示视频,那么 Web 客户端使用的同一互联网上的 Android 客户端也应该能够显示视频。这是错的吗?为什么android不显示视频(调用onAddStream)

是否需要使用Turn server?我的再次假设是如果 Web 客户端有效,那么 android 也应该有效。我在 RPI 上使用的服务不支持 turn server。

附加信息:设备在双 natted ISP 后面(我猜)(但由于 Web 客户端可以连接,所以我猜这不会成为问题)。

最佳答案

我找到了解决问题的方法

我在用

private fun onIceCandidateReceived(iceCandidate: IceCandidate) {
//we have received ice candidate. We can set it to the other peer.
if (localPeer == null) {
return
}

val message = JSONObject()
message.put("type", "candidate")
message.put("label", iceCandidate.sdpMLineIndex)
message.put("id", iceCandidate.sdpMid)
message.put("candidate", iceCandidate.serverUrl)

fSignalling.doSignalingSend(message.toString())
}

而是需要使用

message.put("candidate", iceCandidate.sdp) // iceCandidate.serverUrl)

关于Android WebRTC 不适用于不同的网络 - 无视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54893790/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com