Fix EGL crash when ending call.

This commit is contained in:
Cody Henthorne 2021-11-10 13:01:48 -05:00
parent 8a05626791
commit f0ab919ca5
14 changed files with 105 additions and 114 deletions

View file

@ -31,7 +31,7 @@ public class BroadcastVideoSink implements VideoSink {
private RequestedSize currentlyRequestedMaxSize; private RequestedSize currentlyRequestedMaxSize;
public BroadcastVideoSink() { public BroadcastVideoSink() {
this(new EglBaseWrapper(null), false, true, 0); this(new EglBaseWrapper(), false, true, 0);
} }
/** /**

View file

@ -15,16 +15,21 @@ private val TAG = Log.tag(EglBaseWrapper::class.java)
/** /**
* Wrapper which allows caller to perform synchronized actions on an EglBase object. * Wrapper which allows caller to perform synchronized actions on an EglBase object.
*/ * Must use [acquireEglBase] to get a valid instance to an [EglBaseWrapper] for use in calling.
class EglBaseWrapper(val eglBase: EglBase?) { * The instance returned may be shared across calls. Call [releaseEglBase] when it is no longer
* required. When the wrapper has no others are using it, it will be properly released (a la reference counting).
*/
class EglBaseWrapper private constructor(val eglBase: EglBase?) {
private val lock: Lock = ReentrantLock() private val lock: Lock = ReentrantLock()
fun require(): EglBase = requireNotNull(eglBase)
@Volatile @Volatile
private var isReleased: Boolean = false private var isReleased: Boolean = false
constructor() : this(null)
fun require(): EglBase = requireNotNull(eglBase)
fun performWithValidEglBase(consumer: Consumer<EglBase>) { fun performWithValidEglBase(consumer: Consumer<EglBase>) {
if (isReleased) { if (isReleased) {
Log.d(TAG, "Tried to use a released EglBase", Exception()) Log.d(TAG, "Tried to use a released EglBase", Exception())
@ -53,7 +58,7 @@ class EglBaseWrapper(val eglBase: EglBase?) {
} }
} }
fun releaseEglBase() { private fun releaseEglBase() {
if (isReleased || eglBase == null) { if (isReleased || eglBase == null) {
return return
} }
@ -67,4 +72,48 @@ class EglBaseWrapper(val eglBase: EglBase?) {
eglBase.release() eglBase.release()
} }
} }
companion object {
const val OUTGOING_PLACEHOLDER: String = "OUTGOING_PLACEHOLDER"
private var eglBaseWrapper: EglBaseWrapper? = null
private val holders: MutableSet<Any> = mutableSetOf()
@JvmStatic
fun acquireEglBase(holder: Any): EglBaseWrapper {
val eglBase: EglBaseWrapper = eglBaseWrapper ?: EglBaseWrapper(EglBase.create())
eglBaseWrapper = eglBase
holders += holder
Log.d(TAG, "Acquire EGL $eglBaseWrapper with holder: $holder")
return eglBase
}
@JvmStatic
fun releaseEglBase(holder: Any) {
Log.d(TAG, "Release EGL with holder: $holder")
holders.remove(holder)
if (holders.isEmpty()) {
Log.d(TAG, "Holders empty, release EGL Base")
eglBaseWrapper?.releaseEglBase()
eglBaseWrapper = null
}
}
@JvmStatic
fun replaceHolder(currentHolder: Any, newHolder: Any) {
if (currentHolder == newHolder) {
return
}
Log.d(TAG, "Replace holder $currentHolder with $newHolder")
holders += newHolder
holders.remove(currentHolder)
}
@JvmStatic
fun forceRelease() {
eglBaseWrapper?.releaseEglBase()
eglBaseWrapper = null
holders.clear()
}
}
} }

View file

@ -118,21 +118,6 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor {
} }
} }
@Override
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
Log.i(tag, "handleCallConcluded():");
if (remotePeer == null) {
return currentState;
}
Log.i(tag, "delete remotePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode());
return currentState.builder()
.changeCallInfoState()
.removeRemotePeer(remotePeer)
.build();
}
@Override @Override
protected @NonNull WebRtcServiceState handleReceivedOfferWhileActive(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { protected @NonNull WebRtcServiceState handleReceivedOfferWhileActive(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
RemotePeer activePeer = currentState.getCallInfoState().requireActivePeer(); RemotePeer activePeer = currentState.getCallInfoState().requireActivePeer();

View file

@ -105,9 +105,4 @@ public class ConnectedCallActionProcessor extends DeviceAwareActionProcessor {
protected @NonNull WebRtcServiceState handleReceivedOfferWhileActive(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { protected @NonNull WebRtcServiceState handleReceivedOfferWhileActive(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
return activeCallDelegate.handleReceivedOfferWhileActive(currentState, remotePeer); return activeCallDelegate.handleReceivedOfferWhileActive(currentState, remotePeer);
} }
@Override
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
return activeCallDelegate.handleCallConcluded(currentState, remotePeer);
}
} }

View file

@ -1,60 +0,0 @@
package org.thoughtcrime.securesms.service.webrtc;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
/**
* Handles disconnecting state actions. This primairly entails dealing with final
* clean up in the call concluded action, but also allows for transitioning into idle/setup
* via beginning an outgoing or incoming call.
*/
public class DisconnectingCallActionProcessor extends WebRtcActionProcessor {
private static final String TAG = Log.tag(DisconnectingCallActionProcessor.class);
public DisconnectingCallActionProcessor(@NonNull WebRtcInteractor webRtcInteractor) {
super(webRtcInteractor, TAG);
}
@Override
protected @NonNull WebRtcServiceState handleStartIncomingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
Log.i(TAG, "handleStartIncomingCall():");
currentState = currentState.builder()
.actionProcessor(new IdleActionProcessor(webRtcInteractor))
.build();
return currentState.getActionProcessor().handleStartIncomingCall(currentState, remotePeer);
}
@Override
protected @NonNull WebRtcServiceState handleOutgoingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer, @NonNull OfferMessage.Type offerType) {
Log.i(TAG, "handleOutgoingCall():");
currentState = currentState.builder()
.actionProcessor(new IdleActionProcessor(webRtcInteractor))
.build();
return currentState.getActionProcessor().handleOutgoingCall(currentState, remotePeer, offerType);
}
@Override
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
Log.i(TAG, "handleCallConcluded():");
WebRtcServiceStateBuilder builder = currentState.builder()
.actionProcessor(new IdleActionProcessor(webRtcInteractor));
if (remotePeer != null) {
Log.i(TAG, "delete remotePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode());
builder.changeCallInfoState()
.removeRemotePeer(remotePeer)
.commit();
}
return builder.build();
}
}

