Android SDK not gathering all ICE candidates

794 views
Skip to first unread message

Martin Kaplan

unread,
Mar 2, 2021, 4:06:13 PM3/2/21
to discuss-webrtc
I'm trying to figure out the logic, of how ICE gathering works in Android SDK and in Chrome for Android. I would have expected the offered candidates to be the same,  however they are not.

For simplicity I'll start with an example of 2 interfaces only. More advanced and problematic example is further down.

With Chrome (88) for Android I get:

candidate:1019731727 1 udp 2122260223 192.168.1.104 42655 typ host generation 0 network-id 2 network-cost 10

candidate:1243386348 1 udp 2122194687 10.94.222.157 40230 typ host generation 0 network-id 1 network-cost 900

candidate:1917068287 1 tcp 1518280447 192.168.1.104 9 typ host tcptype active generation 0 network-id 2 network-cost 10

candidate:77557020 1 tcp 1518214911 10.94.222.157 9 typ host tcptype active generation 0 network-id 1 network-cost 900

With Android SDK  I get:
(tried the 6 months old pre-built libraries, then M87, then built from tip of the tree, but they all do the same)

candidate:1019731727 1 udp 2122260223 192.168.1.104 45773 typ host generation 0 ufrag ecUa network-id 4 network-cost 10

candidate:77557020 1 tcp 1518214911 10.94.222.157 9 typ host tcptype active generation 0 ufrag ecUa network-id 3 network-cost 900


My constraints are audio only in both cases. 

To me it looks like Chrome SDK loops through all interfaces, offers them as UDP and then again the same interfaces as TCP.

In case of Android it looks like it offers the least cost interface as UDP and the  rest as TCP.

We have RTPEngine on the far end, so UDP is the only acceptable transport for the SRTP.  It is also running on IPv4 only host.

This behaviour is causing a big issue in case of IPv6 enabled devices, such as T-Mobile  US, where the IPv6 only interface is offered as the only UDP candidate and the rest of interfaces including the important IPv4 interface/address (464XLAT) are offered as TCP candidate. 

In Chrome on the Android device, we get all proper candidates and audio is established. The chosen candidate is highlighted with bold:

candidate:3118503659 1 udp 2122262783 2607:fc20:xxx:xxxx:xxxx:xxxx:xxxx:xxxx 41304 typ host generation 0 network-id 1 network-cost 900

candidate:2702152489 1 udp 2122197247 2607:fb90:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx 44809 typ host generation 0 network-id 2 network-cost 900

candidate:2833031007 1 udp 2122129151 192.0.0.4 44818 typ host generation 0 network-id 3 network-cost 900

candidate:4150487579 1 tcp 1518283007 2607:fc20:xxx:xxxx:xxxx:xxxx:xxxx:xxxx 9 typ host tcptype active generation 0 network-id 1 network-cost 900

candidate:4018958297 1 tcp 1518217471 2607:xxxx:xxxx:xxxx:xxxx:xxxx:xxx:xxxx 9 typ host tcptype active generation 0 network-id 2 network-cost 900

candidate:3865011119 1 tcp 1518149375 192.0.0.4 9 typ host tcptype active generation 0 network-id 3 network-cost 900


Android SDK however  offers following candidates (the same device). As we have UDP only and IPv4 only capabilities, no ICE connection is be negotiated and we have no audio.

candidate:2702152489 1 udp 2122197247 2607:fb90:xxxx:xxxx:xxxx:xxxx:xxx:xxxx 40361 typ host generation 0 network-id 4 network-cost 900

candidate:4150487579 1 tcp 1518283007 2607:fc20:xxx:xxxx:xxxx:xxxx:xxxx:xxxx 9 typ host tcptype active generation 0 network-id 3 network-cost 900

candidate:3865011119 1 tcp 1518149375 192.0.0.4 9 typ host tcptype active generation 0 network-id 5 network-cost 900

We tried with:
        val config = PeerConnection.RTCConfiguration(emptyList())
        config.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED
        config.disableIpv6 =  true

