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

View File

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

View File

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

View File

@ -70,34 +70,52 @@ public class MediaStreamTrack {
} }
} }
final long nativeTrack; private long nativeTrack;
public MediaStreamTrack(long nativeTrack) { public MediaStreamTrack(long nativeTrack) {
this.nativeTrack = nativeTrack; this.nativeTrack = nativeTrack;
} }
public String id() { public String id() {
checkMediaStreamTrackExists();
return nativeGetId(nativeTrack); return nativeGetId(nativeTrack);
} }
public String kind() { public String kind() {
checkMediaStreamTrackExists();
return nativeGetKind(nativeTrack); return nativeGetKind(nativeTrack);
} }
public boolean enabled() { public boolean enabled() {
checkMediaStreamTrackExists();
return nativeGetEnabled(nativeTrack); return nativeGetEnabled(nativeTrack);
} }
public boolean setEnabled(boolean enable) { public boolean setEnabled(boolean enable) {
checkMediaStreamTrackExists();
return nativeSetEnabled(nativeTrack, enable); return nativeSetEnabled(nativeTrack, enable);
} }
public State state() { public State state() {
checkMediaStreamTrackExists();
return nativeGetState(nativeTrack); return nativeGetState(nativeTrack);
} }
public void dispose() { public void dispose() {
checkMediaStreamTrackExists();
JniCommon.nativeReleaseRef(nativeTrack); 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); private static native String nativeGetId(long track);

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ import javax.annotation.Nullable;
/** Java wrapper for a C++ RtpSenderInterface. */ /** Java wrapper for a C++ RtpSenderInterface. */
public class RtpSender { public class RtpSender {
final long nativeRtpSender; private long nativeRtpSender;
@Nullable private MediaStreamTrack cachedTrack; @Nullable private MediaStreamTrack cachedTrack;
private boolean ownsTrack = true; private boolean ownsTrack = true;
@ -45,7 +45,8 @@ public class RtpSender {
* @return true on success and false on failure. * @return true on success and false on failure.
*/ */
public boolean setTrack(@Nullable MediaStreamTrack track, boolean takeOwnership) { 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; return false;
} }
if (cachedTrack != null && ownsTrack) { if (cachedTrack != null && ownsTrack) {
@ -62,14 +63,17 @@ public class RtpSender {
} }
public boolean setParameters(RtpParameters parameters) { public boolean setParameters(RtpParameters parameters) {
checkRtpSenderExists();
return nativeSetParameters(nativeRtpSender, parameters); return nativeSetParameters(nativeRtpSender, parameters);
} }
public RtpParameters getParameters() { public RtpParameters getParameters() {
checkRtpSenderExists();
return nativeGetParameters(nativeRtpSender); return nativeGetParameters(nativeRtpSender);
} }
public String id() { public String id() {
checkRtpSenderExists();
return nativeGetId(nativeRtpSender); return nativeGetId(nativeRtpSender);
} }
@ -79,10 +83,12 @@ public class RtpSender {
} }
public void setFrameEncryptor(FrameEncryptor frameEncryptor) { public void setFrameEncryptor(FrameEncryptor frameEncryptor) {
checkRtpSenderExists();
nativeSetFrameEncryptor(nativeRtpSender, frameEncryptor.getNativeFrameEncryptor()); nativeSetFrameEncryptor(nativeRtpSender, frameEncryptor.getNativeFrameEncryptor());
} }
public void dispose() { public void dispose() {
checkRtpSenderExists();
if (dtmfSender != null) { if (dtmfSender != null) {
dtmfSender.dispose(); dtmfSender.dispose();
} }
@ -90,6 +96,19 @@ public class RtpSender {
cachedTrack.dispose(); cachedTrack.dispose();
} }
JniCommon.nativeReleaseRef(nativeRtpSender); 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); 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.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.webrtc.RtpParameters.Encoding;
/** /**
* Java wrapper for a C++ RtpTransceiverInterface. * Java wrapper for a C++ RtpTransceiverInterface.
@ -96,7 +95,7 @@ public class RtpTransceiver {
} }
} }
private final long nativeRtpTransceiver; private long nativeRtpTransceiver;
private RtpSender cachedSender; private RtpSender cachedSender;
private RtpReceiver cachedReceiver; private RtpReceiver cachedReceiver;
@ -112,6 +111,7 @@ public class RtpTransceiver {
* type as well. * type as well.
*/ */
public MediaStreamTrack.MediaType getMediaType() { public MediaStreamTrack.MediaType getMediaType() {
checkRtpTransceiverExists();
return nativeGetMediaType(nativeRtpTransceiver); return nativeGetMediaType(nativeRtpTransceiver);
} }
@ -122,6 +122,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid
*/ */
public String getMid() { public String getMid() {
checkRtpTransceiverExists();
return nativeGetMid(nativeRtpTransceiver); return nativeGetMid(nativeRtpTransceiver);
} }
@ -153,6 +154,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped
*/ */
public boolean isStopped() { public boolean isStopped() {
checkRtpTransceiverExists();
return nativeStopped(nativeRtpTransceiver); return nativeStopped(nativeRtpTransceiver);
} }
@ -162,6 +164,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/ */
public RtpTransceiverDirection getDirection() { public RtpTransceiverDirection getDirection() {
checkRtpTransceiverExists();
return nativeDirection(nativeRtpTransceiver); return nativeDirection(nativeRtpTransceiver);
} }
@ -172,6 +175,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection
*/ */
public RtpTransceiverDirection getCurrentDirection() { public RtpTransceiverDirection getCurrentDirection() {
checkRtpTransceiverExists();
return nativeCurrentDirection(nativeRtpTransceiver); return nativeCurrentDirection(nativeRtpTransceiver);
} }
@ -183,6 +187,7 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction
*/ */
public void setDirection(RtpTransceiverDirection rtpTransceiverDirection) { public void setDirection(RtpTransceiverDirection rtpTransceiverDirection) {
checkRtpTransceiverExists();
nativeSetDirection(nativeRtpTransceiver, rtpTransceiverDirection); nativeSetDirection(nativeRtpTransceiver, rtpTransceiverDirection);
} }
@ -192,14 +197,23 @@ public class RtpTransceiver {
* https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop * https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop
*/ */
public void stop() { public void stop() {
checkRtpTransceiverExists();
nativeStop(nativeRtpTransceiver); nativeStop(nativeRtpTransceiver);
} }
@CalledByNative @CalledByNative
public void dispose() { public void dispose() {
checkRtpTransceiverExists();
cachedSender.dispose(); cachedSender.dispose();
cachedReceiver.dispose(); cachedReceiver.dispose();
JniCommon.nativeReleaseRef(nativeRtpTransceiver); 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); private static native MediaStreamTrack.MediaType nativeGetMediaType(long rtpTransceiver);

View File

@ -12,20 +12,30 @@ package org.webrtc;
/** Java wrapper for a C++ TurnCustomizer. */ /** Java wrapper for a C++ TurnCustomizer. */
public class TurnCustomizer { public class TurnCustomizer {
final long nativeTurnCustomizer; private long nativeTurnCustomizer;
public TurnCustomizer(long nativeTurnCustomizer) { public TurnCustomizer(long nativeTurnCustomizer) {
this.nativeTurnCustomizer = nativeTurnCustomizer; this.nativeTurnCustomizer = nativeTurnCustomizer;
} }
public void dispose() { public void dispose() {
checkTurnCustomizerExists();
nativeFreeTurnCustomizer(nativeTurnCustomizer); nativeFreeTurnCustomizer(nativeTurnCustomizer);
nativeTurnCustomizer = 0;
} }
private static native void nativeFreeTurnCustomizer(long turnCustomizer); private static native void nativeFreeTurnCustomizer(long turnCustomizer);
/** Return a pointer to webrtc::TurnCustomizer. */
@CalledByNative @CalledByNative
long getNativeTurnCustomizer() { long getNativeTurnCustomizer() {
checkTurnCustomizerExists();
return nativeTurnCustomizer; 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. * 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) { public void adaptOutputFormat(int width, int height, int fps) {
nativeAdaptOutputFormat(nativeSource, width, height, fps); nativeAdaptOutputFormat(getNativeVideoTrackSource(), width, height, fps);
} }
public CapturerObserver getCapturerObserver() { public CapturerObserver getCapturerObserver() {
return capturerObserver; return capturerObserver;
} }
/** Returns a pointer to webrtc::VideoTrackSourceInterface. */
long getNativeVideoTrackSource() {
return getNativeMediaSource();
}
// Returns source->internal() from webrtc::VideoTrackSourceProxy. // Returns source->internal() from webrtc::VideoTrackSourceProxy.
private static native long nativeGetInternalSource(long source); private static native long nativeGetInternalSource(long source);
private static native void nativeAdaptOutputFormat(long source, int width, int height, int fps); private static native void nativeAdaptOutputFormat(long source, int width, int height, int fps);

View File

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