Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,17 @@ void mediaStreamTrackSetEnabled(String trackId, final boolean enabled) {
}
}

void disposeAllTracks() {
for (Map.Entry<String, TrackPrivate> entry : tracks.entrySet()) {
try {
entry.getValue().dispose();
} catch (Exception e) {
Log.w(TAG, "disposeAllTracks: error disposing " + entry.getKey(), e);
}
}
tracks.clear();
}

void disposeTrack(String id) {
TrackPrivate track = tracks.remove(id);
if (track != null) {
Expand Down Expand Up @@ -344,6 +355,14 @@ public void run() {
}

private void createScreenStream() {
// Guards against onServiceConnected firing after invalidate() has disposed and nulled mFactory.
if (webRTCModule.mFactory == null) {
if (displayMediaPromise != null) {
displayMediaPromise.reject("ERR_MODULE_DISPOSED", "WebRTCModule disposed during getDisplayMedia");
displayMediaPromise = null;
}
return;
}
VideoTrack track = createScreenTrack();

if (track == null) {
Expand Down Expand Up @@ -614,9 +633,10 @@ public void dispose() {
}
}

// Clean up VideoTrackAdapter for video tracks
if (!isClone && videoTrackAdapter != null && track instanceof VideoTrack) {
// Clean up VideoTrackAdapter for video tracks (each TrackPrivate, incl. clones, has its own)
if (videoTrackAdapter != null && track instanceof VideoTrack) {
videoTrackAdapter.removeDimensionDetector((VideoTrack) track);
videoTrackAdapter.dispose();
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ void dispose() {
// by the PeerConnection instance (RtpReceivers, RtpSenders, etc.)
peerConnection.dispose();

videoTrackAdapters.dispose();

remoteStreamIds.clear();
remoteStreams.clear();
remoteTracks.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ public void removeDimensionDetector(VideoTrack videoTrack) {
Log.d(TAG, "Deleted dimension detector for " + trackId);
}

void dispose() {
timer.cancel();
}

/**
* Implements 'mute'/'unmute' events for remote video tracks through
* the {@link VideoSink} interface.
Expand Down
47 changes: 47 additions & 0 deletions android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,53 @@ public WebRTCModule(ReactApplicationContext reactContext) {
getUserMediaImpl = new GetUserMediaImpl(this, reactContext);
}

@Override
public void invalidate() {
Log.d(TAG, "invalidate()");

try {
ThreadUtils.submitToExecutor(() -> {
// 1. Dispose PeerConnections (dispose() calls close() internally)
for (int i = 0; i < mPeerConnectionObservers.size(); i++) {
try {
mPeerConnectionObservers.valueAt(i).dispose();
} catch (Exception e) {
Log.w(TAG, "invalidate(): error disposing PC " + mPeerConnectionObservers.keyAt(i), e);
}
}
mPeerConnectionObservers.clear();

// 2. Detach tracks, then dispose streams. Tracks themselves get disposed in step 3.
for (Map.Entry<String, MediaStream> entry : localStreams.entrySet()) {
try {
MediaStream stream = entry.getValue();
for (AudioTrack t : new ArrayList<>(stream.audioTracks)) stream.removeTrack(t);
for (VideoTrack t : new ArrayList<>(stream.videoTracks)) stream.removeTrack(t);
stream.dispose();
} catch (Exception e) {
Log.w(TAG, "invalidate(): error disposing stream " + entry.getKey(), e);
}
}
localStreams.clear();

// 3. Stop capturers + dispose tracks (prevents use-after-free on factory threads)
getUserMediaImpl.disposeAllTracks();

// 4. Dispose factory (frees C++ factory + 3 threads)
if (mFactory != null) {
mFactory.dispose();
mFactory = null;
}

return null;
}).get();
} catch (InterruptedException | ExecutionException e) {
Log.e(TAG, "invalidate() error", e);
}

super.invalidate();
}

private JavaAudioDeviceModule createAudioDeviceModule(ReactApplicationContext reactContext) {
speechActivityDetector = new SpeechActivityDetector(new SpeechActivityDetector.Listener() {
@Override
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stream-io/react-native-webrtc",
"version": "137.1.4-alpha.5",
"version": "137.1.4-alpha.8",
"repository": {
"type": "git",
"url": "git+https://github.com/GetStream/react-native-webrtc.git"
Expand Down
Loading