assume credentials are the same for all contents when restarting ICE

This commit is contained in:
Daniel Gultsch 2021-11-16 17:08:34 +01:00
parent abb671616c
commit 0a18c8613f
4 changed files with 28 additions and 17 deletions

View file

@ -1003,6 +1003,7 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe
RendererCommon.ScalingType.SCALE_ASPECT_FILL, RendererCommon.ScalingType.SCALE_ASPECT_FILL,
RendererCommon.ScalingType.SCALE_ASPECT_FIT RendererCommon.ScalingType.SCALE_ASPECT_FIT
); );
//TODO this should probably only be 'connected'
if (STATES_CONSIDERED_CONNECTED.contains(state)) { if (STATES_CONSIDERED_CONNECTED.contains(state)) {
binding.appBarLayout.setVisibility(View.GONE); binding.appBarLayout.setVisibility(View.GONE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

View file

@ -141,7 +141,6 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
} }
private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this); private final WebRTCWrapper webRTCWrapper = new WebRTCWrapper(this);
//TODO convert to Queue<Map.Entry<String, Description>>?
private final Queue<Map.Entry<String, RtpContentMap.DescriptionTransport>> pendingIceCandidates = new LinkedList<>(); private final Queue<Map.Entry<String, RtpContentMap.DescriptionTransport>> pendingIceCandidates = new LinkedList<>();
private final OmemoVerification omemoVerification = new OmemoVerification(); private final OmemoVerification omemoVerification = new OmemoVerification();
private final Message message; private final Message message;
@ -295,9 +294,13 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
private boolean checkForIceRestart(final JinglePacket jinglePacket, final RtpContentMap rtpContentMap) { private boolean checkForIceRestart(final JinglePacket jinglePacket, final RtpContentMap rtpContentMap) {
final RtpContentMap existing = getRemoteContentMap(); final RtpContentMap existing = getRemoteContentMap();
final Map<String, IceUdpTransportInfo.Credentials> existingCredentials = existing.getCredentials(); final IceUdpTransportInfo.Credentials existingCredentials;
final Map<String, IceUdpTransportInfo.Credentials> newCredentials = rtpContentMap.getCredentials(); final IceUdpTransportInfo.Credentials newCredentials;
if (!existingCredentials.keySet().equals(newCredentials.keySet())) { try {
existingCredentials = existing.getCredentials();
newCredentials = rtpContentMap.getCredentials();
} catch (final IllegalStateException e) {
Log.d(Config.LOGTAG, "unable to gather credentials for comparison", e);
return false; return false;
} }
if (existingCredentials.equals(newCredentials)) { if (existingCredentials.equals(newCredentials)) {
@ -307,11 +310,11 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
final RtpContentMap restartContentMap; final RtpContentMap restartContentMap;
try { try {
if (isOffer) { if (isOffer) {
Log.d(Config.LOGTAG, "received offer to restart ICE " + newCredentials.values()); Log.d(Config.LOGTAG, "received offer to restart ICE " + newCredentials);
restartContentMap = existing.modifiedCredentials(newCredentials, IceUdpTransportInfo.Setup.ACTPASS); restartContentMap = existing.modifiedCredentials(newCredentials, IceUdpTransportInfo.Setup.ACTPASS);
} else { } else {
final IceUdpTransportInfo.Setup setup = getPeerDtlsSetup(); final IceUdpTransportInfo.Setup setup = getPeerDtlsSetup();
Log.d(Config.LOGTAG, "received confirmation of ICE restart" + newCredentials.values() + " peer_setup=" + setup); Log.d(Config.LOGTAG, "received confirmation of ICE restart" + newCredentials + " peer_setup=" + setup);
// DTLS setup attribute needs to be rewritten to reflect current peer state // DTLS setup attribute needs to be rewritten to reflect current peer state
// https://groups.google.com/g/discuss-webrtc/c/DfpIMwvUfeM // https://groups.google.com/g/discuss-webrtc/c/DfpIMwvUfeM
restartContentMap = existing.modifiedCredentials(newCredentials, setup); restartContentMap = existing.modifiedCredentials(newCredentials, setup);
@ -319,7 +322,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
if (applyIceRestart(jinglePacket, restartContentMap, isOffer)) { if (applyIceRestart(jinglePacket, restartContentMap, isOffer)) {
return isOffer; return isOffer;
} else { } else {
Log.d(Config.LOGTAG,"ignored ice restart. offer="+isOffer); Log.d(Config.LOGTAG, "ignoring ICE restart. sending tie-break");
respondWithTieBreak(jinglePacket); respondWithTieBreak(jinglePacket);
return true; return true;
} }
@ -327,7 +330,7 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
respondOk(jinglePacket); respondOk(jinglePacket);
final Throwable rootCause = Throwables.getRootCause(exception); final Throwable rootCause = Throwables.getRootCause(exception);
if (rootCause instanceof WebRTCWrapper.PeerConnectionNotInitialized) { if (rootCause instanceof WebRTCWrapper.PeerConnectionNotInitialized) {
Log.d(Config.LOGTAG,"ignoring PeerConnectionNotInitialized"); Log.d(Config.LOGTAG, "ignoring PeerConnectionNotInitialized");
//TODO dont respond OK but respond with out-of-order //TODO dont respond OK but respond with out-of-order
return true; return true;
} }
@ -1451,8 +1454,8 @@ public class JingleRtpConnection extends AbstractJingleConnection implements Web
@Override @Override
public void onIceCandidate(final IceCandidate iceCandidate) { public void onIceCandidate(final IceCandidate iceCandidate) {
final RtpContentMap rtpContentMap = isInitiator() ? this.initiatorRtpContentMap : this.responderRtpContentMap; final RtpContentMap rtpContentMap = isInitiator() ? this.initiatorRtpContentMap : this.responderRtpContentMap;
final Collection<String> currentUfrags = Collections2.transform(rtpContentMap.getCredentials().values(), c -> c.ufrag); final String ufrag = rtpContentMap.getCredentials().ufrag;
final IceUdpTransportInfo.Candidate candidate = IceUdpTransportInfo.Candidate.fromSdpAttribute(iceCandidate.sdp, currentUfrags); final IceUdpTransportInfo.Candidate candidate = IceUdpTransportInfo.Candidate.fromSdpAttribute(iceCandidate.sdp, ufrag);
if (candidate == null) { if (candidate == null) {
Log.d(Config.LOGTAG, "ignoring (not sending) candidate: " + iceCandidate.toString()); Log.d(Config.LOGTAG, "ignoring (not sending) candidate: " + iceCandidate.toString());
return; return;

View file

@ -146,14 +146,22 @@ public class RtpContentMap {
); );
} }
public Map<String, IceUdpTransportInfo.Credentials> getCredentials() { public IceUdpTransportInfo.Credentials getCredentials() {
return Maps.transformValues(contents, dt -> dt.transport.getCredentials()); final Set<IceUdpTransportInfo.Credentials> allCredentials = ImmutableSet.copyOf(Collections2.transform(
contents.values(),
dt -> dt.transport.getCredentials()
));
final IceUdpTransportInfo.Credentials credentials = Iterables.getFirst(allCredentials, null);
if (allCredentials.size() == 1 && credentials != null) {
return credentials;
}
throw new IllegalStateException("Content map does not have distinct credentials");
} }
public IceUdpTransportInfo.Setup getDtlsSetup() { public IceUdpTransportInfo.Setup getDtlsSetup() {
final Set<IceUdpTransportInfo.Setup> setups = ImmutableSet.copyOf(Collections2.transform( final Set<IceUdpTransportInfo.Setup> setups = ImmutableSet.copyOf(Collections2.transform(
contents.values(), contents.values(),
dt->dt.transport.getFingerprint().getSetup() dt -> dt.transport.getFingerprint().getSetup()
)); ));
final IceUdpTransportInfo.Setup setup = Iterables.getFirst(setups, null); final IceUdpTransportInfo.Setup setup = Iterables.getFirst(setups, null);
if (setups.size() == 1 && setup != null) { if (setups.size() == 1 && setup != null) {
@ -170,12 +178,11 @@ public class RtpContentMap {
return count == 0; return count == 0;
} }
public RtpContentMap modifiedCredentials(Map<String, IceUdpTransportInfo.Credentials> credentialsMap, final IceUdpTransportInfo.Setup setup) { public RtpContentMap modifiedCredentials(IceUdpTransportInfo.Credentials credentials, final IceUdpTransportInfo.Setup setup) {
final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder = new ImmutableMap.Builder<>(); final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder = new ImmutableMap.Builder<>();
for (final Map.Entry<String, DescriptionTransport> content : contents.entrySet()) { for (final Map.Entry<String, DescriptionTransport> content : contents.entrySet()) {
final RtpDescription rtpDescription = content.getValue().description; final RtpDescription rtpDescription = content.getValue().description;
IceUdpTransportInfo transportInfo = content.getValue().transport; IceUdpTransportInfo transportInfo = content.getValue().transport;
final IceUdpTransportInfo.Credentials credentials = Objects.requireNonNull(credentialsMap.get(content.getKey()));
final IceUdpTransportInfo modifiedTransportInfo = transportInfo.modifyCredentials(credentials, setup); final IceUdpTransportInfo modifiedTransportInfo = transportInfo.modifyCredentials(credentials, setup);
contentMapBuilder.put(content.getKey(), new DescriptionTransport(rtpDescription, modifiedTransportInfo)); contentMapBuilder.put(content.getKey(), new DescriptionTransport(rtpDescription, modifiedTransportInfo));
} }

View file

@ -146,7 +146,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
} }
// https://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-39#section-5.1 // https://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-39#section-5.1
public static Candidate fromSdpAttribute(final String attribute, Collection<String> currentUfrags) { public static Candidate fromSdpAttribute(final String attribute, String currentUfrag) {
final String[] pair = attribute.split(":", 2); final String[] pair = attribute.split(":", 2);
if (pair.length == 2 && "candidate".equals(pair[0])) { if (pair.length == 2 && "candidate".equals(pair[0])) {
final String[] segments = pair[1].split(" "); final String[] segments = pair[1].split(" ");
@ -163,7 +163,7 @@ public class IceUdpTransportInfo extends GenericTransportInfo {
additional.put(segments[i], segments[i + 1]); additional.put(segments[i], segments[i + 1]);
} }
final String ufrag = additional.get("ufrag"); final String ufrag = additional.get("ufrag");
if (ufrag != null && !currentUfrags.contains(ufrag)) { if (ufrag != null && !ufrag.equals(currentUfrag)) {
return null; return null;
} }
final Candidate candidate = new Candidate(); final Candidate candidate = new Candidate();