1 year ago

#355940

test-img

David

Android WebRTC connection is not established in non-local network

I'm developing an Android app with a P2P call feature with WebRTC. I've faced a strange problem and cannot find a solution for already several days.

The problem is that the side A cannot connect to the side B if the side A is connected to the network N1 and the side B is connected to the network N2. When both the sides are connected to the same network N then everything works fine.

In case of different networks the devices generate candidates, exchange but cannot find the best pair...

The connection establishment algorithm is:

  • Side A creates an offer, sets a local description and sends SDP to the side B via signalling server
  • Side B sets a remote description, creates an answer and sends SDP the the side A
  • Side A sets a remote desscription
  • Side A and side B generate ICE candidates, sends them to each other and apply them.

I guarantee that the ICE candidates generated from the side A are delivered to the side B.

I guess the problem is related to TURN server. I know that non-local connection establishment needs a TURN server so I've added it.

The most useful webrtc native library log I've got in the logcat is:

(line 848): Port[e6cb70c0:0:1:0:relay:Net[lo:127.0.0.x/8:Loopback:id=1]]: Failed to send TURN message, error: 22

The local logs:

2022-03-30 20:58:29.303 26318-31936/org.hedwig D/Log: On renegotiation needed
2022-03-30 20:58:29.311 26318-31936/org.hedwig D/Log: On signaling change HAVE_LOCAL_OFFER
2022-03-30 20:58:29.314 26318-31936/org.hedwig D/Log: On ice gathering change GATHERING
2022-03-30 20:58:29.322 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:1460998643 1 udp 2122260223 *hidden* 46575 typ host generation 0 ufrag iUAZ network-id 3 network-cost 900::UNKNOWN
2022-03-30 20:58:29.326 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:559267639 1 udp 2122202367 ::1 49813 typ host generation 0 ufrag iUAZ network-id 2::UNKNOWN
2022-03-30 20:58:29.327 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:1510613869 1 udp 2122129151 127.0.0.1 42709 typ host generation 0 ufrag iUAZ network-id 1::UNKNOWN
2022-03-30 20:58:29.349 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:3596425031 1 udp 1686052607 *hidden* typ srflx raddr *hidden* rport 46575 generation 0 ufrag iUAZ network-id 3 network-cost 900:stun:*hidden*:UNKNOWN
2022-03-30 20:58:29.426 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:429321475 1 tcp 1518280447 *hidden* typ host tcptype passive generation 0 ufrag iUAZ network-id 3 network-cost 900::UNKNOWN
2022-03-30 20:58:29.426 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:1876313031 1 tcp 1518222591 ::1 37467 typ host tcptype passive generation 0 ufrag iUAZ network-id 2::UNKNOWN
2022-03-30 20:58:29.429 26318-31936/org.hedwig D/Log: On ice candidate 0:0:candidate:344579997 1 tcp 1518149375 127.0.0.1 40083 typ host tcptype passive generation 0 ufrag iUAZ network-id 1::UNKNOWN
2022-03-30 20:58:29.664 26318-31936/org.hedwig D/Log: On signaling change STABLE
2022-03-30 20:58:29.723 26318-31936/org.hedwig D/Log: On ice connection change CHECKING
2022-03-30 20:58:29.727 26318-31936/org.hedwig D/Log: On standardized ice con change: CHECKING
2022-03-30 20:58:29.728 26318-31936/org.hedwig D/Log: On connection change CONNECTING
2022-03-30 20:58:30.921 26318-31936/org.hedwig D/Log: On selected candidate pair changed $Candidate pair change event:
    remote: :-1:candidate:3011219415 1 udp 1686052607 *hidden* 56205 typ srflx raddr ***hidden*** rport 56205 generation 0 ufrag rv+a network-id 1 network-cost 50::UNKNOWN
    local: :-1:candidate:3596425031 1 udp 1686052607 *hidden* 37170 typ srflx raddr ***hidden*** rport 46575 generation 0 ufrag iUAZ network-id 3 network-cost 900::CELLULAR
    last data received ms: 0
    reason: candidate pair state changed
    estimatedDisconnectedTimeMs: 0
2022-03-30 20:58:30.923 26318-31936/org.hedwig D/Log: On standardized ice con change: CONNECTED
2022-03-30 20:58:30.927 26318-31936/org.hedwig D/Log: On ice gathering change COMPLETE
2022-03-30 20:58:34.840 26318-31936/org.hedwig D/Log: On selected candidate pair changed $Candidate pair change event:
    remote: :-1:candidate:2623950527 1 udp 41885439 ***hidden*** 61645 typ relay raddr ***hidden*** rport 56205 generation 0 ufrag rv+a network-id 1 network-cost 50::UNKNOWN
    local: :-1:candidate:3596425031 1 udp 1686052607 ***hidden*** 37170 typ srflx raddr ***hidden*** rport 46575 generation 0 ufrag iUAZ network-id 3 network-cost 900::CELLULAR
    last data received ms: 0
    reason: candidate pair state changed (after delay: 1000)
    estimatedDisconnectedTimeMs: 3881
2022-03-30 20:58:40.866 26318-31936/org.hedwig D/Log: On selected candidate pair changed $Candidate pair change event:
    remote: :-1:candidate:3011219415 1 udp 1686052607 ***hidden*** 56205 typ srflx raddr ***hidden*** rport 56205 generation 0 ufrag rv+a network-id 1 network-cost 50::UNKNOWN
    local: :-1:candidate:3596425031 1 udp 1686052607 *hidden* 37170 typ srflx raddr ***hidden*** rport 46575 generation 0 ufrag iUAZ network-id 3 network-cost 900::CELLULAR
    last data received ms: 0
    reason: candidate pair state changed
    estimatedDisconnectedTimeMs: 6013
