Add new PeerConnection APIs to the Java SDK.

This adds wrappers to the following native APIs:
- SdpSemantics enum added to the RTCConfiguration
- RtpTransceiver
- PeerConnection.addTrack
- PeerConnection.removeTrack
- PeerConnection.addTransceiver
- PeerConnection.getTransceivers
These APIs are used with the new Unified Plan semantics.

Bug: webrtc:8869
Change-Id: I19443f3ff7ffc91a139ad8276331f09e57cec554
Reviewed-on: https://webrtc-review.googlesource.com/57800
Commit-Queue: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22317}
This commit is contained in:
Seth Hampson 2018-03-06 15:47:10 -08:00 committed by Commit Bot
parent 513449eab9
commit c384e14707
12 changed files with 799 additions and 63 deletions

View File

@ -423,6 +423,7 @@ generate_jni("generated_peerconnection_jni") {
"api/org/webrtc/RtpParameters.java",
"api/org/webrtc/RtpReceiver.java",
"api/org/webrtc/RtpSender.java",
"api/org/webrtc/RtpTransceiver.java",
"api/org/webrtc/SdpObserver.java",
"api/org/webrtc/SessionDescription.java",
"api/org/webrtc/StatsObserver.java",
@ -471,6 +472,8 @@ rtc_static_library("peerconnection_jni") {
"src/jni/pc/rtpreceiver.h",
"src/jni/pc/rtpsender.cc",
"src/jni/pc/rtpsender.h",
"src/jni/pc/rtptransceiver.cc",
"src/jni/pc/rtptransceiver.h",
"src/jni/pc/sdpobserver.cc",
"src/jni/pc/sdpobserver.h",
"src/jni/pc/sessiondescription.cc",
@ -669,6 +672,7 @@ rtc_android_library("libjingle_peerconnection_java") {
"api/org/webrtc/RtpParameters.java",
"api/org/webrtc/RtpReceiver.java",
"api/org/webrtc/RtpSender.java",
"api/org/webrtc/RtpTransceiver.java",
"api/org/webrtc/ScreenCapturerAndroid.java",
"api/org/webrtc/SdpObserver.java",
"api/org/webrtc/SessionDescription.java",

View File

@ -88,13 +88,19 @@ public class MediaStream {
JniCommon.nativeReleaseRef(nativeStream);
}
// TODO(shampson): Remove this when downstreams have moved to using id() instead.
@Deprecated
public String label() {
return nativeGetLabel(nativeStream);
return nativeGetId(nativeStream);
}
public String getId() {
return nativeGetId(nativeStream);
}
@Override
public String toString() {
return "[" + label() + ":A=" + audioTracks.size() + ":V=" + videoTracks.size() + "]";
return "[" + getId() + ":A=" + audioTracks.size() + ":V=" + videoTracks.size() + "]";
}
@CalledByNative
@ -137,5 +143,5 @@ public class MediaStream {
long stream, long nativeVideoTrack);
private static native boolean nativeRemoveAudioTrack(long stream, long nativeAudioTrack);
private static native boolean nativeRemoveVideoTrack(long stream, long nativeVideoTrack);
private static native String nativeGetLabel(long stream);
private static native String nativeGetId(long stream);
}

View File

@ -341,6 +341,33 @@ 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.
*
* <p>PLAN_B will cause PeerConnection to create offers and answers with at
* most one audio and one video m= section with multiple RtpSenders and
* RtpReceivers specified as multiple a=ssrc lines within the section. This
* will also cause PeerConnection to ignore all but the first m= section of
* the same media type.
*
* <p>UNIFIED_PLAN will cause PeerConnection to create offers and answers with
* multiple m= sections where each m= section maps to one RtpSender and one
* RtpReceiver (an RtpTransceiver), either both audio or both video. This
* will also cause PeerConnection to ignore all but the first a=ssrc lines
* that form a Plan B stream.
*
* <p>For users who wish to send multiple audio/video streams and need to stay
* interoperable with legacy WebRTC implementations, specify PLAN_B.
*
* <p>For users who wish to send multiple audio/video streams and/or wish to
* use the new RtpTransceiver API, specify UNIFIED_PLAN.
*/
public enum SdpSemantics { PLAN_B, UNIFIED_PLAN }
/** Java version of PeerConnectionInterface.RTCConfiguration */
// TODO(qingsi): Resolve the naming inconsistency of fields with/without units.
public static class RTCConfiguration {
@ -386,6 +413,7 @@ public class PeerConnection {
// Use "Unknown" to represent no preference of adapter types, not the
// preference of adapters of unknown types.
public AdapterType networkPreference;
public SdpSemantics sdpSemantics;
// This is an optional wrapper for the C++ webrtc::TurnCustomizer.
public TurnCustomizer turnCustomizer;
@ -423,6 +451,7 @@ public class PeerConnection {
combinedAudioVideoBwe = null;
enableDtlsSrtp = null;
networkPreference = AdapterType.UNKNOWN;
sdpSemantics = SdpSemantics.PLAN_B;
}
@CalledByNative("RTCConfiguration")
@ -574,12 +603,18 @@ public class PeerConnection {
AdapterType getNetworkPreference() {
return networkPreference;
}
@CalledByNative("RTCConfiguration")
SdpSemantics getSdpSemantics() {
return sdpSemantics;
}
};
private final List<MediaStream> localStreams = new ArrayList<>();
private final long nativePeerConnection;
private List<RtpSender> senders = new ArrayList<>();
private List<RtpReceiver> receivers = new ArrayList<>();
private List<RtpTransceiver> transceivers = new ArrayList<>();
/**
* Wraps a PeerConnection created by the factory. Can be used by clients that want to implement
@ -622,18 +657,24 @@ public class PeerConnection {
nativeSetRemoteDescription(observer, sdp);
}
// True if remote audio should be played out. Defaults to true.
// Note that even if playout is enabled, streams will only be played out if
// the appropriate SDP is also applied. The main purpose of this API is to
// be able to control the exact time when audio playout starts.
/**
* Enables/disables playout of received audio streams. Enabled by default.
*
* Note that even if playout is enabled, streams will only be played out if
* the appropriate SDP is also applied. The main purpose of this API is to
* be able to control the exact time when audio playout starts.
*/
public void setAudioPlayout(boolean playout) {
nativeSetAudioPlayout(playout);
}
// True if local audio shall be recorded. Defaults to true.
// Note that even if recording is enabled, streams will only be recorded if
// the appropriate SDP is also applied. The main purpose of this API is to
// be able to control the exact time when audio recording starts.
/**
* Enables/disables recording of transmitted audio streams. Enabled by default.
*
* Note that even if recording is enabled, streams will only be recorded if
* the appropriate SDP is also applied. The main purpose of this API is to
* be able to control the exact time when audio recording starts.
*/
public void setAudioRecording(boolean recording) {
nativeSetAudioRecording(recording);
}
@ -650,6 +691,11 @@ public class PeerConnection {
return nativeRemoveIceCandidates(candidates);
}
/**
* Adds a new MediaStream to be sent on this peer connection.
* Note: This method is not supported with SdpSemantics.UNIFIED_PLAN. Please
* use addTrack instead.
*/
public boolean addStream(MediaStream stream) {
boolean ret = nativeAddLocalStream(stream.nativeStream);
if (!ret) {
@ -659,6 +705,11 @@ public class PeerConnection {
return true;
}
/**
* Removes the given media stream from this peer connection.
* This method is not supported with SdpSemantics.UNIFIED_PLAN. Please use
* removeTrack instead.
*/
public void removeStream(MediaStream stream) {
nativeRemoveLocalStream(stream.nativeStream);
localStreams.remove(stream);
@ -666,15 +717,15 @@ public class PeerConnection {
/**
* Creates an RtpSender without a track.
* <p>
* This method allows an application to cause the PeerConnection to negotiate
*
* <p>This method allows an application to cause the PeerConnection to negotiate
* sending/receiving a specific media type, but without having a track to
* send yet.
* <p>
* When the application does want to begin sending a track, it can call
*
* <p>When the application does want to begin sending a track, it can call
* RtpSender.setTrack, which doesn't require any additional SDP negotiation.
* <p>
* Example use:
*
* <p>Example use:
* <pre>
* {@code
* audioSender = pc.createSender("audio", "stream1");
@ -686,12 +737,15 @@ public class PeerConnection {
* videoSender.setTrack(videoTrack, false);
* }
* </pre>
* Note: This corresponds most closely to "addTransceiver" in the official
* <p>Note: This corresponds most closely to "addTransceiver" in the official
* WebRTC API, in that it creates a sender without a track. It was
* implemented before addTransceiver because it provides useful
* functionality, and properly implementing transceivers would have required
* a great deal more work.
*
* <p>Note: This is only available with SdpSemantics.PLAN_B specified. Please use
* addTransceiver instead.
*
* @param kind Corresponds to MediaStreamTrack kinds (must be "audio" or
* "video").
* @param stream_id The ID of the MediaStream that this sender's track will
@ -702,15 +756,18 @@ public class PeerConnection {
* @return A new RtpSender object if successful, or null otherwise.
*/
public RtpSender createSender(String kind, String stream_id) {
RtpSender new_sender = nativeCreateSender(kind, stream_id);
if (new_sender != null) {
senders.add(new_sender);
RtpSender newSender = nativeCreateSender(kind, stream_id);
if (newSender != null) {
senders.add(newSender);
}
return new_sender;
return newSender;
}
// Note that calling getSenders will dispose of the senders previously
// returned (and same goes for getReceivers).
/**
* Gets all RtpSenders associated with this peer connection.
* Note that calling getSenders will dispose of the senders previously
* returned.
*/
public List<RtpSender> getSenders() {
for (RtpSender sender : senders) {
sender.dispose();
@ -719,6 +776,11 @@ public class PeerConnection {
return Collections.unmodifiableList(senders);
}
/**
* Gets all RtpReceivers associated with this peer connection.
* Note that calling getReceivers will dispose of the receivers previously
* returned.
*/
public List<RtpReceiver> getReceivers() {
for (RtpReceiver receiver : receivers) {
receiver.dispose();
@ -727,35 +789,162 @@ public class PeerConnection {
return Collections.unmodifiableList(receivers);
}
/**
* Gets all RtpTransceivers associated with this peer connection.
* Note that calling getTransceivers will dispose of the transceivers previously
* returned.
* Note: This is only available with SdpSemantics.UNIFIED_PLAN specified.
*/
public List<RtpTransceiver> getTransceivers() {
for (RtpTransceiver transceiver : transceivers) {
transceiver.dispose();
}
transceivers = nativeGetTransceivers();
return Collections.unmodifiableList(transceivers);
}
/**
* Adds a new media stream track to be sent on this peer connection, and returns
* the newly created RtpSender. If streamIds are specified, the RtpSender will
* be associated with the streams specified in the streamIds list.
*
* @throws IllegalStateException if an error accors in C++ addTrack.
* An error can occur if:
* - A sender already exists for the track.
* - The peer connection is closed.
*/
public RtpSender addTrack(MediaStreamTrack track) {
return addTrack(track, Collections.emptyList());
}
public RtpSender addTrack(MediaStreamTrack track, List<String> streamIds) {
if (track == null || streamIds == null) {
throw new NullPointerException("No MediaStreamTrack specified in addTrack.");
}
RtpSender newSender = nativeAddTrack(track.nativeTrack, streamIds);
if (newSender == null) {
throw new IllegalStateException("C++ addTrack failed.");
}
senders.add(newSender);
return newSender;
}
/**
* Stops sending media from sender. The sender will still appear in getSenders. Future
* calls to createOffer will mark the m section for the corresponding transceiver as
* receive only or inactive, as defined in JSEP. Returns true on success.
*/
public boolean removeTrack(RtpSender sender) {
if (sender == null) {
throw new NullPointerException("No RtpSender specified for removeTrack.");
}
return nativeRemoveTrack(sender.nativeRtpSender);
}
/**
* Creates a new RtpTransceiver and adds it to the set of transceivers. Adding a
* transceiver will cause future calls to CreateOffer to add a media description
* for the corresponding transceiver.
*
* <p>The initial value of |mid| in the returned transceiver is null. Setting a
* new session description may change it to a non-null value.
*
* <p>https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-addtransceiver
*
* <p>If a MediaStreamTrack is specified then a transceiver will be added with a
* sender set to transmit the given track. The kind
* of the transceiver (and sender/receiver) will be derived from the kind of
* the track.
*
* <p>If MediaType is specified then a transceiver will be added based upon that type.
* This can be either MEDIA_TYPE_AUDIO or MEDIA_TYPE_VIDEO.
*
* <p>Optionally, an RtpTransceiverInit structure can be specified to configure
* the transceiver from construction. If not specified, the transceiver will
* default to having a direction of kSendRecv and not be part of any streams.
*
* <p>Note: These methods are only available with SdpSemantics.UNIFIED_PLAN specified.
* @throws IllegalStateException if an error accors in C++ addTransceiver
*/
public RtpTransceiver addTransceiver(MediaStreamTrack track) {
return addTransceiver(track, new RtpTransceiver.RtpTransceiverInit());
}
public RtpTransceiver addTransceiver(
MediaStreamTrack track, RtpTransceiver.RtpTransceiverInit init) {
if (track == null) {
throw new NullPointerException("No MediaStreamTrack specified for addTransceiver.");
}
if (init == null) {
init = new RtpTransceiver.RtpTransceiverInit();
}
RtpTransceiver newTransceiver = nativeAddTransceiverWithTrack(track.nativeTrack, init);
if (newTransceiver == null) {
throw new IllegalStateException("C++ addTransceiver failed.");
}
transceivers.add(newTransceiver);
return newTransceiver;
}
public RtpTransceiver addTransceiver(MediaStreamTrack.MediaType mediaType) {
return addTransceiver(mediaType, new RtpTransceiver.RtpTransceiverInit());
}
public RtpTransceiver addTransceiver(
MediaStreamTrack.MediaType mediaType, RtpTransceiver.RtpTransceiverInit init) {
if (mediaType == null) {
throw new NullPointerException("No MediaType specified for addTransceiver.");
}
if (init == null) {
init = new RtpTransceiver.RtpTransceiverInit();
}
RtpTransceiver newTransceiver = nativeAddTransceiverOfType(mediaType, init);
if (newTransceiver == null) {
throw new IllegalStateException("C++ addTransceiver failed.");
}
transceivers.add(newTransceiver);
return newTransceiver;
}
// Older, non-standard implementation of getStats.
@Deprecated
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
return nativeOldGetStats(observer, (track == null) ? 0 : track.nativeTrack);
}
// Gets stats using the new stats collection API, see webrtc/api/stats/. These
// will replace old stats collection API when the new API has matured enough.
/**
* Gets stats using the new stats collection API, see webrtc/api/stats/. These
* will replace old stats collection API when the new API has matured enough.
*/
public void getStats(RTCStatsCollectorCallback callback) {
nativeNewGetStats(callback);
}
// Limits the bandwidth allocated for all RTP streams sent by this
// PeerConnection. Pass null to leave a value unchanged.
/**
* Limits the bandwidth allocated for all RTP streams sent by this
* PeerConnection. Pass null to leave a value unchanged.
*/
public boolean setBitrate(Integer min, Integer current, Integer max) {
return nativeSetBitrate(min, current, max);
}
// Starts recording an RTC event log. Ownership of the file is transfered to
// the native code. If an RTC event log is already being recorded, it will be
// stopped and a new one will start using the provided file. Logging will
// continue until the stopRtcEventLog function is called. The max_size_bytes
// argument is ignored, it is added for future use.
/**
* Starts recording an RTC event log.
*
* Ownership of the file is transfered to the native code. If an RTC event
* log is already being recorded, it will be stopped and a new one will start
* using the provided file. Logging will continue until the stopRtcEventLog
* function is called. The max_size_bytes argument is ignored, it is added
* for future use.
*/
public boolean startRtcEventLog(int file_descriptor, int max_size_bytes) {
return nativeStartRtcEventLog(file_descriptor, max_size_bytes);
}
// Stops recording an RTC event log. If no RTC event log is currently being
// recorded, this call will have no effect.
/**
* Stops recording an RTC event log. If no RTC event log is currently being
* recorded, this call will have no effect.
*/
public void stopRtcEventLog() {
nativeStopRtcEventLog();
}
@ -780,14 +969,14 @@ public class PeerConnection {
/**
* Free native resources associated with this PeerConnection instance.
* <p>
*
* This method removes a reference count from the C++ PeerConnection object,
* which should result in it being destroyed. It also calls equivalent
* "dispose" methods on the Java objects attached to this PeerConnection
* (streams, senders, receivers), such that their associated C++ objects
* will also be destroyed.
* <p>
* Note that this method cannot be safely called from an observer callback
*
* <p>Note that this method cannot be safely called from an observer callback
* (PeerConnection.Observer, DataChannel.Observer, etc.). If you want to, for
* example, destroy the PeerConnection after an "ICE failed" callback, you
* must do this asynchronously (in other words, unwind the stack first). See
@ -808,6 +997,10 @@ public class PeerConnection {
for (RtpReceiver receiver : receivers) {
receiver.dispose();
}
for (RtpTransceiver transceiver : transceivers) {
transceiver.dispose();
}
transceivers.clear();
receivers.clear();
nativeFreeOwnedPeerConnection(nativePeerConnection);
}
@ -854,6 +1047,13 @@ public class PeerConnection {
private native RtpSender nativeCreateSender(String kind, String stream_id);
private native List<RtpSender> nativeGetSenders();
private native List<RtpReceiver> nativeGetReceivers();
private native List<RtpTransceiver> nativeGetTransceivers();
private native RtpSender nativeAddTrack(long track, List<String> streamIds);
private native boolean nativeRemoveTrack(long sender);
private native RtpTransceiver nativeAddTransceiverWithTrack(
long track, RtpTransceiver.RtpTransceiverInit init);
private native RtpTransceiver nativeAddTransceiverOfType(
MediaStreamTrack.MediaType mediaType, RtpTransceiver.RtpTransceiverInit init);
private native boolean nativeStartRtcEventLog(int file_descriptor, int max_size_bytes);
private native void nativeStopRtcEventLog();
}

View File

@ -0,0 +1,215 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
package org.webrtc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.webrtc.RtpParameters.Encoding;
/**
* Java wrapper for a C++ RtpTransceiverInterface.
*
* <p>The RTCRtpTransceiver maps to the RTCRtpTransceiver defined by the WebRTC
* specification. A transceiver represents a combination of an RTCRtpSender
* and an RTCRtpReceiver that share a common mid. As defined in JSEP, an
* RTCRtpTransceiver is said to be associated with a media description if its
* mid property is non-nil; otherwise, it is said to be disassociated.
* JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24
*
* <p>Note that RTCRtpTransceivers are only supported when using
* RTCPeerConnection with Unified Plan SDP.
*
* <p>WebRTC specification for RTCRtpTransceiver, the JavaScript analog:
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver
*/
@JNINamespace("webrtc::jni")
public class RtpTransceiver {
/** Java version of webrtc::RtpTransceiverDirection - the ordering must be kept in sync. */
public enum RtpTransceiverDirection {
SEND_RECV(0),
SEND_ONLY(1),
RECV_ONLY(2),
INACTIVE(3);
private final int nativeIndex;
private RtpTransceiverDirection(int nativeIndex) {
this.nativeIndex = nativeIndex;
}
@CalledByNative("RtpTransceiverDirection")
int getNativeIndex() {
return nativeIndex;
}
@CalledByNative("RtpTransceiverDirection")
static RtpTransceiverDirection fromNativeIndex(int nativeIndex) {
for (RtpTransceiverDirection type : RtpTransceiverDirection.values()) {
if (type.getNativeIndex() == nativeIndex) {
return type;
}
}
throw new IllegalArgumentException(
"Uknown native RtpTransceiverDirection type" + nativeIndex);
}
}
/**
* Tracks webrtc::RtpTransceiverInit. https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
* A structure for initializing an RtpTransceiver in a call to addTransceiver.
* Note: This does not contain a list of encoding parameters, because they are currently
* not being used natively.
*/
public static final class RtpTransceiverInit {
private final RtpTransceiverDirection direction;
private final List<String> streamIds;
public RtpTransceiverInit() {
this(RtpTransceiverDirection.SEND_RECV);
}
public RtpTransceiverInit(RtpTransceiverDirection direction) {
this(direction, Collections.emptyList());
}
public RtpTransceiverInit(RtpTransceiverDirection direction, List<String> streamIds) {
this.direction = direction;
this.streamIds = new ArrayList<String>(streamIds);
}
@CalledByNative("RtpTransceiverInit")
int getDirectionNativeIndex() {
return direction.getNativeIndex();
}
@CalledByNative("RtpTransceiverInit")
List<String> getStreamIds() {
return new ArrayList<String>(this.streamIds);
}
}
private final long nativeRtpTransceiver;
private RtpSender cachedSender;
private RtpReceiver cachedReceiver;
@CalledByNative
protected RtpTransceiver(long nativeRtpTransceiver) {
this.nativeRtpTransceiver = nativeRtpTransceiver;
cachedSender = nativeGetSender(nativeRtpTransceiver);
cachedReceiver = nativeGetReceiver(nativeRtpTransceiver);
}
/**
* Media type of the transceiver. Any sender(s)/receiver(s) will have this
* type as well.
*/
public MediaStreamTrack.MediaType getMediaType() {
return nativeGetMediaType(nativeRtpTransceiver);
}
/**
* The mid attribute is the mid negotiated and present in the local and
* remote descriptions. Before negotiation is complete, the mid value may be
* null. After rollbacks, the value may change from a non-null value to null.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
*/
public String getMid() {
return nativeGetMid(nativeRtpTransceiver);
}
/**
* The sender attribute exposes the RtpSender corresponding to the RTP media
* that may be sent with the transceiver's mid. The sender is always present,
* regardless of the direction of media.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender
*/
public RtpSender getSender() {
return cachedSender;
}
/**
* The receiver attribute exposes the RtpReceiver corresponding to the RTP
* media that may be received with the transceiver's mid. The receiver is
* always present, regardless of the direction of media.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver
*/
public RtpReceiver getReceiver() {
return cachedReceiver;
}
/**
* The stopped attribute indicates that the sender of this transceiver will no
* longer send, and that the receiver will no longer receive. It is true if
* either stop has been called or if setting the local or remote description
* has caused the RtpTransceiver to be stopped.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped
*/
public boolean isStopped() {
return nativeStopped(nativeRtpTransceiver);
}
/**
* The direction attribute indicates the preferred direction of this
* transceiver, which will be used in calls to CreateOffer and CreateAnswer.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/
public RtpTransceiverDirection getDirection() {
return nativeDirection(nativeRtpTransceiver);
}
/**
* The current_direction attribute indicates the current direction negotiated
* for this transceiver. If this transceiver has never been represented in an
* offer/answer exchange, or if the transceiver is stopped, the value is null.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
*/
public RtpTransceiverDirection getCurrentDirection() {
return nativeCurrentDirection(nativeRtpTransceiver);
}
/**
* Sets the preferred direction of this transceiver. An update of
* directionality does not take effect immediately. Instead, future calls to
* CreateOffer and CreateAnswer mark the corresponding media descriptions as
* sendrecv, sendonly, recvonly, or inactive.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/
public void setDirection(RtpTransceiverDirection rtpTransceiverDirection) {
nativeSetDirection(nativeRtpTransceiver, rtpTransceiverDirection);
}
/**
* The Stop method irreversibly stops the RtpTransceiver. The sender of this
* transceiver will no longer send, the receiver will no longer receive.
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop
*/
public void stop() {
nativeStop(nativeRtpTransceiver);
}
public void dispose() {
cachedSender.dispose();
cachedReceiver.dispose();
JniCommon.nativeReleaseRef(nativeRtpTransceiver);
}
private static native MediaStreamTrack.MediaType nativeGetMediaType(long rtpTransceiver);
private static native String nativeGetMid(long rtpTransceiver);
private static native RtpSender nativeGetSender(long rtpTransceiver);
private static native RtpReceiver nativeGetReceiver(long rtpTransceiver);
private static native boolean nativeStopped(long rtpTransceiver);
private static native RtpTransceiverDirection nativeDirection(long rtpTransceiver);
private static native RtpTransceiverDirection nativeCurrentDirection(long rtpTransceiver);
private static native void nativeStop(long rtpTransceiver);
private static native void nativeSetDirection(
long rtpTransceiver, RtpTransceiverDirection rtpTransceiverDirection);
}

View File

@ -200,6 +200,12 @@ ScopedJavaLocalRef<jobject> NativeToJavaInteger(
return optional_int ? NativeToJavaInteger(jni, *optional_int) : nullptr;
}
ScopedJavaLocalRef<jstring> NativeToJavaString(
JNIEnv* jni,
const rtc::Optional<std::string>& str) {
return str ? NativeToJavaString(jni, *str) : nullptr;
}
ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray(
JNIEnv* env,
const std::vector<bool>& container) {

View File

@ -150,6 +150,21 @@ std::vector<T> JavaToNativeVector(JNIEnv* env,
return container;
}
template <typename T, typename Java_T = jobject, typename Convert>
std::vector<T> JavaListToNativeVector(JNIEnv* env,
const JavaRef<jobject>& j_list,
Convert convert) {
std::vector<T> native_list;
if (!j_list.is_null()) {
for (ScopedJavaLocalRef<jobject>& j_item : Iterable(env, j_list)) {
native_list.emplace_back(
convert(env, static_java_ref_cast<Java_T>(env, j_item)));
}
CHECK_EXCEPTION(env) << "Error during JavaListToNativeVector";
}
return native_list;
}
template <typename Key, typename T, typename Convert>
std::map<Key, T> JavaToNativeMap(JNIEnv* env,
const JavaRef<jobject>& j_map,
@ -182,6 +197,9 @@ ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni,
ScopedJavaLocalRef<jobject> NativeToJavaInteger(
JNIEnv* jni,
const rtc::Optional<int32_t>& optional_int);
ScopedJavaLocalRef<jstring> NativeToJavaString(
JNIEnv* jni,
const rtc::Optional<std::string>& str);
// Helper function for converting std::vector<T> into a Java array.
template <typename T, typename Convert>
@ -282,7 +300,7 @@ inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) {
return JavaToStdString(jni, JavaParamRef<jstring>(j_string));
}
// Deprecated. Use JavaToNativeVector<std::string> instead.
// Deprecated. Use JavaListToNativeVector<std::string, jstring> instead.
// Given a List of (UTF-16) jstrings
// return a new vector of UTF-8 native strings.
std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni,

View File

@ -135,9 +135,9 @@ static jboolean JNI_MediaStream_RemoveVideoTrack(JNIEnv* jni,
}
static ScopedJavaLocalRef<jstring>
JNI_MediaStream_GetLabel(JNIEnv* jni, const JavaParamRef<jclass>&, jlong j_p) {
return NativeToJavaString(
jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
JNI_MediaStream_GetId(JNIEnv* jni, const JavaParamRef<jclass>&, jlong j_p) {
return NativeToJavaString(jni,
reinterpret_cast<MediaStreamInterface*>(j_p)->id());
}
} // namespace jni

View File

@ -36,6 +36,7 @@
#include "api/peerconnectioninterface.h"
#include "api/rtpreceiverinterface.h"
#include "api/rtpsenderinterface.h"
#include "api/rtptransceiverinterface.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
#include "rtc_base/ptr_util.h"
@ -45,8 +46,10 @@
#include "sdk/android/src/jni/pc/datachannel.h"
#include "sdk/android/src/jni/pc/icecandidate.h"
#include "sdk/android/src/jni/pc/mediaconstraints.h"
#include "sdk/android/src/jni/pc/mediastreamtrack.h"
#include "sdk/android/src/jni/pc/rtcstatscollectorcallbackwrapper.h"
#include "sdk/android/src/jni/pc/rtpsender.h"
#include "sdk/android/src/jni/pc/rtptransceiver.h"
#include "sdk/android/src/jni/pc/sdpobserver.h"
#include "sdk/android/src/jni/pc/sessiondescription.h"
#include "sdk/android/src/jni/pc/statsobserver.h"
@ -86,19 +89,35 @@ PeerConnectionInterface::IceServers JavaToNativeIceServers(
ScopedJavaLocalRef<jobject> tls_elliptic_curves =
Java_IceServer_getTlsEllipticCurves(jni, j_ice_server);
PeerConnectionInterface::IceServer server;
server.urls = JavaToStdVectorStrings(jni, urls);
server.username = JavaToStdString(jni, username);
server.password = JavaToStdString(jni, password);
server.urls = JavaListToNativeVector<std::string, jstring>(
jni, urls, &JavaToNativeString);
server.username = JavaToNativeString(jni, username);
server.password = JavaToNativeString(jni, password);
server.tls_cert_policy = tls_cert_policy;
server.hostname = JavaToStdString(jni, hostname);
server.tls_alpn_protocols = JavaToStdVectorStrings(jni, tls_alpn_protocols);
server.tls_elliptic_curves =
JavaToStdVectorStrings(jni, tls_elliptic_curves);
server.hostname = JavaToNativeString(jni, hostname);
server.tls_alpn_protocols = JavaListToNativeVector<std::string, jstring>(
jni, tls_alpn_protocols, &JavaToNativeString);
server.tls_elliptic_curves = JavaListToNativeVector<std::string, jstring>(
jni, tls_elliptic_curves, &JavaToNativeString);
ice_servers.push_back(server);
}
return ice_servers;
}
SdpSemantics JavaToNativeSdpSemantics(JNIEnv* jni,
const JavaRef<jobject>& j_sdp_semantics) {
std::string enum_name = GetJavaEnumName(jni, j_sdp_semantics);
if (enum_name == "PLAN_B")
return SdpSemantics::kPlanB;
if (enum_name == "UNIFIED_PLAN")
return SdpSemantics::kUnifiedPlan;
RTC_NOTREACHED();
return SdpSemantics::kPlanB;
}
} // namespace
void JavaToNativeRTCConfiguration(
@ -123,6 +142,8 @@ void JavaToNativeRTCConfiguration(
Java_RTCConfiguration_getTurnCustomizer(jni, j_rtc_config);
ScopedJavaLocalRef<jobject> j_network_preference =
Java_RTCConfiguration_getNetworkPreference(jni, j_rtc_config);
ScopedJavaLocalRef<jobject> j_sdp_semantics =
Java_RTCConfiguration_getSdpSemantics(jni, j_rtc_config);
rtc_config->type = JavaToNativeIceTransportsType(jni, j_ice_transports_type);
rtc_config->bundle_policy = JavaToNativeBundlePolicy(jni, j_bundle_policy);
@ -193,6 +214,7 @@ void JavaToNativeRTCConfiguration(
jni, Java_RTCConfiguration_getEnableDtlsSrtp(jni, j_rtc_config));
rtc_config->network_preference =
JavaToNativeNetworkPreference(jni, j_network_preference);
rtc_config->sdp_semantics = JavaToNativeSdpSemantics(jni, j_sdp_semantics);
}
rtc::KeyType GetRtcConfigKeyType(JNIEnv* env,
@ -380,7 +402,7 @@ static ScopedJavaLocalRef<jobject> JNI_PeerConnection_CreateDataChannel(
DataChannelInit init = JavaToNativeDataChannelInit(jni, j_init);
rtc::scoped_refptr<DataChannelInterface> channel(
ExtractNativePC(jni, j_pc)->CreateDataChannel(
JavaToStdString(jni, j_label), &init));
JavaToNativeString(jni, j_label), &init));
return WrapNativeDataChannel(jni, channel);
}
@ -469,8 +491,8 @@ static jboolean JNI_PeerConnection_AddIceCandidate(
const JavaParamRef<jstring>& j_sdp_mid,
jint j_sdp_mline_index,
const JavaParamRef<jstring>& j_candidate_sdp) {
std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
std::string sdp = JavaToStdString(jni, j_candidate_sdp);
std::string sdp_mid = JavaToNativeString(jni, j_sdp_mid);
std::string sdp = JavaToNativeString(jni, j_candidate_sdp);
std::unique_ptr<IceCandidateInterface> candidate(
CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, nullptr));
return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
@ -507,8 +529,8 @@ static ScopedJavaLocalRef<jobject> JNI_PeerConnection_CreateSender(
const JavaParamRef<jobject>& j_pc,
const JavaParamRef<jstring>& j_kind,
const JavaParamRef<jstring>& j_stream_id) {
std::string kind = JavaToStdString(jni, j_kind);
std::string stream_id = JavaToStdString(jni, j_stream_id);
std::string kind = JavaToNativeString(jni, j_kind);
std::string stream_id = JavaToNativeString(jni, j_stream_id);
rtc::scoped_refptr<RtpSenderInterface> sender =
ExtractNativePC(jni, j_pc)->CreateSender(kind, stream_id);
return NativeToJavaRtpSender(jni, sender);
@ -528,6 +550,75 @@ static ScopedJavaLocalRef<jobject> JNI_PeerConnection_GetReceivers(
&NativeToJavaRtpReceiver);
}
static ScopedJavaLocalRef<jobject> JNI_PeerConnection_GetTransceivers(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc) {
return NativeToJavaList(jni, ExtractNativePC(jni, j_pc)->GetTransceivers(),
&NativeToJavaRtpTransceiver);
}
static ScopedJavaLocalRef<jobject> JNI_PeerConnection_AddTrack(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc,
const jlong native_track,
const JavaParamRef<jobject>& j_stream_labels) {
RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> result =
ExtractNativePC(jni, j_pc)->AddTrack(
reinterpret_cast<MediaStreamTrackInterface*>(native_track),
JavaListToNativeVector<std::string, jstring>(jni, j_stream_labels,
&JavaToNativeString));
if (!result.ok()) {
RTC_LOG(LS_ERROR) << "Failed to add track: " << result.error().message();
return nullptr;
} else {
return NativeToJavaRtpSender(jni, result.MoveValue());
}
}
static jboolean JNI_PeerConnection_RemoveTrack(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc,
jlong native_sender) {
return ExtractNativePC(jni, j_pc)->RemoveTrack(
reinterpret_cast<RtpSenderInterface*>(native_sender));
}
static ScopedJavaLocalRef<jobject> JNI_PeerConnection_AddTransceiverWithTrack(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc,
jlong native_track,
const JavaParamRef<jobject>& j_init) {
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
ExtractNativePC(jni, j_pc)->AddTransceiver(
reinterpret_cast<MediaStreamTrackInterface*>(native_track),
JavaToNativeRtpTransceiverInit(jni, j_init));
if (!result.ok()) {
RTC_LOG(LS_ERROR) << "Failed to add transceiver: "
<< result.error().message();
return nullptr;
} else {
return NativeToJavaRtpTransceiver(jni, result.MoveValue());
}
}
static ScopedJavaLocalRef<jobject> JNI_PeerConnection_AddTransceiverOfType(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc,
const JavaParamRef<jobject>& j_media_type,
const JavaParamRef<jobject>& j_init) {
RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> result =
ExtractNativePC(jni, j_pc)->AddTransceiver(
JavaToNativeMediaType(jni, j_media_type),
JavaToNativeRtpTransceiverInit(jni, j_init));
if (!result.ok()) {
RTC_LOG(LS_ERROR) << "Failed to add transceiver: "
<< result.error().message();
return nullptr;
} else {
return NativeToJavaRtpTransceiver(jni, result.MoveValue());
}
}
static jboolean JNI_PeerConnection_OldGetStats(
JNIEnv* jni,
const JavaParamRef<jobject>& j_pc,

View File

@ -40,6 +40,21 @@ ScopedJavaLocalRef<jobject> NativeToJavaRtpCodecParameter(
} // namespace
RtpEncodingParameters JavaToNativeRtpEncodingParameters(
JNIEnv* jni,
const JavaRef<jobject>& j_encoding_parameters) {
RtpEncodingParameters encoding;
encoding.active = Java_Encoding_getActive(jni, j_encoding_parameters);
ScopedJavaLocalRef<jobject> j_bitrate =
Java_Encoding_getMaxBitrateBps(jni, j_encoding_parameters);
encoding.max_bitrate_bps = JavaToNativeOptionalInt(jni, j_bitrate);
ScopedJavaLocalRef<jobject> j_ssrc =
Java_Encoding_getSsrc(jni, j_encoding_parameters);
if (!IsNull(jni, j_ssrc))
encoding.ssrc = JavaToNativeLong(jni, j_ssrc);
return encoding;
}
RtpParameters JavaToNativeRtpParameters(JNIEnv* jni,
const JavaRef<jobject>& j_parameters) {
RtpParameters parameters;
@ -49,15 +64,8 @@ RtpParameters JavaToNativeRtpParameters(JNIEnv* jni,
Java_RtpParameters_getEncodings(jni, j_parameters);
for (const JavaRef<jobject>& j_encoding_parameters :
Iterable(jni, j_encodings)) {
RtpEncodingParameters encoding;
encoding.active = Java_Encoding_getActive(jni, j_encoding_parameters);
ScopedJavaLocalRef<jobject> j_bitrate =
Java_Encoding_getMaxBitrateBps(jni, j_encoding_parameters);
encoding.max_bitrate_bps = JavaToNativeOptionalInt(jni, j_bitrate);
ScopedJavaLocalRef<jobject> j_ssrc =
Java_Encoding_getSsrc(jni, j_encoding_parameters);
if (!IsNull(jni, j_ssrc))
encoding.ssrc = JavaToNativeLong(jni, j_ssrc);
RtpEncodingParameters encoding =
JavaToNativeRtpEncodingParameters(jni, j_encoding_parameters);
parameters.encodings.push_back(encoding);
}

View File

@ -19,6 +19,10 @@
namespace webrtc {
namespace jni {
RtpEncodingParameters JavaToNativeRtpEncodingParameters(
JNIEnv* env,
const JavaRef<jobject>& j_encoding_parameters);
RtpParameters JavaToNativeRtpParameters(JNIEnv* jni,
const JavaRef<jobject>& j_parameters);
ScopedJavaLocalRef<jobject> NativeToJavaRtpParameters(

View File

@ -0,0 +1,151 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "sdk/android/src/jni/pc/rtptransceiver.h"
#include <string>
#include "sdk/android/generated_peerconnection_jni/jni/RtpTransceiver_jni.h"
#include "sdk/android/native_api/jni/java_types.h"
#include "sdk/android/src/jni/jni_helpers.h"
#include "sdk/android/src/jni/pc/mediastreamtrack.h"
#include "sdk/android/src/jni/pc/rtpparameters.h"
#include "sdk/android/src/jni/pc/rtpreceiver.h"
#include "sdk/android/src/jni/pc/rtpsender.h"
namespace webrtc {
namespace jni {
namespace {
ScopedJavaLocalRef<jobject> NativeToJavaRtpTransceiverDirection(
JNIEnv* jni,
RtpTransceiverDirection rtp_transceiver_direction) {
return Java_RtpTransceiverDirection_fromNativeIndex(
jni, static_cast<int>(rtp_transceiver_direction));
}
} // namespace
RtpTransceiverInit JavaToNativeRtpTransceiverInit(
JNIEnv* jni,
const JavaRef<jobject>& j_init) {
RtpTransceiverInit init;
// Convert the direction.
init.direction = static_cast<RtpTransceiverDirection>(
Java_RtpTransceiverInit_getDirectionNativeIndex(jni, j_init));
// Convert the stream ids.
ScopedJavaLocalRef<jobject> j_stream_ids =
Java_RtpTransceiverInit_getStreamIds(jni, j_init);
init.stream_ids = JavaListToNativeVector<std::string, jstring>(
jni, j_stream_ids, &JavaToNativeString);
return init;
}
ScopedJavaLocalRef<jobject> NativeToJavaRtpTransceiver(
JNIEnv* env,
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {
if (!transceiver) {
return nullptr;
}
// Transceiver will now have shared ownership by the Java object.
return Java_RtpTransceiver_Constructor(
env, jlongFromPointer(transceiver.release()));
}
ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_GetMediaType(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
return NativeToJavaMediaType(
jni, reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->media_type());
}
ScopedJavaLocalRef<jstring> JNI_RtpTransceiver_GetMid(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
rtc::Optional<std::string> mid =
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->mid();
return NativeToJavaString(jni, mid);
}
ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_GetSender(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
return NativeToJavaRtpSender(
jni, reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->sender());
}
ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_GetReceiver(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
return NativeToJavaRtpReceiver(
jni, reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->receiver());
}
jboolean JNI_RtpTransceiver_Stopped(JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
return reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->stopped();
}
ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_Direction(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
return NativeToJavaRtpTransceiverDirection(
jni, reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->direction());
}
ScopedJavaLocalRef<jobject> JNI_RtpTransceiver_CurrentDirection(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
rtc::Optional<RtpTransceiverDirection> direction =
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->current_direction();
return direction ? NativeToJavaRtpTransceiverDirection(jni, *direction)
: nullptr;
}
void JNI_RtpTransceiver_Stop(JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer) {
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)->Stop();
}
void JNI_RtpTransceiver_SetDirection(
JNIEnv* jni,
const base::android::JavaParamRef<jclass>&,
jlong j_rtp_transceiver_pointer,
const base::android::JavaParamRef<jobject>& j_rtp_transceiver_direction) {
if (IsNull(jni, j_rtp_transceiver_direction)) {
return;
}
RtpTransceiverDirection direction = static_cast<RtpTransceiverDirection>(
Java_RtpTransceiverDirection_getNativeIndex(jni,
j_rtp_transceiver_direction));
reinterpret_cast<RtpTransceiverInterface*>(j_rtp_transceiver_pointer)
->SetDirection(direction);
}
} // namespace jni
} // namespace webrtc

View File

@ -0,0 +1,33 @@
/*
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SDK_ANDROID_SRC_JNI_PC_RTPTRANSCEIVER_H_
#define SDK_ANDROID_SRC_JNI_PC_RTPTRANSCEIVER_H_
#include <jni.h>
#include "api/rtptransceiverinterface.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
namespace webrtc {
namespace jni {
RtpTransceiverInit JavaToNativeRtpTransceiverInit(
JNIEnv* jni,
const JavaRef<jobject>& j_init);
ScopedJavaLocalRef<jobject> NativeToJavaRtpTransceiver(
JNIEnv* env,
rtc::scoped_refptr<RtpTransceiverInterface> transceiver);
} // namespace jni
} // namespace webrtc
#endif // SDK_ANDROID_SRC_JNI_PC_RTPTRANSCEIVER_H_