however that just gathers the same way, but removes the TCP and IPv6 candidates, so no candidates are being offered from Android  SDK.

Is there a reason why Android SDK is using different method for gathering candidates than Android Chrome is using? I've also tried with CHANGE_NETWORK_STATE AndroidManigest permissions added  to the native app using Android SDK, but that didn't do anything.

Thank you.

Regards,

Martin

Martin Kaplan

unread,
Mar 2, 2021, 4:34:17 PM3/2/21
to discuss-webrtc
I meant 
        config.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED 

Also to add some more details, the Android device is Pixel 4a, Android 11
Dne úterý 2. března 2021 v 22:06:13 UTC+1 uživatel Martin Kaplan napsal:

Martin Kaplan

unread,
Mar 5, 2021, 7:33:21 AM3/5/21
to discuss-webrtc
I enabled extra logging and got this:

03-04 20:33:46.295 17002 17034 I basic_port_allocator.cc: (line 1360): Net[wlan0:192.168.1.x/24:Wifi:id=4]: Allocation Phase=Udp
03-04 20:33:46.295 17002 17034 I port.cc : (line 186): Port[6f31ba40::1:0:local:Net[wlan0:192.168.1.x/24:Wifi:id=4]]: Port created with network cost 10
03-04 20:33:46.295 17002 17034 I basic_port_allocator.cc: (line 885): Adding allocated port for audio
03-04 20:33:46.295 17002 17034 I basic_port_allocator.cc: (line 906): Port[6f31ba40:audio:1:0:local:Net[wlan0:192.168.1.x/24:Wifi:id=4]]: Added port to allocator
03-04 20:33:46.295 17002 17034 I basic_port_allocator.cc: (line 924): Port[6f31ba40:audio:1:0:local:Net[wlan0:192.168.1.x/24:Wifi:id=4]]: Gathered candidate: Cand[:1019731727:1:udp:2122260223:192.168.1.x:44593:local::0:G7hS:Fmoz7nYhUxFXQI8fLagNIUNT:4:10:0]
03-04 20:33:46.295 17002 17034 I basic_port_allocator.cc: (line 957): Port[6f31ba40:audio:1:0:local:Net[wlan0:192.168.1.x/24:Wifi:id=4]]: Port ready.
03-04 20:33:46.296 17002 17036 D Clicktocall: onIceCandidate candidate=audio:0:candidate:1019731727 1 udp 2122260223 192.168.1.104 44593 typ host generation 0 ufrag G7hS network-id 4 network-cost 10::UNKNOWN
03-04 20:33:46.296 17002 17034 I basic_port_allocator.cc: (line 1068): Port[6f31ba40:audio:1:0:local:Net[wlan0:192.168.1.x/24:Wifi:id=4]]: Port completed gathering candidates.

03-04 20:33:46.296 17002 17034 I basic_port_allocator.cc: (line 1360): Net[rmnet_data2:10.241.252.x/30:Cellular:id=3]: Allocation Phase=Udp
03-04 20:33:46.296 17002 17034 I port.cc : (line 186): Port[6f31faa0::1:0:local:Net[rmnet_data2:10.241.252.x/30:Cellular:id=3]]: Port created with network cost 900
03-04 20:33:46.296 17002 17034 I android_network_monitor.cc: (line 404): Find network handle.
03-04 20:33:46.296 17002 17034 W physical_socket_server.cc: (line 217): Binding socket to network address failed; result: -1
03-04 20:33:46.296 17002 17034 E basic_packet_socket_factory.cc: (line 54): UDP bind failed with error 13
03-04 20:33:46.296 17002 17034 W stun_port.cc: (line 221): Port[6f31faa0::1:0:local:Net[rmnet_data2:10.241.252.x/30:Cellular:id=3]]: UDP socket creation failed


I looked at POSIX error codes (I believe AsyncSocket is wrapping sys/socket) and 13 is permission denied. I wonder what is Chrom(ium) doing differently so that it can bind the socket on Android, while the app cannot? I looked at AndroidManifest permissions and didn't find much more to be added.

