diff --git a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java index 4f93925e6b..a2b4c102c1 100644 --- a/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java +++ b/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java @@ -47,12 +47,15 @@ import org.webrtc.IceCandidate; import org.webrtc.Logging; import org.webrtc.MediaConstraints; import org.webrtc.MediaStream; +import org.webrtc.MediaStreamTrack; +import org.webrtc.MediaStreamTrack.MediaType; import org.webrtc.PeerConnection; import org.webrtc.PeerConnection.IceConnectionState; import org.webrtc.PeerConnectionFactory; import org.webrtc.RtpParameters; import org.webrtc.RtpReceiver; import org.webrtc.RtpSender; +import org.webrtc.RtpTransceiver; import org.webrtc.SdpObserver; import org.webrtc.SessionDescription; import org.webrtc.SoftwareVideoDecoderFactory; @@ -636,6 +639,7 @@ public class PeerConnectionClient { rtcConfig.keyType = PeerConnection.KeyType.ECDSA; // Enable DTLS for normal calls and disable for loopback calls. rtcConfig.enableDtlsSrtp = !peerConnectionParameters.loopback; + rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; peerConnection = factory.createPeerConnection(rtcConfig, pcObserver); @@ -655,13 +659,18 @@ public class PeerConnectionClient { // NOTE: this _must_ happen while |factory| is alive! Logging.enableLogToDebugOutput(Logging.Severity.LS_INFO); - mediaStream = factory.createLocalMediaStream("ARDAMS"); + List mediaStreamLabels = Collections.singletonList("ARDAMS"); if (videoCallEnabled) { - mediaStream.addTrack(createVideoTrack(videoCapturer)); + peerConnection.addTrack(createVideoTrack(videoCapturer), mediaStreamLabels); + // We can add the renderers right away because we don't need to wait for an + // answer to get the remote track. + remoteVideoTrack = getRemoteVideoTrack(); + remoteVideoTrack.setEnabled(renderVideo); + for (VideoRenderer.Callbacks remoteRender : remoteRenders) { + remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender)); + } } - - mediaStream.addTrack(createAudioTrack()); - peerConnection.addStream(mediaStream); + peerConnection.addTrack(createAudioTrack(), mediaStreamLabels); if (videoCallEnabled) { findVideoSender(); } @@ -1024,6 +1033,17 @@ public class PeerConnectionClient { } } + // Returns the remote VideoTrack, assuming there is only one. + private VideoTrack getRemoteVideoTrack() { + for (RtpTransceiver transceiver : peerConnection.getTransceivers()) { + MediaStreamTrack track = transceiver.getReceiver().track(); + if (track instanceof VideoTrack) { + return (VideoTrack) track; + } + } + return null; + } + @SuppressWarnings("StringSplitter") private static String setStartBitrate( String codec, boolean isVideoCodec, String sdpDescription, int bitrateKbps) { @@ -1274,37 +1294,10 @@ public class PeerConnectionClient { } @Override - public void onAddStream(final MediaStream stream) { - executor.execute(new Runnable() { - @Override - public void run() { - if (peerConnection == null || isError) { - return; - } - if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) { - reportError("Weird-looking stream: " + stream); - return; - } - if (stream.videoTracks.size() == 1) { - remoteVideoTrack = stream.videoTracks.get(0); - remoteVideoTrack.setEnabled(renderVideo); - for (VideoRenderer.Callbacks remoteRender : remoteRenders) { - remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender)); - } - } - } - }); - } + public void onAddStream(final MediaStream stream) {} @Override - public void onRemoveStream(final MediaStream stream) { - executor.execute(new Runnable() { - @Override - public void run() { - remoteVideoTrack = null; - } - }); - } + public void onRemoveStream(final MediaStream stream) {} @Override public void onDataChannel(final DataChannel dc) { diff --git a/sdk/android/api/org/webrtc/MediaStreamTrack.java b/sdk/android/api/org/webrtc/MediaStreamTrack.java index 449ca75dbd..0a020ae72c 100644 --- a/sdk/android/api/org/webrtc/MediaStreamTrack.java +++ b/sdk/android/api/org/webrtc/MediaStreamTrack.java @@ -13,6 +13,9 @@ package org.webrtc; /** Java wrapper for a C++ MediaStreamTrackInterface. */ @JNINamespace("webrtc::jni") public class MediaStreamTrack { + public static final String AUDIO_TRACK_KIND = "audio"; + public static final String VIDEO_TRACK_KIND = "video"; + /** Tracks MediaStreamTrackInterface.TrackState */ public enum State { LIVE, @@ -51,6 +54,21 @@ public class MediaStreamTrack { } } + /** Factory method to create an AudioTrack or VideoTrack subclass. */ + static MediaStreamTrack createMediaStreamTrack(long nativeTrack) { + if (nativeTrack == 0) { + return null; + } + String trackKind = nativeGetKind(nativeTrack); + if (trackKind.equals(AUDIO_TRACK_KIND)) { + return new AudioTrack(nativeTrack); + } else if (trackKind.equals(VIDEO_TRACK_KIND)) { + return new VideoTrack(nativeTrack); + } else { + return null; + } + } + final long nativeTrack; public MediaStreamTrack(long nativeTrack) { diff --git a/sdk/android/api/org/webrtc/RtpReceiver.java b/sdk/android/api/org/webrtc/RtpReceiver.java index 0c9de5649a..f33fa58fb5 100644 --- a/sdk/android/api/org/webrtc/RtpReceiver.java +++ b/sdk/android/api/org/webrtc/RtpReceiver.java @@ -30,9 +30,8 @@ public class RtpReceiver { @CalledByNative public RtpReceiver(long nativeRtpReceiver) { this.nativeRtpReceiver = nativeRtpReceiver; - long track = nativeGetTrack(nativeRtpReceiver); - // We can assume that an RtpReceiver always has an associated track. - cachedTrack = new MediaStreamTrack(track); + long nativeTrack = nativeGetTrack(nativeRtpReceiver); + cachedTrack = MediaStreamTrack.createMediaStreamTrack(nativeTrack); } public MediaStreamTrack track() { diff --git a/sdk/android/api/org/webrtc/RtpSender.java b/sdk/android/api/org/webrtc/RtpSender.java index 9675d9d2e6..33ac3af9ec 100644 --- a/sdk/android/api/org/webrtc/RtpSender.java +++ b/sdk/android/api/org/webrtc/RtpSender.java @@ -23,9 +23,8 @@ public class RtpSender { @CalledByNative public RtpSender(long nativeRtpSender) { this.nativeRtpSender = nativeRtpSender; - long track = nativeGetTrack(nativeRtpSender); - // It may be possible for an RtpSender to be created without a track. - cachedTrack = (track != 0) ? new MediaStreamTrack(track) : null; + long nativeTrack = nativeGetTrack(nativeRtpSender); + cachedTrack = MediaStreamTrack.createMediaStreamTrack(nativeTrack); long nativeDtmfSender = nativeGetDtmfSender(nativeRtpSender); dtmfSender = (nativeDtmfSender != 0) ? new DtmfSender(nativeDtmfSender) : null; diff --git a/sdk/android/src/jni/pc/rtpreceiver.cc b/sdk/android/src/jni/pc/rtpreceiver.cc index 9487f404bd..049df49e7d 100644 --- a/sdk/android/src/jni/pc/rtpreceiver.cc +++ b/sdk/android/src/jni/pc/rtpreceiver.cc @@ -67,6 +67,8 @@ JavaRtpReceiverGlobalOwner::~JavaRtpReceiverGlobalOwner() { static jlong JNI_RtpReceiver_GetTrack(JNIEnv* jni, const JavaParamRef&, jlong j_rtp_receiver_pointer) { + // MediaStreamTrack will have shared ownership by the MediaStreamTrack Java + // object. return jlongFromPointer( reinterpret_cast(j_rtp_receiver_pointer) ->track() diff --git a/sdk/android/src/jni/pc/rtpsender.cc b/sdk/android/src/jni/pc/rtpsender.cc index 3a00383753..772dbcd613 100644 --- a/sdk/android/src/jni/pc/rtpsender.cc +++ b/sdk/android/src/jni/pc/rtpsender.cc @@ -39,6 +39,8 @@ static jboolean JNI_RtpSender_SetTrack(JNIEnv* jni, jlong JNI_RtpSender_GetTrack(JNIEnv* jni, const JavaParamRef&, jlong j_rtp_sender_pointer) { + // MediaStreamTrack will have shared ownership by the MediaStreamTrack Java + // object. return jlongFromPointer( reinterpret_cast(j_rtp_sender_pointer) ->track()