Throw IllegalStateException if native objects are used after dispose.

This makes it easier to debug issues related to double dispose /
use after dispose.

Bug: webrtc:7566, webrtc:8297
Change-Id: I07429b2b794deabb62b5f3ea1cf92eea6f66a149
Reviewed-on: https://webrtc-review.googlesource.com/102540
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Paulina Hensman <phensman@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24894}
This commit is contained in:
Sami Kalliomäki
2018-09-28 14:38:21 +02:00
committed by Commit Bot
parent dca5a2ca73
commit ee05e90297
15 changed files with 213 additions and 35 deletions

View File

@ -18,4 +18,9 @@ public class AudioSource extends MediaSource {
public AudioSource(long nativeSource) {
super(nativeSource);
}
/** Returns a pointer to webrtc::AudioSourceInterface. */
long getNativeAudioSource() {
return getNativeMediaSource();
}
}

View File

@ -20,7 +20,12 @@ public class AudioTrack extends MediaStreamTrack {
* 0 to 10.
*/
public void setVolume(double volume) {
nativeSetVolume(super.nativeTrack, volume);
nativeSetVolume(getNativeAudioTrack(), volume);
}
/** Returns a pointer to webrtc::AudioTrackInterface. */
long getNativeAudioTrack() {
return getNativeMediaStreamTrack();
}
private static native void nativeSetVolume(long track, double volume);

View File

@ -102,7 +102,7 @@ public class DataChannel {
}
}
private final long nativeDataChannel;
private long nativeDataChannel;
private long nativeObserver;
@CalledByNative
@ -112,6 +112,7 @@ public class DataChannel {
/** Register |observer|, replacing any previously-registered observer. */
public void registerObserver(Observer observer) {
checkDataChannelExists();
if (nativeObserver != 0) {
nativeUnregisterObserver(nativeObserver);
}
@ -120,18 +121,22 @@ public class DataChannel {
/** Unregister the (only) observer. */
public void unregisterObserver() {
checkDataChannelExists();
nativeUnregisterObserver(nativeObserver);
}
public String label() {
checkDataChannelExists();
return nativeLabel();
}
public int id() {
checkDataChannelExists();
return nativeId();
}
public State state() {
checkDataChannelExists();
return nativeState();
}
@ -141,16 +146,19 @@ public class DataChannel {
* to the network.
*/
public long bufferedAmount() {
checkDataChannelExists();
return nativeBufferedAmount();
}
/** Close the channel. */
public void close() {
checkDataChannelExists();
nativeClose();
}
/** Send |data| to the remote peer; return success. */
public boolean send(Buffer buffer) {
checkDataChannelExists();
// TODO(fischman): this could be cleverer about avoiding copies if the
// ByteBuffer is direct and/or is backed by an array.
byte[] data = new byte[buffer.data.remaining()];
@ -160,7 +168,9 @@ public class DataChannel {
/** Dispose of native resources attached to this channel. */
public void dispose() {
checkDataChannelExists();
JniCommon.nativeReleaseRef(nativeDataChannel);
nativeDataChannel = 0;
}
@CalledByNative
@ -168,6 +178,12 @@ public class DataChannel {
return nativeDataChannel;
}
private void checkDataChannelExists() {
if (nativeDataChannel == 0) {
throw new IllegalStateException("DataChannel has been disposed.");
}
}
private native long nativeRegisterObserver(Observer observer);
private native void nativeUnregisterObserver(long observer);
private native String nativeLabel();

View File

@ -12,7 +12,7 @@ package org.webrtc;
/** Java wrapper for a C++ DtmfSenderInterface. */
public class DtmfSender {
final long nativeDtmfSender;
private long nativeDtmfSender;
public DtmfSender(long nativeDtmfSender) {
this.nativeDtmfSender = nativeDtmfSender;
@ -22,6 +22,7 @@ public class DtmfSender {
* @return true if this DtmfSender is capable of sending DTMF. Otherwise false.
*/
public boolean canInsertDtmf() {
checkDtmfSenderExists();
return nativeCanInsertDtmf(nativeDtmfSender);
}
@ -43,6 +44,7 @@ public class DtmfSender {
* @return true on success and false on failure.
*/
public boolean insertDtmf(String tones, int duration, int interToneGap) {
checkDtmfSenderExists();
return nativeInsertDtmf(nativeDtmfSender, tones, duration, interToneGap);
}
@ -50,6 +52,7 @@ public class DtmfSender {
* @return The tones remaining to be played out
*/
public String tones() {
checkDtmfSenderExists();
return nativeTones(nativeDtmfSender);
}
@ -58,6 +61,7 @@ public class DtmfSender {
* insertDtmf() method, or the default value of 100 ms if insertDtmf() was never called.
*/
public int duration() {
checkDtmfSenderExists();
return nativeDuration(nativeDtmfSender);
}
@ -67,11 +71,20 @@ public class DtmfSender {
* called.
*/
public int interToneGap() {
checkDtmfSenderExists();
return nativeInterToneGap(nativeDtmfSender);
}
public void dispose() {
checkDtmfSenderExists();
JniCommon.nativeReleaseRef(nativeDtmfSender);
nativeDtmfSender = 0;
}
private void checkDtmfSenderExists() {
if (nativeDtmfSender == 0) {
throw new IllegalStateException("DtmfSender has been disposed.");
}
}
private static native boolean nativeCanInsertDtmf(long dtmfSender);

View File

@ -25,18 +25,33 @@ public class MediaSource {
}
}
final long nativeSource; // Package-protected for PeerConnectionFactory.
private long nativeSource;
public MediaSource(long nativeSource) {
this.nativeSource = nativeSource;
}
public State state() {
checkMediaSourceExists();
return nativeGetState(nativeSource);
}
public void dispose() {
checkMediaSourceExists();
JniCommon.nativeReleaseRef(nativeSource);
nativeSource = 0;
}
/** Returns a pointer to webrtc::MediaSourceInterface. */
protected long getNativeMediaSource() {
checkMediaSourceExists();
return nativeSource;
}
private void checkMediaSourceExists() {
if (nativeSource == 0) {
throw new IllegalStateException("MediaSource has been disposed.");
}
}
private static native State nativeGetState(long pointer);

View File

@ -11,8 +11,8 @@
package org.webrtc;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.List;
/** Java wrapper for a C++ MediaStreamInterface. */
public class MediaStream {
@ -21,8 +21,7 @@ public class MediaStream {
public final List<AudioTrack> audioTracks = new ArrayList<>();
public final List<VideoTrack> videoTracks = new ArrayList<>();
public final List<VideoTrack> preservedVideoTracks = new ArrayList<>();
// Package-protected for PeerConnection.
final long nativeStream;
private long nativeStream;
@CalledByNative
public MediaStream(long nativeStream) {
@ -30,7 +29,8 @@ public class MediaStream {
}
public boolean addTrack(AudioTrack track) {
if (nativeAddAudioTrackToNativeStream(nativeStream, track.nativeTrack)) {
checkMediaStreamExists();
if (nativeAddAudioTrackToNativeStream(nativeStream, track.getNativeAudioTrack())) {
audioTracks.add(track);
return true;
}
@ -38,7 +38,8 @@ public class MediaStream {
}
public boolean addTrack(VideoTrack track) {
if (nativeAddVideoTrackToNativeStream(nativeStream, track.nativeTrack)) {
checkMediaStreamExists();
if (nativeAddVideoTrackToNativeStream(nativeStream, track.getNativeVideoTrack())) {
videoTracks.add(track);
return true;
}
@ -49,7 +50,8 @@ public class MediaStream {
// is called. If video track need to be preserved after MediaStream is destroyed it
// should be added to MediaStream using addPreservedTrack() call.
public boolean addPreservedTrack(VideoTrack track) {
if (nativeAddVideoTrackToNativeStream(nativeStream, track.nativeTrack)) {
checkMediaStreamExists();
if (nativeAddVideoTrackToNativeStream(nativeStream, track.getNativeVideoTrack())) {
preservedVideoTracks.add(track);
return true;
}
@ -57,18 +59,21 @@ public class MediaStream {
}
public boolean removeTrack(AudioTrack track) {
checkMediaStreamExists();
audioTracks.remove(track);
return nativeRemoveAudioTrack(nativeStream, track.nativeTrack);
return nativeRemoveAudioTrack(nativeStream, track.getNativeAudioTrack());
}
public boolean removeTrack(VideoTrack track) {
checkMediaStreamExists();
videoTracks.remove(track);
preservedVideoTracks.remove(track);
return nativeRemoveVideoTrack(nativeStream, track.nativeTrack);
return nativeRemoveVideoTrack(nativeStream, track.getNativeVideoTrack());
}
@CalledByNative
public void dispose() {
checkMediaStreamExists();
// Remove and release previously added audio and video tracks.
while (!audioTracks.isEmpty()) {
AudioTrack track = audioTracks.get(0 /* index */);
@ -85,9 +90,11 @@ public class MediaStream {
removeTrack(preservedVideoTracks.get(0 /* index */));
}
JniCommon.nativeReleaseRef(nativeStream);
nativeStream = 0;
}
public String getId() {
checkMediaStreamExists();
return nativeGetId(nativeStream);
}
@ -116,12 +123,24 @@ public class MediaStream {
removeMediaStreamTrack(videoTracks, nativeTrack);
}
/** Returns a pointer to webrtc::MediaStreamInterface. */
long getNativeMediaStream() {
checkMediaStreamExists();
return nativeStream;
}
private void checkMediaStreamExists() {
if (nativeStream == 0) {
throw new IllegalStateException("MediaStream has been disposed.");
}
}
private static void removeMediaStreamTrack(
List<? extends MediaStreamTrack> tracks, long nativeTrack) {
final Iterator<? extends MediaStreamTrack> it = tracks.iterator();
while (it.hasNext()) {
MediaStreamTrack track = it.next();
if (track.nativeTrack == nativeTrack) {
if (track.getNativeMediaStreamTrack() == nativeTrack) {
track.dispose();
it.remove();
return;

View File

@ -70,34 +70,52 @@ public class MediaStreamTrack {
}
}
final long nativeTrack;
private long nativeTrack;
public MediaStreamTrack(long nativeTrack) {
this.nativeTrack = nativeTrack;
}
public String id() {
checkMediaStreamTrackExists();
return nativeGetId(nativeTrack);
}
public String kind() {
checkMediaStreamTrackExists();
return nativeGetKind(nativeTrack);
}
public boolean enabled() {
checkMediaStreamTrackExists();
return nativeGetEnabled(nativeTrack);
}
public boolean setEnabled(boolean enable) {
checkMediaStreamTrackExists();
return nativeSetEnabled(nativeTrack, enable);
}
public State state() {
checkMediaStreamTrackExists();
return nativeGetState(nativeTrack);
}
public void dispose() {
checkMediaStreamTrackExists();
JniCommon.nativeReleaseRef(nativeTrack);
nativeTrack = 0;
}
long getNativeMediaStreamTrack() {
checkMediaStreamTrackExists();
return nativeTrack;
}
private void checkMediaStreamTrackExists() {
if (nativeTrack == 0) {
throw new IllegalStateException("MediaStreamTrack has been disposed.");
}
}
private static native String nativeGetId(long track);

View File

@ -781,7 +781,7 @@ public class PeerConnection {
* use addTrack instead.
*/
public boolean addStream(MediaStream stream) {
boolean ret = nativeAddLocalStream(stream.nativeStream);
boolean ret = nativeAddLocalStream(stream.getNativeMediaStream());
if (!ret) {
return false;
}
@ -795,7 +795,7 @@ public class PeerConnection {
* removeTrack instead.
*/
public void removeStream(MediaStream stream) {
nativeRemoveLocalStream(stream.nativeStream);
nativeRemoveLocalStream(stream.getNativeMediaStream());
localStreams.remove(stream);
}
@ -905,7 +905,7 @@ public class PeerConnection {
if (track == null || streamIds == null) {
throw new NullPointerException("No MediaStreamTrack specified in addTrack.");
}
RtpSender newSender = nativeAddTrack(track.nativeTrack, streamIds);
RtpSender newSender = nativeAddTrack(track.getNativeMediaStreamTrack(), streamIds);
if (newSender == null) {
throw new IllegalStateException("C++ addTrack failed.");
}
@ -922,7 +922,7 @@ public class PeerConnection {
if (sender == null) {
throw new NullPointerException("No RtpSender specified for removeTrack.");
}
return nativeRemoveTrack(sender.nativeRtpSender);
return nativeRemoveTrack(sender.getNativeRtpSender());
}
/**
@ -962,7 +962,8 @@ public class PeerConnection {
if (init == null) {
init = new RtpTransceiver.RtpTransceiverInit();
}
RtpTransceiver newTransceiver = nativeAddTransceiverWithTrack(track.nativeTrack, init);
RtpTransceiver newTransceiver =
nativeAddTransceiverWithTrack(track.getNativeMediaStreamTrack(), init);
if (newTransceiver == null) {
throw new IllegalStateException("C++ addTransceiver failed.");
}
@ -993,7 +994,7 @@ public class PeerConnection {
// Older, non-standard implementation of getStats.
@Deprecated
public boolean getStats(StatsObserver observer, @Nullable MediaStreamTrack track) {
return nativeOldGetStats(observer, (track == null) ? 0 : track.nativeTrack);
return nativeOldGetStats(observer, (track == null) ? 0 : track.getNativeMediaStreamTrack());
}
/**
@ -1070,7 +1071,7 @@ public class PeerConnection {
public void dispose() {
close();
for (MediaStream stream : localStreams) {
nativeRemoveLocalStream(stream.nativeStream);
nativeRemoveLocalStream(stream.getNativeMediaStream());
stream.dispose();
}
localStreams.clear();

View File

@ -28,7 +28,7 @@ public class PeerConnectionFactory {
private static final String TAG = "PeerConnectionFactory";
private static final String VIDEO_CAPTURER_THREAD_NAME = "VideoCapturerThread";
private final long nativeFactory;
private long nativeFactory;
private static volatile boolean internalTracerInitialized;
@Nullable private static Thread networkThread;
@Nullable private static Thread workerThread;
@ -307,6 +307,7 @@ public class PeerConnectionFactory {
PeerConnection createPeerConnectionInternal(PeerConnection.RTCConfiguration rtcConfig,
MediaConstraints constraints, PeerConnection.Observer observer,
SSLCertificateVerifier sslCertificateVerifier) {
checkPeerConnectionFactoryExists();
long nativeObserver = PeerConnection.createNativePeerConnectionObserver(observer);
if (nativeObserver == 0) {
return null;
@ -364,61 +365,80 @@ public class PeerConnectionFactory {
}
public MediaStream createLocalMediaStream(String label) {
checkPeerConnectionFactoryExists();
return new MediaStream(nativeCreateLocalMediaStream(nativeFactory, label));
}
public VideoSource createVideoSource(boolean isScreencast) {
checkPeerConnectionFactoryExists();
return new VideoSource(nativeCreateVideoSource(nativeFactory, isScreencast));
}
public VideoTrack createVideoTrack(String id, VideoSource source) {
return new VideoTrack(nativeCreateVideoTrack(nativeFactory, id, source.nativeSource));
checkPeerConnectionFactoryExists();
return new VideoTrack(
nativeCreateVideoTrack(nativeFactory, id, source.getNativeVideoTrackSource()));
}
public AudioSource createAudioSource(MediaConstraints constraints) {
checkPeerConnectionFactoryExists();
return new AudioSource(nativeCreateAudioSource(nativeFactory, constraints));
}
public AudioTrack createAudioTrack(String id, AudioSource source) {
return new AudioTrack(nativeCreateAudioTrack(nativeFactory, id, source.nativeSource));
checkPeerConnectionFactoryExists();
return new AudioTrack(nativeCreateAudioTrack(nativeFactory, id, source.getNativeAudioSource()));
}
// Starts recording an AEC dump. Ownership of the file is transfered to the
// native code. If an AEC dump is already in progress, it will be stopped and
// a new one will start using the provided file.
public boolean startAecDump(int file_descriptor, int filesize_limit_bytes) {
checkPeerConnectionFactoryExists();
return nativeStartAecDump(nativeFactory, file_descriptor, filesize_limit_bytes);
}
// Stops recording an AEC dump. If no AEC dump is currently being recorded,
// this call will have no effect.
public void stopAecDump() {
checkPeerConnectionFactoryExists();
nativeStopAecDump(nativeFactory);
}
public void dispose() {
checkPeerConnectionFactoryExists();
nativeFreeFactory(nativeFactory);
networkThread = null;
workerThread = null;
signalingThread = null;
MediaCodecVideoEncoder.disposeEglContext();
MediaCodecVideoDecoder.disposeEglContext();
nativeFactory = 0;
}
public void threadsCallbacks() {
checkPeerConnectionFactoryExists();
nativeInvokeThreadsCallbacks(nativeFactory);
}
/** Returns a pointer to the native webrtc::PeerConnectionFactoryInterface. */
public long getNativePeerConnectionFactory() {
checkPeerConnectionFactoryExists();
return nativeGetNativePeerConnectionFactory(nativeFactory);
}
/** Returns a pointer to the native OwnedFactoryAndThreads object */
public long getNativeOwnedFactoryAndThreads() {
checkPeerConnectionFactoryExists();
return nativeFactory;
}
private void checkPeerConnectionFactoryExists() {
if (nativeFactory == 0) {
throw new IllegalStateException("PeerConnectionFactory has been disposed.");
}
}
private static void printStackTrace(@Nullable Thread thread, String threadName) {
if (thread != null) {
StackTraceElement[] stackTraces = thread.getStackTrace();

View File

@ -22,7 +22,7 @@ public class RtpReceiver {
public void onFirstPacketReceived(MediaStreamTrack.MediaType media_type);
}
final long nativeRtpReceiver;
private long nativeRtpReceiver;
private long nativeObserver;
@Nullable private MediaStreamTrack cachedTrack;
@ -40,28 +40,34 @@ public class RtpReceiver {
}
public boolean setParameters(@Nullable RtpParameters parameters) {
checkRtpReceiverExists();
return parameters == null ? false : nativeSetParameters(nativeRtpReceiver, parameters);
}
public RtpParameters getParameters() {
checkRtpReceiverExists();
return nativeGetParameters(nativeRtpReceiver);
}
public String id() {
checkRtpReceiverExists();
return nativeGetId(nativeRtpReceiver);
}
@CalledByNative
public void dispose() {
checkRtpReceiverExists();
cachedTrack.dispose();
if (nativeObserver != 0) {
nativeUnsetObserver(nativeRtpReceiver, nativeObserver);
nativeObserver = 0;
}
JniCommon.nativeReleaseRef(nativeRtpReceiver);
nativeRtpReceiver = 0;
}
public void SetObserver(Observer observer) {
checkRtpReceiverExists();
// Unset the existing one before setting a new one.
if (nativeObserver != 0) {
nativeUnsetObserver(nativeRtpReceiver, nativeObserver);
@ -70,9 +76,16 @@ public class RtpReceiver {
}
public void setFrameDecryptor(FrameDecryptor frameDecryptor) {
checkRtpReceiverExists();
nativeSetFrameDecryptor(nativeRtpReceiver, frameDecryptor.getNativeFrameDecryptor());
}
private void checkRtpReceiverExists() {
if (nativeRtpReceiver == 0) {
throw new IllegalStateException("RtpReceiver has been disposed.");
}
}
// This should increment the reference count of the track.
// Will be released in dispose().
private static native long nativeGetTrack(long rtpReceiver);

View File

@ -14,7 +14,7 @@ import javax.annotation.Nullable;
/** Java wrapper for a C++ RtpSenderInterface. */
public class RtpSender {
final long nativeRtpSender;
private long nativeRtpSender;
@Nullable private MediaStreamTrack cachedTrack;
private boolean ownsTrack = true;
@ -45,7 +45,8 @@ public class RtpSender {
* @return true on success and false on failure.
*/
public boolean setTrack(@Nullable MediaStreamTrack track, boolean takeOwnership) {
if (!nativeSetTrack(nativeRtpSender, (track == null) ? 0 : track.nativeTrack)) {
checkRtpSenderExists();
if (!nativeSetTrack(nativeRtpSender, (track == null) ? 0 : track.getNativeMediaStreamTrack())) {
return false;
}
if (cachedTrack != null && ownsTrack) {
@ -62,14 +63,17 @@ public class RtpSender {
}
public boolean setParameters(RtpParameters parameters) {
checkRtpSenderExists();
return nativeSetParameters(nativeRtpSender, parameters);
}
public RtpParameters getParameters() {
checkRtpSenderExists();
return nativeGetParameters(nativeRtpSender);
}
public String id() {
checkRtpSenderExists();
return nativeGetId(nativeRtpSender);
}
@ -79,10 +83,12 @@ public class RtpSender {
}
public void setFrameEncryptor(FrameEncryptor frameEncryptor) {
checkRtpSenderExists();
nativeSetFrameEncryptor(nativeRtpSender, frameEncryptor.getNativeFrameEncryptor());
}
public void dispose() {
checkRtpSenderExists();
if (dtmfSender != null) {
dtmfSender.dispose();
}
@ -90,6 +96,19 @@ public class RtpSender {
cachedTrack.dispose();
}
JniCommon.nativeReleaseRef(nativeRtpSender);
nativeRtpSender = 0;
}
/** Returns a pointer to webrtc::RtpSenderInterface. */
long getNativeRtpSender() {
checkRtpSenderExists();
return nativeRtpSender;
}
private void checkRtpSenderExists() {
if (nativeRtpSender == 0) {
throw new IllegalStateException("RtpSender has been disposed.");
}
}
private static native boolean nativeSetTrack(long rtpSender, long nativeTrack);

View File

@ -13,7 +13,6 @@ 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.
@ -96,7 +95,7 @@ public class RtpTransceiver {
}
}
private final long nativeRtpTransceiver;
private long nativeRtpTransceiver;
private RtpSender cachedSender;
private RtpReceiver cachedReceiver;
@ -112,6 +111,7 @@ public class RtpTransceiver {
* type as well.
*/
public MediaStreamTrack.MediaType getMediaType() {
checkRtpTransceiverExists();
return nativeGetMediaType(nativeRtpTransceiver);
}
@ -122,6 +122,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
*/
public String getMid() {
checkRtpTransceiverExists();
return nativeGetMid(nativeRtpTransceiver);
}
@ -153,6 +154,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped
*/
public boolean isStopped() {
checkRtpTransceiverExists();
return nativeStopped(nativeRtpTransceiver);
}
@ -162,6 +164,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/
public RtpTransceiverDirection getDirection() {
checkRtpTransceiverExists();
return nativeDirection(nativeRtpTransceiver);
}
@ -172,6 +175,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
*/
public RtpTransceiverDirection getCurrentDirection() {
checkRtpTransceiverExists();
return nativeCurrentDirection(nativeRtpTransceiver);
}
@ -183,6 +187,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/
public void setDirection(RtpTransceiverDirection rtpTransceiverDirection) {
checkRtpTransceiverExists();
nativeSetDirection(nativeRtpTransceiver, rtpTransceiverDirection);
}
@ -192,14 +197,23 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop
*/
public void stop() {
checkRtpTransceiverExists();
nativeStop(nativeRtpTransceiver);
}
@CalledByNative
public void dispose() {
checkRtpTransceiverExists();
cachedSender.dispose();
cachedReceiver.dispose();
JniCommon.nativeReleaseRef(nativeRtpTransceiver);
nativeRtpTransceiver = 0;
}
private void checkRtpTransceiverExists() {
if (nativeRtpTransceiver == 0) {
throw new IllegalStateException("RtpTransceiver has been disposed.");
}
}
private static native MediaStreamTrack.MediaType nativeGetMediaType(long rtpTransceiver);

View File

@ -12,20 +12,30 @@ package org.webrtc;
/** Java wrapper for a C++ TurnCustomizer. */
public class TurnCustomizer {
final long nativeTurnCustomizer;
private long nativeTurnCustomizer;
public TurnCustomizer(long nativeTurnCustomizer) {
this.nativeTurnCustomizer = nativeTurnCustomizer;
}
public void dispose() {
checkTurnCustomizerExists();
nativeFreeTurnCustomizer(nativeTurnCustomizer);
nativeTurnCustomizer = 0;
}
private static native void nativeFreeTurnCustomizer(long turnCustomizer);
/** Return a pointer to webrtc::TurnCustomizer. */
@CalledByNative
long getNativeTurnCustomizer() {
checkTurnCustomizerExists();
return nativeTurnCustomizer;
}
private void checkTurnCustomizerExists() {
if (nativeTurnCustomizer == 0) {
throw new IllegalStateException("TurnCustomizer has been disposed.");
}
}
}

View File

@ -30,13 +30,18 @@ public class VideoSource extends MediaSource {
* maintain the input orientation, so it doesn't matter if e.g. 1280x720 or 720x1280 is requested.
*/
public void adaptOutputFormat(int width, int height, int fps) {
nativeAdaptOutputFormat(nativeSource, width, height, fps);
nativeAdaptOutputFormat(getNativeVideoTrackSource(), width, height, fps);
}
public CapturerObserver getCapturerObserver() {
return capturerObserver;
}
/** Returns a pointer to webrtc::VideoTrackSourceInterface. */
long getNativeVideoTrackSource() {
return getNativeMediaSource();
}
// Returns source->internal() from webrtc::VideoTrackSourceProxy.
private static native long nativeGetInternalSource(long source);
private static native void nativeAdaptOutputFormat(long source, int width, int height, int fps);

View File

@ -10,8 +10,8 @@
package org.webrtc;
import java.util.IdentityHashMap;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
/** Java version of VideoTrackInterface. */
@ -39,7 +39,7 @@ public class VideoTrack extends MediaStreamTrack {
if (!sinks.containsKey(sink)) {
final long nativeSink = nativeWrapSink(sink);
sinks.put(sink, nativeSink);
nativeAddSink(nativeTrack, nativeSink);
nativeAddSink(getNativeMediaStreamTrack(), nativeSink);
}
}
@ -51,7 +51,7 @@ public class VideoTrack extends MediaStreamTrack {
public void removeSink(VideoSink sink) {
final Long nativeSink = sinks.remove(sink);
if (nativeSink != null) {
nativeRemoveSink(nativeTrack, nativeSink);
nativeRemoveSink(getNativeMediaStreamTrack(), nativeSink);
nativeFreeSink(nativeSink);
}
}
@ -59,13 +59,18 @@ public class VideoTrack extends MediaStreamTrack {
@Override
public void dispose() {
for (long nativeSink : sinks.values()) {
nativeRemoveSink(nativeTrack, nativeSink);
nativeRemoveSink(getNativeMediaStreamTrack(), nativeSink);
nativeFreeSink(nativeSink);
}
sinks.clear();
super.dispose();
}
/** Returns a pointer to webrtc::VideoTrackInterface. */
long getNativeVideoTrack() {
return getNativeMediaStreamTrack();
}
private static native void nativeAddSink(long track, long nativeSink);
private static native void nativeRemoveSink(long track, long nativeSink);
private static native long nativeWrapSink(VideoSink sink);