View file

@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.ringrtc.RemotePeer;
@ -60,6 +61,7 @@ class GroupNetworkUnavailableActionProcessor extends WebRtcActionProcessor {
Log.i(TAG, "handleCancelPreJoinCall():"); Log.i(TAG, "handleCancelPreJoinCall():");
WebRtcVideoUtil.deinitializeVideo(currentState); WebRtcVideoUtil.deinitializeVideo(currentState);
EglBaseWrapper.releaseEglBase(RemotePeer.GROUP_CALL_ID.longValue());
return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor)); return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor));
} }

View file

@ -9,6 +9,7 @@ import org.signal.ringrtc.CallException;
import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.GroupCall;
import org.signal.ringrtc.PeekInfo; import org.signal.ringrtc.PeekInfo;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.events.CallParticipant;
import org.thoughtcrime.securesms.events.CallParticipantId; import org.thoughtcrime.securesms.events.CallParticipantId;
import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.events.WebRtcViewModel;
@ -78,6 +79,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
} }
WebRtcVideoUtil.deinitializeVideo(currentState); WebRtcVideoUtil.deinitializeVideo(currentState);
EglBaseWrapper.releaseEglBase(RemotePeer.GROUP_CALL_ID.longValue());
return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor)); return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor));
} }

View file

@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallManager; import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.GroupId;
@ -34,7 +35,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
protected @NonNull WebRtcServiceState handleStartIncomingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { protected @NonNull WebRtcServiceState handleStartIncomingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
Log.i(TAG, "handleStartIncomingCall():"); Log.i(TAG, "handleStartIncomingCall():");
currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState); currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState, remotePeer.getCallId().longValue());
return beginCallDelegate.handleStartIncomingCall(currentState, remotePeer); return beginCallDelegate.handleStartIncomingCall(currentState, remotePeer);
} }
@ -51,7 +52,7 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
return currentState; return currentState;
} }
currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState); currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState, EglBaseWrapper.OUTGOING_PLACEHOLDER);
return beginCallDelegate.handleOutgoingCall(currentState, remotePeer, offerType); return beginCallDelegate.handleOutgoingCall(currentState, remotePeer, offerType);
} }
@ -63,7 +64,11 @@ public class IdleActionProcessor extends WebRtcActionProcessor {
WebRtcActionProcessor processor = isGroupCall ? new GroupPreJoinActionProcessor(webRtcInteractor) WebRtcActionProcessor processor = isGroupCall ? new GroupPreJoinActionProcessor(webRtcInteractor)
: new PreJoinActionProcessor(webRtcInteractor); : new PreJoinActionProcessor(webRtcInteractor);
currentState = WebRtcVideoUtil.initializeVanityCamera(WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState)); currentState = WebRtcVideoUtil.initializeVanityCamera(WebRtcVideoUtil.initializeVideo(context,
webRtcInteractor.getCameraEventListener(),
currentState,
isGroupCall ? RemotePeer.GROUP_CALL_ID.longValue()
: EglBaseWrapper.OUTGOING_PLACEHOLDER));
currentState = currentState.builder() currentState = currentState.builder()
.actionProcessor(processor) .actionProcessor(processor)

