diff --git a/sdk/android/api/org/webrtc/PeerConnection.java b/sdk/android/api/org/webrtc/PeerConnection.java index 468413ba2f..56d584e75a 100644 --- a/sdk/android/api/org/webrtc/PeerConnection.java +++ b/sdk/android/api/org/webrtc/PeerConnection.java @@ -432,9 +432,10 @@ public class PeerConnection { /** * Java version of webrtc::SdpSemantics. * - * Configure the SDP semantics used by this PeerConnection. Note that the - * WebRTC 1.0 specification requires UNIFIED_PLAN semantics. The - * RtpTransceiver API is only available with UNIFIED_PLAN semantics. + * Configure the SDP semantics used by this PeerConnection. That the WebRTC + * 1.0 specification requires UNIFIED_PLAN semantics and the RtpTransceiver + * API is only available with UNIFIED_PLAN semantics. PLAN_B is being + * deprecated and will be removed at a future date. * *

PLAN_B will cause PeerConnection to create offers and answers with at * most one audio and one video m= section with multiple RtpSenders and @@ -448,13 +449,27 @@ public class PeerConnection { * will also cause PeerConnection to ignore all but the first a=ssrc lines * that form a Plan B stream. * - *

For users who wish to send multiple audio/video streams and need to stay - * interoperable with legacy WebRTC implementations, specify PLAN_B. + *

For users who have to interwork with legacy WebRTC implementations, it + * is possible to specify PLAN_B until the code is finally removed + * (https://crbug.com/webrtc/13528). * - *

For users who wish to send multiple audio/video streams and/or wish to - * use the new RtpTransceiver API, specify UNIFIED_PLAN. + *

The default SdpSemantics value is about to change to UNIFIED_PLAN. + * During a short transition period, NOT_SPECIFIED is used to ensure clients + * that don't set SdpSemantics are aware of the change by CHECK-crashing. + * TODO(https://crbug.com/webrtc/11121): When the default has changed to + * UNIFIED_PLAN, delete NOT_SPECIFIED. */ - public enum SdpSemantics { PLAN_B, UNIFIED_PLAN } + public enum SdpSemantics { + // TODO(https://crbug.com/webrtc/13528): Remove support for PLAN_B. + @Deprecated PLAN_B, + UNIFIED_PLAN, + // The default SdpSemantics value is about to change to UNIFIED_PLAN. During + // a short transition period, NOT_SPECIFIED is used to ensure clients that + // don't set SdpSemantics are aware of the change by CHECK-crashing. + // TODO(https://crbug.com/webrtc/11121): When the default has changed to + // kUnifiedPlan, delete kNotSpecified. + NOT_SPECIFIED + } /** Java version of PeerConnectionInterface.RTCConfiguration */ // TODO(qingsi): Resolve the naming inconsistency of fields with/without units. @@ -611,7 +626,7 @@ public class PeerConnection { screencastMinBitrate = null; combinedAudioVideoBwe = null; networkPreference = AdapterType.UNKNOWN; - sdpSemantics = SdpSemantics.PLAN_B; + sdpSemantics = SdpSemantics.NOT_SPECIFIED; activeResetSrtpParams = false; cryptoOptions = null; turnLoggingId = null; diff --git a/sdk/android/api/org/webrtc/PeerConnectionFactory.java b/sdk/android/api/org/webrtc/PeerConnectionFactory.java index 2b33c6ccd9..e9cf6d3e21 100644 --- a/sdk/android/api/org/webrtc/PeerConnectionFactory.java +++ b/sdk/android/api/org/webrtc/PeerConnectionFactory.java @@ -404,6 +404,7 @@ public class PeerConnectionFactory { public PeerConnection createPeerConnection(List iceServers, MediaConstraints constraints, PeerConnection.Observer observer) { PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers); + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; return createPeerConnection(rtcConfig, constraints, observer); } @@ -411,6 +412,7 @@ public class PeerConnectionFactory { public PeerConnection createPeerConnection( List iceServers, PeerConnection.Observer observer) { PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers); + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; return createPeerConnection(rtcConfig, observer); } diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java index d9799ab448..588e64700b 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionEndToEndTest.java @@ -27,6 +27,7 @@ import java.nio.charset.Charset; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; @@ -642,6 +643,12 @@ public class PeerConnectionEndToEndTest { private static WeakReference addTracksToPC(PeerConnectionFactory factory, PeerConnection pc, VideoSource videoSource, String streamLabel, String videoTrackId, String audioTrackId, VideoSink videoSink) { + return addTracksToPC(factory, pc, videoSource, streamLabel, videoTrackId, audioTrackId, + videoSink, /*useAddStream=*/false); + } + private static WeakReference addTracksToPC(PeerConnectionFactory factory, + PeerConnection pc, VideoSource videoSource, String streamLabel, String videoTrackId, + String audioTrackId, VideoSink videoSink, boolean useAddStream) { MediaStream lMS = factory.createLocalMediaStream(streamLabel); VideoTrack videoTrack = factory.createVideoTrack(videoTrackId, videoSource); assertNotNull(videoTrack); @@ -653,7 +660,20 @@ public class PeerConnectionEndToEndTest { lMS.addTrack(videoTrack); lMS.addTrack( factory.createAudioTrack(audioTrackId, factory.createAudioSource(new MediaConstraints()))); - pc.addStream(lMS); + if (!useAddStream) { + // In Unified Plan, addTrack() is the preferred way of adding tracks. + for (AudioTrack track : lMS.audioTracks) { + pc.addTrack(track, Collections.singletonList(lMS.getId())); + } + for (VideoTrack track : lMS.videoTracks) { + pc.addTrack(track, Collections.singletonList(lMS.getId())); + } + } else { + // Only in Plan B is addStream() supported. Used by a legacy test not yet + // updated to Unified Plan. + // TODO(https://crbug.com/webrtc/13528): Remove use of addStream(). + pc.addStream(lMS); + } return new WeakReference(lMS); } @@ -680,6 +700,7 @@ public class PeerConnectionEndToEndTest { .createIceServer()); PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers); + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); PeerConnection offeringPC = factory.createPeerConnection(rtcConfig, offeringExpectations); @@ -946,6 +967,7 @@ public class PeerConnectionEndToEndTest { .createIceServer()); PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers); + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); PeerConnection offeringPC = factory.createPeerConnection(rtcConfig, offeringExpectations); @@ -1107,7 +1129,8 @@ public class PeerConnectionEndToEndTest { PeerConnectionFactory.builder().setOptions(options).createPeerConnectionFactory(); PeerConnection.RTCConfiguration rtcConfig = - new PeerConnection.RTCConfiguration(Arrays.asList()); + new PeerConnection.RTCConfiguration(Collections.emptyList()); + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; // NONE would prevent any candidate being signaled to the PC. rtcConfig.iceTransportsType = PeerConnection.IceTransportsType.NONE; // We must have the continual gathering enabled to allow the surfacing of candidates on the ICE @@ -1173,6 +1196,8 @@ public class PeerConnectionEndToEndTest { PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer()); PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers); + // TODO(https://crbug.com/webrtc/13528): Update test not to use Plan B. + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.PLAN_B; ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); PeerConnection offeringPC = factory.createPeerConnection(rtcConfig, offeringExpectations); @@ -1198,7 +1223,8 @@ public class PeerConnectionEndToEndTest { offeringExpectations.expectRenegotiationNeeded(); WeakReference oLMS = addTracksToPC(factory, offeringPC, videoSource, "offeredMediaStream", "offeredVideoTrack", - "offeredAudioTrack", new ExpectedResolutionSetter(answeringExpectations)); + "offeredAudioTrack", new ExpectedResolutionSetter(answeringExpectations), + /*useAddStream=*/true); offeringExpectations.expectAddTrack(2); answeringExpectations.expectAddTrack(2); @@ -1232,7 +1258,8 @@ public class PeerConnectionEndToEndTest { answeringExpectations.expectRenegotiationNeeded(); WeakReference aLMS = addTracksToPC(factory, answeringPC, videoSource, "answeredMediaStream", "answeredVideoTrack", "answeredAudioTrack", - new ExpectedResolutionSetter(offeringExpectations)); + new ExpectedResolutionSetter(offeringExpectations), + /*useAddStream=*/true); // Create answer. sdpLatch = new SdpObserverLatch(); @@ -1376,8 +1403,10 @@ public class PeerConnectionEndToEndTest { .setVideoDecoderFactory(new SoftwareVideoDecoderFactory()) .createPeerConnectionFactory(); - // This test is fine with no ICE servers. - List iceServers = new ArrayList<>(); + // TODO(https://crbug.com/webrtc/13528): Update test not to use Plan B. + PeerConnection.RTCConfiguration planBConfig = + new PeerConnection.RTCConfiguration(Collections.emptyList()); + planBConfig.sdpSemantics = PeerConnection.SdpSemantics.PLAN_B; // Use OfferToReceiveAudio/Video to ensure every offer has an audio and // video m= section. Simplifies the test because it means we don't have to @@ -1391,11 +1420,11 @@ public class PeerConnectionEndToEndTest { // This PeerConnection will only be used to generate offers. ObserverExpectations offeringExpectations = new ObserverExpectations("offerer"); - PeerConnection offeringPC = factory.createPeerConnection(iceServers, offeringExpectations); + PeerConnection offeringPC = factory.createPeerConnection(planBConfig, offeringExpectations); assertNotNull(offeringPC); ObserverExpectations expectations = new ObserverExpectations("PC under test"); - PeerConnection pcUnderTest = factory.createPeerConnection(iceServers, expectations); + PeerConnection pcUnderTest = factory.createPeerConnection(planBConfig, expectations); assertNotNull(pcUnderTest); // Add offerer media stream with just an audio track. @@ -1403,9 +1432,9 @@ public class PeerConnectionEndToEndTest { AudioTrack localAudioTrack = factory.createAudioTrack("audio", factory.createAudioSource(new MediaConstraints())); localStream.addTrack(localAudioTrack); - // TODO(deadbeef): Use addTrack once that's available. offeringExpectations.expectRenegotiationNeeded(); - offeringPC.addStream(localStream); + RtpSender audioSender = + offeringPC.addTrack(localAudioTrack, Collections.singletonList(localStream.getId())); // Create offer. SdpObserverLatch sdpLatch = new SdpObserverLatch(); offeringPC.createOffer(sdpLatch, offerConstraints); @@ -1435,6 +1464,7 @@ public class PeerConnectionEndToEndTest { VideoTrack videoTrack = factory.createVideoTrack("video", videoSource); offeringExpectations.expectRenegotiationNeeded(); localStream.addTrack(videoTrack); + offeringPC.addTrack(videoTrack, Collections.singletonList(localStream.getId())); // ... and create an updated offer. sdpLatch = new SdpObserverLatch(); offeringPC.createOffer(sdpLatch, offerConstraints); @@ -1453,6 +1483,7 @@ public class PeerConnectionEndToEndTest { offeringExpectations.expectRenegotiationNeeded(); localStream.removeTrack(localAudioTrack); localAudioTrack.dispose(); + offeringPC.removeTrack(audioSender); sdpLatch = new SdpObserverLatch(); offeringPC.createOffer(sdpLatch, offerConstraints); assertTrue(sdpLatch.await()); @@ -1492,7 +1523,8 @@ public class PeerConnectionEndToEndTest { @SmallTest public void testRollback() throws Exception { PeerConnectionFactory factory = PeerConnectionFactory.builder().createPeerConnectionFactory(); - PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Arrays.asList()); + PeerConnection.RTCConfiguration config = + new PeerConnection.RTCConfiguration(Collections.emptyList()); config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; ObserverExpectations offeringExpectations = new ObserverExpectations("PCTest:offerer"); diff --git a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java index 8478fe5571..7d19143166 100644 --- a/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java +++ b/sdk/android/instrumentationtests/src/org/webrtc/PeerConnectionTest.java @@ -165,6 +165,7 @@ public class PeerConnectionTest { .setPassword("fakePassword") .createIceServer()); PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(iceServers); + config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; // Test configuration options. config.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY; @@ -179,6 +180,7 @@ public class PeerConnectionTest { public void testCreationWithCertificate() throws Exception { PeerConnectionFactory factory = PeerConnectionFactory.builder().createPeerConnectionFactory(); PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Arrays.asList()); + config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; // Test certificate. RtcCertificatePem originalCert = RtcCertificatePem.generateCertificate(); @@ -197,6 +199,7 @@ public class PeerConnectionTest { public void testCreationWithCryptoOptions() throws Exception { PeerConnectionFactory factory = PeerConnectionFactory.builder().createPeerConnectionFactory(); PeerConnection.RTCConfiguration config = new PeerConnection.RTCConfiguration(Arrays.asList()); + config.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; assertNull(config.cryptoOptions); diff --git a/sdk/android/src/jni/pc/peer_connection.cc b/sdk/android/src/jni/pc/peer_connection.cc index ee3c35cb3a..6bcaef4552 100644 --- a/sdk/android/src/jni/pc/peer_connection.cc +++ b/sdk/android/src/jni/pc/peer_connection.cc @@ -118,6 +118,9 @@ SdpSemantics JavaToNativeSdpSemantics(JNIEnv* jni, if (enum_name == "UNIFIED_PLAN") return SdpSemantics::kUnifiedPlan; + if (enum_name == "NOT_SPECIFIED") + return SdpSemantics::kNotSpecified; + RTC_DCHECK_NOTREACHED(); return SdpSemantics::kPlanB_DEPRECATED; }