package com.quickblox.q_municate.ui.views; import android.content.Context; import android.content.res.TypedArray; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.util.Log; import com.quickblox.q_municate.R; import org.webrtc.RendererCommon; import org.webrtc.VideoRenderer; import org.webrtc.VideoRendererGui; /** * View Class displays webrtc video frames {@link org.webrtc.VideoRenderer.I420Frame I420Frame} * using {@link org.webrtc.VideoRendererGui VideoRendererGui}. * <p> * Note this view * allows to display only 2 video frames on 1 view - for example remote video and * local. If you want to display more than 2 frames on one view * use {@link org.webrtc.VideoRendererGui VideoRendererGui} * to define your own behaviour. * </p> * * <p> * Note that if you put multiple RTCGlVIew view in layout you can manage state only * of the last inflated RTCGlVIew view, because VideoRendererGui works * only with one GLSurfaceView at one time. * </p> * * Use xml attributes "mainCoords" and "secondCoords" to define start point, * width and height in percent of entire view to be held by particular frame in format * [x, y, width, height] as array resource. * Use xml attributes "mainMirror" and "secondMirror" to reflect frame by Y axis. * */ public class RTCGLVideoView extends GLSurfaceView { private static final String TAG = RTCGLVideoView.class.getSimpleName(); private static final int NUMBER_COORDINATES = 4; private VideoRenderer.Callbacks mainRendererCallback; private VideoRenderer.Callbacks localRendererCallback; private final int[] remoteCoords = {0, 0, 100, 100}; private final int[] localCoords = {0, 0, 100, 100}; private boolean mainMirror; private boolean secondMirror; public RTCGLVideoView(Context context) { super(context); Log.i(TAG, "ctor"); init(null); } public RTCGLVideoView(Context c, AttributeSet attr) { super(c, attr); Log.i(TAG, "ctor with attrs"); TypedArray a = c.getTheme().obtainStyledAttributes( attr, R.styleable.RTCGlView, 0, 0); init(a); } public VideoRenderer.Callbacks obtainVideoRenderer(RendererSurface rendererSurface){ Log.i(TAG, "obtainVideoRenderer"); return RendererSurface.MAIN.equals(rendererSurface) ? obtainMainVideoRenderer() : obtainSecondVideoRenderer() ; } private VideoRenderer.Callbacks obtainMainVideoRenderer(){ Log.i(TAG, "obtainMainVideoRenderer"); if (mainRendererCallback == null) { mainRendererCallback = initRenderer(mainMirror, remoteCoords); } return mainRendererCallback; } private VideoRenderer.Callbacks obtainSecondVideoRenderer(){ Log.i(TAG, "obtainSecondVideoRenderer"); if (localRendererCallback == null) { localRendererCallback = initRenderer(secondMirror, localCoords); } return localRendererCallback; } public void updateRenderer(RendererSurface rendererSurface, RendererConfig config){ boolean mainRenderer = RendererSurface.MAIN.equals(rendererSurface); VideoRenderer.Callbacks callbacks = mainRenderer ? mainRendererCallback :localRendererCallback; if (config.coordinates != null) { setViewCoordinates((mainRenderer ? remoteCoords : localCoords), config.coordinates); } setRendererMirror(config.mirror, rendererSurface); int[] viewCoordinates = mainRenderer ? remoteCoords : localCoords; VideoRendererGui.update(callbacks, viewCoordinates[0], viewCoordinates[1], viewCoordinates[2], viewCoordinates[3], RendererCommon.ScalingType.SCALE_ASPECT_FILL, (mainRenderer ? mainMirror : secondMirror)); } public void release(){ if (localRendererCallback != null) { VideoRendererGui.remove(localRendererCallback); } if (mainRendererCallback != null) { VideoRendererGui.remove(mainRendererCallback); } } public void removeLocalRendererCallback(){ if (localRendererCallback != null) { VideoRendererGui.remove(localRendererCallback); localRendererCallback = null; } } public void removeMainRendererCallback(){ if (mainRendererCallback != null) { VideoRendererGui.remove(mainRendererCallback); mainRendererCallback = null; } } private void setRendererMirror(boolean mirror, RendererSurface type){ Log.i(TAG, "setRendererMirror type=" + type + ", value= " + mirror); if (RendererSurface.MAIN.equals(type)){ mainMirror = mirror; } else { secondMirror = mirror; } } private VideoRenderer.Callbacks initRenderer(boolean mirror, int[] viewCoordinates) { return VideoRendererGui.createGuiRenderer(viewCoordinates[0], viewCoordinates[1], viewCoordinates[2], viewCoordinates[3], RendererCommon.ScalingType.SCALE_ASPECT_FILL, mirror); } private void init(TypedArray typedArray) { VideoRendererGui.setView(this, null); if (typedArray != null) { setValuefromResources(typedArray); typedArray.recycle(); } obtainMainVideoRenderer(); } private void setValuefromResources(TypedArray typedArray){ Log.i(TAG, "setValuefromResources"); setRendererMirror(typedArray.getBoolean(R.styleable.RTCGlView_mainMirror, false), RendererSurface.MAIN); setRendererMirror(typedArray.getBoolean(R.styleable.RTCGlView_secondMirror, false), RendererSurface.SECOND); final int remoteValuesId = typedArray.getResourceId(R.styleable.RTCGlView_mainCoords, 0); if (remoteValuesId != 0) { int[] values = getResources().getIntArray(remoteValuesId); setViewCoordinates(remoteCoords, values); } final int localValuesId = typedArray.getResourceId(R.styleable.RTCGlView_secondCoords, 0); if (localValuesId != 0) { int[] values = getResources().getIntArray(localValuesId); setViewCoordinates(localCoords, values); } } private void setViewCoordinates(int[] coordinates, int[] resources){ if (resources.length >= NUMBER_COORDINATES) { System.arraycopy(resources, 0, coordinates, 0, NUMBER_COORDINATES); } } public static class RendererConfig{ public int[] coordinates; public boolean mirror; } public enum RendererSurface { MAIN, SECOND } }