View file

@ -204,11 +204,6 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
return activeCallDelegate.handleSetupFailure(currentState, callId); return activeCallDelegate.handleSetupFailure(currentState, callId);
} }
@Override
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
return activeCallDelegate.handleCallConcluded(currentState, remotePeer);
}
@Override @Override
public @NonNull WebRtcServiceState handleCallConnected(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { public @NonNull WebRtcServiceState handleCallConnected(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
return callSetupDelegate.handleCallConnected(currentState, remotePeer); return callSetupDelegate.handleCallConnected(currentState, remotePeer);

View file

@ -9,6 +9,7 @@ import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallManager; import org.signal.ringrtc.CallManager;
import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@ -105,7 +106,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
DatabaseFactory.getGroupCallRingDatabase(context).insertGroupRing(ringId, System.currentTimeMillis(), ringUpdate); DatabaseFactory.getGroupCallRingDatabase(context).insertGroupRing(ringId, System.currentTimeMillis(), ringUpdate);
currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState); currentState = WebRtcVideoUtil.initializeVideo(context, webRtcInteractor.getCameraEventListener(), currentState, RemotePeer.GROUP_CALL_ID.longValue());
webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_RINGING, remotePeerGroup); webRtcInteractor.setCallInProgressNotification(TYPE_INCOMING_RINGING, remotePeerGroup);
webRtcInteractor.updatePhoneState(LockManager.PhoneState.INTERACTIVE); webRtcInteractor.updatePhoneState(LockManager.PhoneState.INTERACTIVE);
@ -240,10 +241,12 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE); webRtcInteractor.updatePhoneState(LockManager.PhoneState.IDLE);
webRtcInteractor.stopForegroundService(); webRtcInteractor.stopForegroundService();
return WebRtcVideoUtil.deinitializeVideo(currentState) currentState = WebRtcVideoUtil.deinitializeVideo(currentState);
.builder() EglBaseWrapper.releaseEglBase(RemotePeer.GROUP_CALL_ID.longValue());
.actionProcessor(new IdleActionProcessor(webRtcInteractor))
.terminate(RemotePeer.GROUP_CALL_ID) return currentState.builder()
.build(); .actionProcessor(new IdleActionProcessor(webRtcInteractor))
.terminate(RemotePeer.GROUP_CALL_ID)
.build();
} }
} }

View file

