Skip to content

Commit d004e93

Browse files
committed
chore: cleanup for android on bridge reload
1 parent 13da032 commit d004e93

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,17 @@ void mediaStreamTrackSetEnabled(String trackId, final boolean enabled) {
285285
}
286286
}
287287

288+
void disposeAllTracks() {
289+
for (Map.Entry<String, TrackPrivate> entry : tracks.entrySet()) {
290+
try {
291+
entry.getValue().dispose();
292+
} catch (Exception e) {
293+
Log.w(TAG, "disposeAllTracks: error disposing " + entry.getKey(), e);
294+
}
295+
}
296+
tracks.clear();
297+
}
298+
288299
void disposeTrack(String id) {
289300
TrackPrivate track = tracks.remove(id);
290301
if (track != null) {
@@ -344,6 +355,8 @@ public void run() {
344355
}
345356

346357
private void createScreenStream() {
358+
// Guards against onServiceConnected firing after invalidate() has disposed and nulled mFactory.
359+
if (webRTCModule.mFactory == null) return;
347360
VideoTrack track = createScreenTrack();
348361

349362
if (track == null) {

android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,46 @@ public WebRTCModule(ReactApplicationContext reactContext) {
124124
getUserMediaImpl = new GetUserMediaImpl(this, reactContext);
125125
}
126126

127+
@Override
128+
public void invalidate() {
129+
Log.d(TAG, "invalidate()");
130+
131+
try {
132+
ThreadUtils.submitToExecutor(() -> {
133+
// 1. Dispose PeerConnections (dispose() calls close() internally)
134+
for (int i = 0; i < mPeerConnectionObservers.size(); i++) {
135+
try {
136+
mPeerConnectionObservers.valueAt(i).dispose();
137+
} catch (Exception e) {
138+
Log.w(TAG, "invalidate(): error disposing PC " + mPeerConnectionObservers.keyAt(i), e);
139+
}
140+
}
141+
mPeerConnectionObservers.clear();
142+
143+
// 2. Stop capturers + dispose tracks (prevents use-after-free on factory threads)
144+
getUserMediaImpl.disposeAllTracks();
145+
146+
// 3. Dispose local streams
147+
for (MediaStream stream : localStreams.values()) {
148+
stream.dispose();
149+
}
150+
localStreams.clear();
151+
152+
// 4. Dispose factory (frees C++ factory + 3 threads)
153+
if (mFactory != null) {
154+
mFactory.dispose();
155+
mFactory = null;
156+
}
157+
158+
return null;
159+
}).get();
160+
} catch (InterruptedException | ExecutionException e) {
161+
Log.e(TAG, "invalidate() error", e);
162+
}
163+
164+
super.invalidate();
165+
}
166+
127167
private JavaAudioDeviceModule createAudioDeviceModule(ReactApplicationContext reactContext) {
128168
speechActivityDetector = new SpeechActivityDetector(new SpeechActivityDetector.Listener() {
129169
@Override

0 commit comments

Comments
 (0)