mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-31 05:36:18 +00:00
Upgrade to RingRTC 2.0.3 and implement rounded corners for local pip.
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
package org.thoughtcrime.securesms.components.webrtc;
|
||||
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.view.TextureView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.EglRenderer;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.webrtc.ThreadUtils;
|
||||
import org.webrtc.VideoFrame;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* This class is a modified copy of {@link org.webrtc.SurfaceViewRenderer} designed to work with a
|
||||
* {@link SurfaceTexture} to facilitate easier animation, rounding, elevation, etc.
|
||||
*/
|
||||
public class SurfaceTextureEglRenderer extends EglRenderer implements TextureView.SurfaceTextureListener {
|
||||
|
||||
private static final String TAG = Log.tag(SurfaceTextureEglRenderer.class);
|
||||
|
||||
private final Object layoutLock = new Object();
|
||||
|
||||
private RendererCommon.RendererEvents rendererEvents;
|
||||
private boolean isFirstFrameRendered;
|
||||
private boolean isRenderingPaused;
|
||||
private int rotatedFrameWidth;
|
||||
private int rotatedFrameHeight;
|
||||
private int frameRotation;
|
||||
|
||||
public SurfaceTextureEglRenderer(@NonNull String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void init(@Nullable EglBase.Context sharedContext, @Nullable RendererCommon.RendererEvents rendererEvents, @NonNull int[] configAttributes, @NonNull RendererCommon.GlDrawer drawer) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
this.rendererEvents = rendererEvents;
|
||||
synchronized (this.layoutLock) {
|
||||
this.isFirstFrameRendered = false;
|
||||
this.rotatedFrameWidth = 0;
|
||||
this.rotatedFrameHeight = 0;
|
||||
this.frameRotation = 0;
|
||||
}
|
||||
|
||||
super.init(sharedContext, configAttributes, drawer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(@Nullable EglBase.Context sharedContext, @NonNull int[] configAttributes, @NonNull RendererCommon.GlDrawer drawer) {
|
||||
this.init(sharedContext, null, configAttributes, drawer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFpsReduction(float fps) {
|
||||
synchronized(this.layoutLock) {
|
||||
this.isRenderingPaused = fps == 0.0F;
|
||||
}
|
||||
|
||||
super.setFpsReduction(fps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableFpsReduction() {
|
||||
synchronized(this.layoutLock) {
|
||||
this.isRenderingPaused = false;
|
||||
}
|
||||
|
||||
super.disableFpsReduction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pauseVideo() {
|
||||
synchronized(this.layoutLock) {
|
||||
this.isRenderingPaused = true;
|
||||
}
|
||||
|
||||
super.pauseVideo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrame(@NonNull VideoFrame frame) {
|
||||
this.updateFrameDimensionsAndReportEvents(frame);
|
||||
super.onFrame(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
createEglSurface(surface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
Log.d(TAG, "onSurfaceTextureSizeChanged: size: " + width + "x" + height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
CountDownLatch completionLatch = new CountDownLatch(1);
|
||||
|
||||
releaseEglSurface(completionLatch::countDown);
|
||||
ThreadUtils.awaitUninterruptibly(completionLatch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
}
|
||||
|
||||
private void updateFrameDimensionsAndReportEvents(VideoFrame frame) {
|
||||
synchronized(this.layoutLock) {
|
||||
if (!this.isRenderingPaused) {
|
||||
if (!this.isFirstFrameRendered) {
|
||||
this.isFirstFrameRendered = true;
|
||||
Log.d(TAG, "Reporting first rendered frame.");
|
||||
if (this.rendererEvents != null) {
|
||||
this.rendererEvents.onFirstFrameRendered();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.rotatedFrameWidth != frame.getRotatedWidth() || this.rotatedFrameHeight != frame.getRotatedHeight() || this.frameRotation != frame.getRotation()) {
|
||||
Log.d(TAG, "Reporting frame resolution changed to " + frame.getBuffer().getWidth() + "x" + frame.getBuffer().getHeight() + " with rotation " + frame.getRotation());
|
||||
if (this.rendererEvents != null) {
|
||||
this.rendererEvents.onFrameResolutionChanged(frame.getBuffer().getWidth(), frame.getBuffer().getHeight(), frame.getRotation());
|
||||
}
|
||||
|
||||
this.rotatedFrameWidth = frame.getRotatedWidth();
|
||||
this.rotatedFrameHeight = frame.getRotatedHeight();
|
||||
this.frameRotation = frame.getRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
package org.thoughtcrime.securesms.components.webrtc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.TextureView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.webrtc.EglBase;
|
||||
import org.webrtc.EglRenderer;
|
||||
import org.webrtc.GlRectDrawer;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.webrtc.ThreadUtils;
|
||||
import org.webrtc.VideoFrame;
|
||||
import org.webrtc.VideoSink;
|
||||
|
||||
/**
|
||||
* This class is a modified version of {@link org.webrtc.SurfaceViewRenderer} which is based on {@link TextureView}
|
||||
*/
|
||||
public class TextureViewRenderer extends TextureView implements TextureView.SurfaceTextureListener, VideoSink, RendererCommon.RendererEvents {
|
||||
|
||||
private static final String TAG = Log.tag(TextureViewRenderer.class);
|
||||
|
||||
private final SurfaceTextureEglRenderer eglRenderer;
|
||||
private final RendererCommon.VideoLayoutMeasure videoLayoutMeasure = new RendererCommon.VideoLayoutMeasure();
|
||||
|
||||
private RendererCommon.RendererEvents rendererEvents;
|
||||
private int rotatedFrameWidth;
|
||||
private int rotatedFrameHeight;
|
||||
private boolean enableFixedSize;
|
||||
private int surfaceWidth;
|
||||
private int surfaceHeight;
|
||||
|
||||
public TextureViewRenderer(@NonNull Context context) {
|
||||
super(context);
|
||||
this.eglRenderer = new SurfaceTextureEglRenderer(getResourceName());
|
||||
this.setSurfaceTextureListener(this);
|
||||
}
|
||||
|
||||
public TextureViewRenderer(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.eglRenderer = new SurfaceTextureEglRenderer(getResourceName());
|
||||
this.setSurfaceTextureListener(this);
|
||||
}
|
||||
|
||||
public void init(@NonNull EglBase.Context sharedContext, @NonNull RendererCommon.RendererEvents rendererEvents) {
|
||||
this.init(sharedContext, rendererEvents, EglBase.CONFIG_PLAIN, new GlRectDrawer());
|
||||
}
|
||||
|
||||
public void init(@NonNull EglBase.Context sharedContext, @NonNull RendererCommon.RendererEvents rendererEvents, @NonNull int[] configAttributes, @NonNull RendererCommon.GlDrawer drawer) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
this.rendererEvents = rendererEvents;
|
||||
this.rotatedFrameWidth = 0;
|
||||
this.rotatedFrameHeight = 0;
|
||||
|
||||
this.eglRenderer.init(sharedContext, this, configAttributes, drawer);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
eglRenderer.release();
|
||||
}
|
||||
|
||||
public void addFrameListener(@NonNull EglRenderer.FrameListener listener, float scale, @NonNull RendererCommon.GlDrawer drawerParam) {
|
||||
eglRenderer.addFrameListener(listener, scale, drawerParam);
|
||||
}
|
||||
|
||||
public void addFrameListener(@NonNull EglRenderer.FrameListener listener, float scale) {
|
||||
eglRenderer.addFrameListener(listener, scale);
|
||||
}
|
||||
|
||||
public void removeFrameListener(@NonNull EglRenderer.FrameListener listener) {
|
||||
eglRenderer.removeFrameListener(listener);
|
||||
}
|
||||
|
||||
public void setEnableHardwareScaler(boolean enabled) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
enableFixedSize = enabled;
|
||||
|
||||
updateSurfaceSize();
|
||||
}
|
||||
|
||||
public void setMirror(boolean mirror) {
|
||||
eglRenderer.setMirror(mirror);
|
||||
}
|
||||
|
||||
public void setScalingType(@NonNull RendererCommon.ScalingType scalingType) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
videoLayoutMeasure.setScalingType(scalingType);
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setScalingType(@NonNull RendererCommon.ScalingType scalingTypeMatchOrientation,
|
||||
@NonNull RendererCommon.ScalingType scalingTypeMismatchOrientation)
|
||||
{
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
videoLayoutMeasure.setScalingType(scalingTypeMatchOrientation, scalingTypeMismatchOrientation);
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setFpsReduction(float fps) {
|
||||
eglRenderer.setFpsReduction(fps);
|
||||
}
|
||||
|
||||
public void disableFpsReduction() {
|
||||
eglRenderer.disableFpsReduction();
|
||||
}
|
||||
|
||||
public void pauseVideo() {
|
||||
eglRenderer.pauseVideo();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthSpec, int heightSpec) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
Point size = videoLayoutMeasure.measure(widthSpec, heightSpec, this.rotatedFrameWidth, this.rotatedFrameHeight);
|
||||
|
||||
setMeasuredDimension(size.x, size.y);
|
||||
|
||||
Log.d(TAG, "onMeasure(). New size: " + size.x + "x" + size.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
eglRenderer.setLayoutAspectRatio((float)(right - left) / (float)(bottom - top));
|
||||
|
||||
updateSurfaceSize();
|
||||
}
|
||||
|
||||
private void updateSurfaceSize() {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
if (!isAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.enableFixedSize && this.rotatedFrameWidth != 0 && this.rotatedFrameHeight != 0 && this.getWidth() != 0 && this.getHeight() != 0) {
|
||||
|
||||
float layoutAspectRatio = (float)this.getWidth() / (float)this.getHeight();
|
||||
float frameAspectRatio = (float)this.rotatedFrameWidth / (float)this.rotatedFrameHeight;
|
||||
|
||||
int drawnFrameWidth;
|
||||
int drawnFrameHeight;
|
||||
|
||||
if (frameAspectRatio > layoutAspectRatio) {
|
||||
drawnFrameWidth = (int)((float)this.rotatedFrameHeight * layoutAspectRatio);
|
||||
drawnFrameHeight = this.rotatedFrameHeight;
|
||||
} else {
|
||||
drawnFrameWidth = this.rotatedFrameWidth;
|
||||
drawnFrameHeight = (int)((float)this.rotatedFrameWidth / layoutAspectRatio);
|
||||
}
|
||||
|
||||
int width = Math.min(this.getWidth(), drawnFrameWidth);
|
||||
int height = Math.min(this.getHeight(), drawnFrameHeight);
|
||||
|
||||
Log.d(TAG, "updateSurfaceSize. Layout size: " + this.getWidth() + "x" + this.getHeight() + ", frame size: " + this.rotatedFrameWidth + "x" + this.rotatedFrameHeight + ", requested surface size: " + width + "x" + height + ", old surface size: " + this.surfaceWidth + "x" + this.surfaceHeight);
|
||||
|
||||
if (width != this.surfaceWidth || height != this.surfaceHeight) {
|
||||
this.surfaceWidth = width;
|
||||
this.surfaceHeight = height;
|
||||
getSurfaceTexture().setDefaultBufferSize(width, height);
|
||||
}
|
||||
} else {
|
||||
this.surfaceWidth = this.surfaceHeight = 0;
|
||||
this.getSurfaceTexture().setDefaultBufferSize(getMeasuredWidth(), getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFirstFrameRendered() {
|
||||
if (this.rendererEvents != null) {
|
||||
this.rendererEvents.onFirstFrameRendered();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
|
||||
if (this.rendererEvents != null) {
|
||||
this.rendererEvents.onFrameResolutionChanged(videoWidth, videoHeight, rotation);
|
||||
}
|
||||
|
||||
int rotatedWidth = rotation != 0 && rotation != 180 ? videoHeight : videoWidth;
|
||||
int rotatedHeight = rotation != 0 && rotation != 180 ? videoWidth : videoHeight;
|
||||
this.postOrRun(() -> {
|
||||
this.rotatedFrameWidth = rotatedWidth;
|
||||
this.rotatedFrameHeight = rotatedHeight;
|
||||
this.updateSurfaceSize();
|
||||
this.requestLayout();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrame(VideoFrame videoFrame) {
|
||||
eglRenderer.onFrame(videoFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
ThreadUtils.checkIsOnMainThread();
|
||||
|
||||
surfaceWidth = 0;
|
||||
surfaceHeight = 0;
|
||||
|
||||
updateSurfaceSize();
|
||||
|
||||
eglRenderer.onSurfaceTextureAvailable(surface, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
||||
eglRenderer.onSurfaceTextureSizeChanged(surface, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
return eglRenderer.onSurfaceTextureDestroyed(surface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
||||
}
|
||||
|
||||
private String getResourceName() {
|
||||
try {
|
||||
return this.getResources().getResourceEntryName(this.getId());
|
||||
} catch (Resources.NotFoundException var2) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void clearImage() {
|
||||
this.eglRenderer.clearImage();
|
||||
}
|
||||
|
||||
private void postOrRun(Runnable r) {
|
||||
if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
this.post(r);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import org.thoughtcrime.securesms.ringrtc.CameraState;
|
||||
import org.thoughtcrime.securesms.util.AvatarUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.webrtc.SurfaceViewRenderer;
|
||||
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
|
||||
|
||||
public class WebRtcCallView extends FrameLayout {
|
||||
@@ -46,7 +45,7 @@ public class WebRtcCallView extends FrameLayout {
|
||||
|
||||
public static final int FADE_OUT_DELAY = 5000;
|
||||
|
||||
private SurfaceViewRenderer localRenderer;
|
||||
private TextureViewRenderer localRenderer;
|
||||
private Group ongoingCallButtons;
|
||||
private Group incomingCallButtons;
|
||||
private Group answerWithVoiceGroup;
|
||||
@@ -202,7 +201,7 @@ public class WebRtcCallView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocalRenderer(@Nullable SurfaceViewRenderer surfaceViewRenderer) {
|
||||
public void setLocalRenderer(@Nullable TextureViewRenderer surfaceViewRenderer) {
|
||||
if (localRenderer == surfaceViewRenderer) {
|
||||
return;
|
||||
}
|
||||
@@ -218,12 +217,11 @@ public class WebRtcCallView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setRemoteRenderer(@Nullable SurfaceViewRenderer surfaceViewRenderer) {
|
||||
setRenderer(remoteRenderContainer, surfaceViewRenderer);
|
||||
public void setRemoteRenderer(@Nullable TextureViewRenderer remoteRenderer) {
|
||||
setRenderer(remoteRenderContainer, remoteRenderer);
|
||||
}
|
||||
|
||||
public void setLocalRenderState(WebRtcLocalRenderState localRenderState) {
|
||||
boolean enableZOverlay = localRenderState == WebRtcLocalRenderState.SMALL;
|
||||
|
||||
videoToggle.setChecked(localRenderState != WebRtcLocalRenderState.GONE, false);
|
||||
|
||||
@@ -254,10 +252,6 @@ public class WebRtcCallView extends FrameLayout {
|
||||
setRenderer(smallLocalRenderContainer, localRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
if (localRenderer != null) {
|
||||
localRenderer.setZOrderMediaOverlay(enableZOverlay);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCameraDirection(@NonNull CameraState.Direction cameraDirection) {
|
||||
|
||||
Reference in New Issue
Block a user