diff --git a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java index 128984dd9c..56ae7fa1c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java @@ -71,6 +71,7 @@ import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.util.EllapsedTimeFormatter; import org.thoughtcrime.securesms.util.FullscreenHelper; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.thoughtcrime.securesms.util.ThrottledDebouncer; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.livedata.LiveDataUtil; import org.thoughtcrime.securesms.webrtc.CallParticipantsViewState; @@ -79,6 +80,7 @@ import org.whispersystems.signalservice.api.messages.calls.HangupMessage; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static org.thoughtcrime.securesms.components.sensors.Orientation.PORTRAIT_BOTTOM_EDGE; @@ -104,6 +106,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan private boolean enableVideoIfAvailable; private androidx.window.WindowManager windowManager; private WindowLayoutInfoConsumer windowLayoutInfoConsumer; + private ThrottledDebouncer requestNewSizesThrottle; @Override protected void attachBaseContext(@NonNull Context newBase) { @@ -143,6 +146,8 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan windowLayoutInfoConsumer = new WindowLayoutInfoConsumer(); windowManager.registerLayoutChangeCallback(SignalExecutors.BOUNDED, windowLayoutInfoConsumer); + + requestNewSizesThrottle = new ThrottledDebouncer(TimeUnit.SECONDS.toMillis(1)); } @Override @@ -187,6 +192,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan if (!isInPipMode() || isFinishing()) { EventBus.getDefault().unregister(this); + requestNewSizesThrottle.clear(); } if (!viewModel.isCallStarting()) { @@ -297,7 +303,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan CallParticipantsState state = viewModel.getCallParticipantsState().getValue(); if (state != null) { if (state.needsNewRequestSizes()) { - ApplicationDependencies.getSignalCallManager().updateRenderedResolutions(); + requestNewSizesThrottle.publish(() -> ApplicationDependencies.getSignalCallManager().updateRenderedResolutions()); } } }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java index 757094c667..06f5a06266 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java @@ -3,12 +3,11 @@ package org.thoughtcrime.securesms.components.webrtc; import android.graphics.Point; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import org.webrtc.EglBase; import org.webrtc.VideoFrame; import org.webrtc.VideoSink; +import java.util.Objects; import java.util.WeakHashMap; /** @@ -25,11 +24,11 @@ public class BroadcastVideoSink implements VideoSink { private final EglBaseWrapper eglBase; private final WeakHashMap sinks; private final WeakHashMap requestingSizes; - private boolean dirtySizes; private int deviceOrientationDegrees; private boolean rotateToRightSide; private boolean forceRotate; private boolean rotateWithDevice; + private RequestedSize currentlyRequestedMaxSize; public BroadcastVideoSink() { this(new EglBaseWrapper(null), false, true, 0); @@ -45,7 +44,6 @@ public class BroadcastVideoSink implements VideoSink { this.eglBase = eglBase; this.sinks = new WeakHashMap<>(); this.requestingSizes = new WeakHashMap<>(); - this.dirtySizes = true; this.deviceOrientationDegrees = deviceOrientationDegrees; this.rotateToRightSide = false; this.forceRotate = forceRotate; @@ -120,16 +118,18 @@ public class BroadcastVideoSink implements VideoSink { } void putRequestingSize(@NonNull Object object, @NonNull Point size) { + if (size.x == 0 || size.y == 0) { + return; + } + synchronized (requestingSizes) { requestingSizes.put(object, size); - dirtySizes = true; } } void removeRequestingSize(@NonNull Object object) { synchronized (requestingSizes) { requestingSizes.remove(object); - dirtySizes = true; } } @@ -149,15 +149,15 @@ public class BroadcastVideoSink implements VideoSink { return new RequestedSize(width, height); } - public void newSizeRequested() { - dirtySizes = false; + public void setCurrentlyRequestedMaxSize(@NonNull RequestedSize currentlyRequestedMaxSize) { + this.currentlyRequestedMaxSize = currentlyRequestedMaxSize; } public boolean needsNewRequestingSize() { - return dirtySizes; + return !getMaxRequestingSize().equals(currentlyRequestedMaxSize); } - public static class RequestedSize { + public static final class RequestedSize { private final int width; private final int height; @@ -173,5 +173,19 @@ public class BroadcastVideoSink implements VideoSink { public int getHeight() { return height; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final RequestedSize that = (RequestedSize) o; + return width == that.width && height == that.height; + } + + @Override + public int hashCode() { + return Objects.hash(width, height); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/TextureViewRenderer.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/TextureViewRenderer.java index e2f67ed4a9..cd0c71143b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/TextureViewRenderer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/TextureViewRenderer.java @@ -187,8 +187,6 @@ public class TextureViewRenderer extends TextureView implements TextureView.Surf setMeasuredDimension(size.x, size.y); - Log.d(TAG, "onMeasure(). New size: " + size.x + "x" + size.y); - if (attachedVideoSink != null) { attachedVideoSink.putRequestingSize(this, size); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index e15454101d..589fa6770f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -173,7 +173,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { BroadcastVideoSink.RequestedSize maxSize = videoSink.getMaxRequestingSize(); resolutionRequests.add(new GroupCall.VideoRequest(entry.getKey().getDemuxId(), maxSize.getWidth(), maxSize.getHeight(), null)); - videoSink.newSizeRequested(); + videoSink.setCurrentlyRequestedMaxSize(maxSize); } try { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ThrottledDebouncer.java b/app/src/main/java/org/thoughtcrime/securesms/util/ThrottledDebouncer.java index e384f43269..0951c5d336 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ThrottledDebouncer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ThrottledDebouncer.java @@ -38,12 +38,16 @@ public class ThrottledDebouncer { @MainThread public void publish(Runnable runnable) { + handler.setRunnable(runnable); + if (handler.hasMessages(WHAT)) { - handler.setRunnable(runnable); - } else { - runnable.run(); - handler.sendMessageDelayed(handler.obtainMessage(WHAT), threshold); + return; } + + long sinceLastRun = System.currentTimeMillis() - handler.lastRun; + long delay = Math.max(0, threshold - sinceLastRun); + + handler.sendMessageDelayed(handler.obtainMessage(WHAT), delay); } @MainThread @@ -58,10 +62,12 @@ public class ThrottledDebouncer { } private Runnable runnable; + private long lastRun = 0; @Override public void handleMessage(Message msg) { if (msg.what == WHAT && runnable != null) { + lastRun = System.currentTimeMillis(); runnable.run(); runnable = null; }