@ -9,6 +9,7 @@ import org.signal.core.util.logging.Log;
import org.signal.ringrtc.CallException; import org.signal.ringrtc.CallException;
import org.signal.ringrtc.CallId; import org.signal.ringrtc.CallId;
import org.signal.ringrtc.CallManager; import org.signal.ringrtc.CallManager;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.events.CallParticipant; import org.thoughtcrime.securesms.events.CallParticipant;
@ -76,6 +77,8 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, Recipient.resolved(remotePeer.getId()), DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(remotePeer.getId())); RecipientUtil.setAndSendUniversalExpireTimerIfNecessary(context, Recipient.resolved(remotePeer.getId()), DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(remotePeer.getId()));
DatabaseFactory.getSmsDatabase(context).insertOutgoingCall(remotePeer.getId(), isVideoCall); DatabaseFactory.getSmsDatabase(context).insertOutgoingCall(remotePeer.getId(), isVideoCall);
EglBaseWrapper.replaceHolder(EglBaseWrapper.OUTGOING_PLACEHOLDER, remotePeer.getCallId().longValue());
webRtcInteractor.retrieveTurnServers(remotePeer); webRtcInteractor.retrieveTurnServers(remotePeer);
return builder.changeCallSetupState(remotePeer.getCallId()) return builder.changeCallSetupState(remotePeer.getCallId())
@ -210,11 +213,6 @@ public class OutgoingCallActionProcessor extends DeviceAwareActionProcessor {
return activeCallDelegate.handleSetupFailure(currentState, callId); return activeCallDelegate.handleSetupFailure(currentState, callId);
} }
@Override
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
return activeCallDelegate.handleCallConcluded(currentState, remotePeer);
}
@Override @Override
public @NonNull WebRtcServiceState handleCallConnected(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { public @NonNull WebRtcServiceState handleCallConnected(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
return callSetupDelegate.handleCallConnected(currentState, remotePeer); return callSetupDelegate.handleCallConnected(currentState, remotePeer);

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.service.webrtc;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.events.WebRtcViewModel; import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.ringrtc.RemotePeer; import org.thoughtcrime.securesms.ringrtc.RemotePeer;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
@ -28,6 +29,7 @@ public class PreJoinActionProcessor extends DeviceAwareActionProcessor {
Log.i(TAG, "handleCancelPreJoinCall():"); Log.i(TAG, "handleCancelPreJoinCall():");
WebRtcVideoUtil.deinitializeVideo(currentState); WebRtcVideoUtil.deinitializeVideo(currentState);
EglBaseWrapper.releaseEglBase(EglBaseWrapper.OUTGOING_PLACEHOLDER);
return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor)); return new WebRtcServiceState(new IdleActionProcessor(webRtcInteractor));
} }
@ -35,6 +37,7 @@ public class PreJoinActionProcessor extends DeviceAwareActionProcessor {
protected @NonNull WebRtcServiceState handleStartIncomingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) { protected @NonNull WebRtcServiceState handleStartIncomingCall(@NonNull WebRtcServiceState currentState, @NonNull RemotePeer remotePeer) {
Log.i(TAG, "handleStartIncomingCall():"); Log.i(TAG, "handleStartIncomingCall():");
EglBaseWrapper.replaceHolder(EglBaseWrapper.OUTGOING_PLACEHOLDER, remotePeer.getCallId().longValue());
currentState = WebRtcVideoUtil.reinitializeCamera(context, webRtcInteractor.getCameraEventListener(), currentState) currentState = WebRtcVideoUtil.reinitializeCamera(context, webRtcInteractor.getCameraEventListener(), currentState)
.builder() .builder()
.changeCallInfoState() .changeCallInfoState()

View file

@ -16,6 +16,7 @@ import org.signal.ringrtc.CallManager.RingUpdate;
import org.signal.ringrtc.GroupCall; import org.signal.ringrtc.GroupCall;
import org.thoughtcrime.securesms.components.sensors.Orientation; import org.thoughtcrime.securesms.components.sensors.Orientation;
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil; import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -295,9 +296,21 @@ public abstract class WebRtcActionProcessor {
return currentState; return currentState;
} }
protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) { final protected @NonNull WebRtcServiceState handleCallConcluded(@NonNull WebRtcServiceState currentState, @Nullable RemotePeer remotePeer) {
Log.i(tag, "handleCallConcluded not processed"); Log.i(tag, "handleCallConcluded():");
return currentState;
if (remotePeer == null) {
return currentState;
}
Log.i(tag, "delete remotePeer callId: " + remotePeer.getCallId() + " key: " + remotePeer.hashCode());
EglBaseWrapper.releaseEglBase(remotePeer.getCallId().longValue());
return currentState.builder()
.changeCallInfoState()
.removeRemotePeer(remotePeer)
.build();
} }
protected @NonNull WebRtcServiceState handleRemoteVideoEnable(@NonNull WebRtcServiceState currentState, boolean enable) { protected @NonNull WebRtcServiceState handleRemoteVideoEnable(@NonNull WebRtcServiceState currentState, boolean enable) {
@ -558,6 +571,8 @@ public abstract class WebRtcActionProcessor {
Log.w(tag, "Unable to reset call manager: ", e); Log.w(tag, "Unable to reset call manager: ", e);
} }
EglBaseWrapper.forceRelease();
currentState = builder.changeCallInfoState().clearPeerMap().build(); currentState = builder.changeCallInfoState().clearPeerMap().build();
return terminate(currentState, currentState.getCallInfoState().getActivePeer()); return terminate(currentState, currentState.getCallInfoState().getActivePeer());
} }
@ -596,7 +611,7 @@ public abstract class WebRtcActionProcessor {
.commit() .commit()
.changeLocalDeviceState() .changeLocalDeviceState()
.commit() .commit()
.actionProcessor(currentState.getCallInfoState().getCallState() == WebRtcViewModel.State.CALL_DISCONNECTED ? new DisconnectingCallActionProcessor(webRtcInteractor) : new IdleActionProcessor(webRtcInteractor)) .actionProcessor(new IdleActionProcessor(webRtcInteractor))
.terminate(remotePeer.getCallId()) .terminate(remotePeer.getCallId())
.build(); .build();
} }
@ -748,6 +763,7 @@ public abstract class WebRtcActionProcessor {
if (terminateVideo) { if (terminateVideo) {
WebRtcVideoUtil.deinitializeVideo(currentState); WebRtcVideoUtil.deinitializeVideo(currentState);
EglBaseWrapper.releaseEglBase(RemotePeer.GROUP_CALL_ID.longValue());
} }
GroupCallSafetyNumberChangeNotificationUtil.cancelNotification(context, currentState.getCallInfoState().getCallRecipient()); GroupCallSafetyNumberChangeNotificationUtil.cancelNotification(context, currentState.getCallInfoState().getCallRecipient());

View file

@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.ringrtc.CameraState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder; import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
import org.webrtc.CapturerObserver; import org.webrtc.CapturerObserver;
import org.webrtc.EglBase;
import org.webrtc.VideoFrame; import org.webrtc.VideoFrame;
import org.webrtc.VideoSink; import org.webrtc.VideoSink;
@ -27,12 +26,13 @@ public final class WebRtcVideoUtil {
public static @NonNull WebRtcServiceState initializeVideo(@NonNull Context context, public static @NonNull WebRtcServiceState initializeVideo(@NonNull Context context,
@NonNull CameraEventListener cameraEventListener, @NonNull CameraEventListener cameraEventListener,
@NonNull WebRtcServiceState currentState) @NonNull WebRtcServiceState currentState,
@NonNull Object eglBaseHolder)
{ {
final WebRtcServiceStateBuilder builder = currentState.builder(); final WebRtcServiceStateBuilder builder = currentState.builder();
ThreadUtil.runOnMainSync(() -> { ThreadUtil.runOnMainSync(() -> {
EglBaseWrapper eglBase = new EglBaseWrapper(EglBase.create()); EglBaseWrapper eglBase = EglBaseWrapper.acquireEglBase(eglBaseHolder);
BroadcastVideoSink localSink = new BroadcastVideoSink(eglBase, BroadcastVideoSink localSink = new BroadcastVideoSink(eglBase,
true, true,
false, false,
@ -89,8 +89,6 @@ public final class WebRtcVideoUtil {
camera.dispose(); camera.dispose();
} }
currentState.getVideoState().getLockableEglBase().releaseEglBase();
return currentState.builder() return currentState.builder()
.changeVideoState() .changeVideoState()
.eglBase(null) .eglBase(null)