2022-03-30 20:58:40.867 26318-31936/org.hedwig D/Log: On standardized ice con change: DISCONNECTED
2022-03-30 20:58:40.867 26318-31936/org.hedwig D/Log: On connection change DISCONNECTED
2022-03-30 20:58:46.952 26318-31936/org.hedwig D/Log: On selected candidate pair changed $Candidate pair change event:
    remote: :-1:candidate:2623950527 1 udp 41885439 ***hidden*** 61645 typ relay raddr ***hidden*** rport 56205 generation 0 ufrag rv+a network-id 1 network-cost 50::UNKNOWN
    local: :-1:candidate:3596425031 1 udp 1686052607 ***hidden*** 37170 typ srflx raddr ***hidden*** rport 46575 generation 0 ufrag iUAZ network-id 3 network-cost 900::CELLULAR
    last data received ms: 0
    reason: candidate pair state changed
    estimatedDisconnectedTimeMs: 15994
2022-03-30 20:58:50.900 26318-31936/org.hedwig D/Log: On ice connection change FAILED
2022-03-30 20:58:50.901 26318-31936/org.hedwig D/Log: On standardized ice con change: FAILED
2022-03-30 20:58:50.901 26318-31936/org.hedwig D/Log: On connection change FAILED
2022-03-30 20:58:52.585 26318-31936/org.hedwig D/Log: On ice connection change CLOSED
2022-03-30 20:58:52.585 26318-31936/org.hedwig D/Log: On connection change CLOSED
2022-03-30 20:58:52.585 26318-31936/org.hedwig D/Log: On signaling change CLOSED

I've checked my TURN server in the Trickle ICE and it seems to work

enter image description here

Here is connection factory creating code:

    private fun createPeerConnectionFactory(): PeerConnectionFactory {
        initializeFactoryOptions()
        val eglBase = EglBase.create()
        this.eglBase = eglBase
        val encoderFactory =
            DefaultVideoEncoderFactory(eglBase.eglBaseContext, true, true)
        val decoderFactory = DefaultVideoDecoderFactory(eglBase.eglBaseContext)
        val options = PeerConnectionFactory
            .Options()
            .apply {
                disableNetworkMonitor = true
            }
        return PeerConnectionFactory
            .builder()
            .setOptions(options)
            .setVideoDecoderFactory(decoderFactory)
            .setVideoEncoderFactory(encoderFactory)
            .createPeerConnectionFactory()
    }

    private fun initializeFactoryOptions() {
        val initOptions = PeerConnectionFactory
            .InitializationOptions
            .builder(context)
            .setEnableInternalTracer(true)
            .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
            .setInjectableLogger(WebRtcLoggable(), Logging.Severity.LS_VERBOSE)
            .createInitializationOptions()
        PeerConnectionFactory.initialize(initOptions)
    }

Here is the peer connection creating code:

        val stunUrl = PeerConnection.IceServer
            .builder("stun:${webRtcConfig.stunUrl}")
            .createIceServer()
        val username = generateUsername()
        val password = generatePassword(username)
        val turnUrl = PeerConnection
            .IceServer
            .builder("turn:${webRtcConfig.turnUrl}")
            .setUsername(username)
            .setPassword(password)
            .createIceServer()

        val rtcConfig = PeerConnection
            .RTCConfiguration(listOf(stunUrl, turnUrl))
            .also {
                it.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN
            }
        val connection = createPeerConnection(
            factory = peerConnectionFactory,
            config = rtcConfig
        )
    @Suppress("DEPRECATION")
    private fun createPeerConnection(
        factory: PeerConnectionFactory,
        config: PeerConnection.RTCConfiguration
    ): PeerConnection? {
        val constraints = MediaConstraints()
        constraints.optional.add(MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"))

        return factory
            .createPeerConnection(config, constraints, object : WebRtcConnectionObserver() {

                override fun onIceCandidate(p0: IceCandidate?) {
                    super.onIceCandidate(p0)
                    infoLog("On Web RTC ice candidate: $p0", tag = LOG_TAG_WEB_RTC_CONTROLLER)
                    p0
                        ?.let { candidate ->
                            onNewCandidateGenerated(candidate)
                        }
                }

                override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) {
                    super.onIceConnectionChange(p0)
                    infoLog("On Ice connection change: $p0", tag = LOG_TAG_WEB_RTC_CONTROLLER)
                }
            })
    }

Here is remote ICE candidate apply code: If remote description is null the candidate is added to a pending list remoteCandidates. When the remote description is set all the candidates from the pending list are added to the connection.

    private fun onNewCandidateFromOtherSide(
        sdp: String,
        sdpMid: String,
        sdpMLineIndex: Int
    ) {
        infoLog(
            "Got new candidate from the other side. SDP: $sdp\nsdpMid: $sdpMid\nsdpMLineIndex: $sdpMLineIndex",
            tag = LOG_TAG_WEB_RTC_CONTROLLER
        )
        val candidate = IceCandidate(
            sdpMid, sdpMLineIndex, sdp
        )
        if (peerConnection?.remoteDescription != null) {
            requirePeerConnection().addIceCandidate(candidate)
        } else {
            remoteCandidates.add(candidate)
        }
    }

The WebRTC library I use:

implementation 'org.webrtc:google-webrtc:1.0.32006'

FYI: TURN server URL is an IP address (may be useful).

My team has developed an iOS version of the same app and everything works fine on the iPhone. I cannot understand the reason of the failure on Android devices...

Thank you in advance!

android

kotlin

webrtc

p2p

0 Answers

Your Answer

Accepted video resources