When I install termux with python, I can bind UDP socket on any interface without any problem (and without rooting).



Dne úterý 2. března 2021 v 22:34:17 UTC+1 uživatel Martin Kaplan napsal:

Philipp Hancke

unread,
Mar 5, 2021, 8:50:52 AM3/5/21
to discuss...@googlegroups.com
Chromium uses a different socket layer, see
Odd though that it binds correctly while native doesn't.

--

---
You received this message because you are subscribed to the Google Groups "discuss-webrtc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss-webrt...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/discuss-webrtc/4580549e-6f4d-467b-8def-c5faa09dd4acn%40googlegroups.com.

twcgi...@gmail.com

unread,
Mar 8, 2021, 5:52:50 AM3/8/21
to discuss-webrtc
In case of any relevance, in order to get IPv6 only SIMS working I had to apply the following patch (to what is an older version now, for sure):
 
Built from source:
https://webrtc.googlesource.com/src/

Checked out at 00d0f178c2e0eb4b28b87d09716c5d6c6edb81ab
(matches https://bintray.com/google/webrtc/google-webrtc/1.0.30039)

with the following patch applied:

diff --git a/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java b/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java
index 0ac469c..4559c4d 100644
--- a/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java
+++ b/sdk/android/api/org/webrtc/NetworkMonitorAutoDetect.java
@@ -33,6 +33,7 @@ import android.telephony.TelephonyManager;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -471,13 +472,45 @@ public class NetworkMonitorAutoDetect extends BroadcastReceiver {

@SuppressLint("NewApi")
IPAddress[] getIPAddresses(LinkProperties linkProperties) {
- IPAddress[] ipAddresses = new IPAddress[linkProperties.getLinkAddresses().size()];
- int i = 0;
- for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
- ipAddresses[i] = new IPAddress(linkAddress.getAddress().getAddress());
- ++i;
- }
- return ipAddresses;
+ ArrayList<IPAddress> retVal = new ArrayList<>();
+ for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
+ retVal.add(new IPAddress(linkAddress.getAddress().getAddress()));
+ }
+ // IP address(es) from any "stacked" 464XLAT interface not yet included
+ // see: https://bugs.chromium.org/p/webrtc/issues/detail?id=9925
+ addStackedIPAddresses(linkProperties, retVal);
+ return retVal.toArray(new IPAddress[0]);
+ }
+
+ private void addStackedIPAddresses(LinkProperties linkProperties, ArrayList<IPAddress> addTo) {
+ // required info from the "stacked" interface only available via @hide methods in LinkProperties
+ // but *is* available from LinkProperties.toString(): not ideal, but only option w/o radical change
+ String str = linkProperties.toString();
+ int startSearch = str.indexOf("Stacked");
+ if (-1 != startSearch) {
+ // LinkAddresses: [192.0.0.4/32,]
+ int linkAddressesIdx;
+ do {
+ linkAddressesIdx = str.indexOf("LinkAddresses", startSearch);
+ if (-1 != linkAddressesIdx) {
+ int start = str.indexOf('[', linkAddressesIdx);
+ if (-1 != start) {
+ int end = str.indexOf(']', start);
+ if (-1 != end) {
+ for (String ipStr : str.substring(start+1, end).split(",")) {
+ try {
+ addTo.add(new IPAddress(
+ InetAddress.getByName(ipStr.replaceAll("/32", "").trim()).getAddress()));
+ } catch (UnknownHostException e) {
+ Logging.e(TAG, "Stacked Link InetAddress could not be parsed from " + ipStr, e);
+ }
+ }
+ }
+ }
+ startSearch = linkAddressesIdx + 1;
+ }
+ } while (-1 != linkAddressesIdx);
+ }
}

@SuppressLint("NewApi")

Philipp Hancke

unread,
Mar 9, 2021, 7:12:34 AM3/9/21
to discuss...@googlegroups.com

--

---
You received this message because you are subscribed to the Google Groups "discuss-webrtc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to discuss-webrt...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages