de.lespace.apprtc.CallActivity.java Source code

Java tutorial

Introduction

Here is the source code for de.lespace.apprtc.CallActivity.java

Source

/*
 *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

package de.lespace.apprtc;

import org.webrtc.EglBase;
import org.webrtc.RendererCommon;
import org.webrtc.RendererCommon.ScalingType;
import org.webrtc.StatsReport;
import org.webrtc.SurfaceViewRenderer;

import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.widget.Toast;

/**
 * Activity for peer connection call setup, call waiting
 * and call view.
 */
public class CallActivity extends RTCConnection implements CallFragment.OnCallEvents
// AppRTCClient.SignalingEvents,
//    PeerConnectionClient.PeerConnectionEvents,
//     WebSocketChannelClient.WebSocketChannelEvents
{

    private static final String TAG = "CallActivity";

    // Local preview screen position before call is connected.
    private static final int LOCAL_X_CONNECTING = 0;
    private static final int LOCAL_Y_CONNECTING = 0;
    private static final int LOCAL_WIDTH_CONNECTING = 100;
    private static final int LOCAL_HEIGHT_CONNECTING = 100;

    // Local preview screen position after call is connected.
    private static final int LOCAL_X_CONNECTED = 72;
    private static final int LOCAL_Y_CONNECTED = 72;
    private static final int LOCAL_WIDTH_CONNECTED = 25;
    private static final int LOCAL_HEIGHT_CONNECTED = 25;
    // Remote video screen position
    private static final int REMOTE_X = 0;
    private static final int REMOTE_Y = 0;
    private static final int REMOTE_WIDTH = 100;
    private static final int REMOTE_HEIGHT = 100;

    // Screen video screen position
    private static final int SCREEN_X = 0;
    private static final int SCREEN_Y = 0;
    private static final int SCREEN_WIDTH = 100;
    private static final int SCREEN_HEIGHT = 100;

    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 0;
    // private AppRTCClient appRtcClient;
    private ScalingType scalingType;
    private Toast logToast;
    private boolean commandLineRun;
    private boolean sendDisconnectToPeer = true;
    private long callStartedTimeMs = 0;
    // Controls
    public CallFragment callFragment;
    public HudFragment hudFragment;
    public EglBase rootEglBase;
    public PercentFrameLayout localRenderLayout;
    public PercentFrameLayout remoteRenderLayout;
    public PercentFrameLayout screenRenderLayout;

    public SurfaceViewRenderer localRender;
    public SurfaceViewRenderer remoteRender;
    public SurfaceViewRenderer screenRender;
    private GestureDetectorCompat mDetector;
    private static boolean broadcastIsRegistered;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Thread.setDefaultUncaughtExceptionHandler(new UnhandledExceptionHandler(this));

        // Set window styles for fullscreen-window size. Needs to be done before
        // adding content.
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(
                LayoutParams.FLAG_FULLSCREEN | LayoutParams.FLAG_KEEP_SCREEN_ON | LayoutParams.FLAG_DISMISS_KEYGUARD
                        | LayoutParams.FLAG_SHOW_WHEN_LOCKED | LayoutParams.FLAG_TURN_SCREEN_ON);

        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

        setContentView(R.layout.activity_call);

        iceConnected = false;

        scalingType = ScalingType.SCALE_ASPECT_FILL;

        callFragment = new CallFragment();
        hudFragment = new HudFragment();

        // Create UI controls.
        localRender = (SurfaceViewRenderer) findViewById(R.id.local_video_view);
        remoteRender = (SurfaceViewRenderer) findViewById(R.id.remote_video_view);
        screenRender = (SurfaceViewRenderer) findViewById(R.id.remote_screen_view);

        localRenderLayout = (PercentFrameLayout) findViewById(R.id.local_video_layout);
        remoteRenderLayout = (PercentFrameLayout) findViewById(R.id.remote_video_layout);

        screenRenderLayout = (PercentFrameLayout) findViewById(R.id.remote_screen_layout);

        // Show/hide call control fragment on view click.
        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggleCallControlFragmentVisibility();
            }
        };

        localRender.setOnClickListener(listener);
        remoteRender.setOnClickListener(listener);
        screenRender.setOnClickListener(listener); //screensharing

        // Create video renderers.
        rootEglBase = EglBase.create();
        localRender.init(rootEglBase.getEglBaseContext(), null);
        remoteRender.init(rootEglBase.getEglBaseContext(), null);
        screenRender.init(rootEglBase.getEglBaseContext(), null);
        localRender.setZOrderMediaOverlay(true);
        screenRender.setZOrderMediaOverlay(true);
        updateVideoView();

        setResult(RESULT_CANCELED);

        if (!broadcastIsRegistered) {
            registerReceiver(broadcast_reciever, new IntentFilter("finish_CallActivity"));
            registerReceiver(broadcast_reciever, new IntentFilter("finish_screensharing"));
            broadcastIsRegistered = true;
        }

        callFragment = new CallFragment();
        hudFragment = new HudFragment();
        // Send intent arguments to fragments.
        callFragment.setArguments(getIntent().getExtras());
        hudFragment.setArguments(getIntent().getExtras());

        // Activate call and HUD fragments and start the call.
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(R.id.call_fragment_container, callFragment);
        ft.add(R.id.hud_fragment_container, hudFragment);
        ft.commit();

        // For command line execution run connection for <runTimeMs> and exit.
        if (commandLineRun && runTimeMs > 0) {
            (new Handler()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    disconnect(false);
                }
            }, runTimeMs);
        }

        // Create and audio manager that will take care of audio routing,
        // audio modes, audio device enumeration etc.
        audioManager = AppRTCAudioManager.create(this, new Runnable() {
            // This method will be called each time the audio state (number and
            // type of devices) has been changed.
            @Override
            public void run() {
                onAudioManagerChangedState();
            }
        });

        // Store existing audio settings and change audio mode to
        // MODE_IN_COMMUNICATION for best possible VoIP performance.
        Log.d(TAG, "Initializing the audio manager...");
        audioManager.init();

        peerConnectionClient = PeerConnectionClient.getInstance(true);
        peerConnectionClient.createPeerConnectionFactory(CallActivity.this, peerConnectionParameters, this);

        peerConnectionClient.createPeerConnection(rootEglBase.getEglBaseContext(), localRender, remoteRender,
                screenRender, roomConnectionParameters.initiator);

        logAndToast("Creating OFFER...");
        // Create offer. Offer SDP will be sent to answering client in
        // PeerConnectionEvents.onLocalDescription event.
        peerConnectionClient.createOffer();
    }

    private void onAudioManagerChangedState() {
        // TODO(henrika): disable video if AppRTCAudioManager.AudioDevice.EARPIECE
        // is active.
    }

    public void updateVideoView() {

        screenRenderLayout.setPosition(SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT);
        screenRender.setScalingType(scalingType);
        screenRender.setMirror(false);

        remoteRenderLayout.setPosition(SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT);
        remoteRender.setScalingType(scalingType);
        remoteRender.setMirror(false);

        if (iceConnected) {
            localRenderLayout.setPosition(LOCAL_X_CONNECTED, LOCAL_Y_CONNECTED, LOCAL_WIDTH_CONNECTED,
                    LOCAL_HEIGHT_CONNECTED);
            localRender.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);

        } else {
            localRenderLayout.setPosition(LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING, LOCAL_WIDTH_CONNECTING,
                    LOCAL_HEIGHT_CONNECTING);
            localRender.setScalingType(scalingType);
        }
        localRender.setMirror(true);

        localRender.requestLayout();
        remoteRender.requestLayout();
        screenRender.requestLayout();
    }

    @Override
    public void onPeerConnectionStatsReady(final StatsReport[] reports) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (!isError && iceConnected) {
                    hudFragment.updateEncoderStatistics(reports);
                }
            }
        });
    }

    @Override
    public void onIceConnected() {
        final long delta = System.currentTimeMillis() - callStartedTimeMs;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                logAndToast("ICE connected, delay=" + delta + "ms");
                iceConnected = true;
                callConnected();
            }
        });
    }

    @Override
    public void onCameraSwitch() {
        if (peerConnectionClient != null) {
            boolean renderVideo = !peerConnectionClient.renderVideo;
            peerConnectionClient.setVideoEnabled(renderVideo);
            logAndToast(renderVideo ? "video enabled" : "video disabled");
        }
    }

    @Override
    public void onAudioMute() {

        boolean muted = audioManager.setMicrophoneMute(true);
        logAndToast(muted ? "muted" : "unmuted");
    }

    @Override
    public void onCaptureFormatChange(int width, int height, int framerate) {
        if (peerConnectionClient != null) {
            peerConnectionClient.changeCaptureFormat(width, height, framerate);
        }
    }

    @Override
    public void onVideoScalingSwitch(RendererCommon.ScalingType scalingType) {
        this.scalingType = scalingType;
        updateVideoView();
    }

    @Override
    protected void onDestroy() {

        disconnect(sendDisconnectToPeer);
        if (logToast != null) {
            logToast.cancel();
        }
        activityRunning = false;

        unregisterReceiver(broadcast_reciever);
        broadcastIsRegistered = false;

        rootEglBase.release();
        super.onDestroy();

    }

    // CallFragment.OnCallEvents interface implementation.
    @Override
    public void onCallHangUp() {
        disconnect(true);
    }

    @Override
    public void onChannelError(String description) {
        reportError(description);
    }

    // Should be called from UI thread
    private void callConnected() {
        final long delta = System.currentTimeMillis() - callStartedTimeMs;
        Log.i(TAG, "Call connected: delay=" + delta + "ms");
        if (peerConnectionClient == null || isError) {
            Log.w(TAG, "Call is connected in closed or error state");
            return;
        }
        // Update video view.
        updateVideoView();
        // Enable statistics callback.
        peerConnectionClient.enableStatsEvents(true, STAT_CALLBACK_PERIOD);
    }

    public void disconnect(boolean sendRemoteHangup) {

        if (localRender != null) {
            localRender.release();
            localRender = null;
        }
        if (remoteRender != null) {
            remoteRender.release();
            remoteRender = null;
        }

        if (screenRender != null) {
            screenRender.release();
            screenRender = null;
        }

        if (audioManager != null) {
            audioManager.close();
            audioManager = null;
        }

        if (appRtcClient != null && sendRemoteHangup) {
            appRtcClient.sendDisconnectToPeer(); //send bye message to peer only when initiator
            sendDisconnectToPeer = false;
            // appRtcClient = null;
        }

        //DON'T DO THAT if(appRtcClient != null) appRtcClient = null;

        if (peerConnectionClient != null) {
            peerConnectionClient.close();
            peerConnectionClient = null;
        }

        if (peerConnectionClient2 != null) {
            peerConnectionClient2.close();
            peerConnectionClient2 = null;
        }

        if (activityRunning) {
            activityRunning = false;
            setResult(RESULT_OK); //okey means send stop to client!
            finish();
        }

    }

    // Helper functions.
    public void toggleCallControlFragmentVisibility() {
        if (!iceConnected || !callFragment.isAdded()) {
            return;
        }
        // Show/hide call control fragment
        callControlFragmentVisible = !callControlFragmentVisible;
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        if (callControlFragmentVisible) {
            ft.show(callFragment);
            ft.show(hudFragment);
        } else {
            ft.hide(callFragment);
            ft.hide(hudFragment);
        }
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        ft.commit();
    }

    BroadcastReceiver broadcast_reciever = new BroadcastReceiver() {

        @Override
        public void onReceive(Context arg0, Intent intent) {

            String action = intent.getAction();
            if (action.equals("finish_CallActivity")) {
                sendDisconnectToPeer = false;
                finish();
            }

            if (action.equals("finish_screensharing")) {
                //  http://stackoverflow.com/questions/37385522/how-to-change-surfaceviews-z-order-runtime-in-android
                if (screenRender != null) {
                    //

                    peerConnectionClient2.close();
                    screenRenderLayout.removeView(screenRender);
                    //  screenRender.release();
                    // screenRenderLayout.add(screenRender);
                    screenRenderLayout.addView(screenRender, new ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
                    // screenRender.setVisibility(View.GONE);
                    screenRender.setZOrderMediaOverlay(true);
                    // screenRender.release();
                    //screenRender = null;
                    // screenRender = (SurfaceViewRenderer) findViewById(R.id.remote_screen_view);
                    //  screenRenderLayout = (PercentFrameLayout) findViewById(R.id.remote_screen_layout);
                    //  screenRender.init(rootEglBase.getEglBaseContext(), null);
                    //  screenRender.setZOrderMediaOverlay(true);
                    /*
                    remoteRenderLayout.removeView(remoteRender);
                    localRenderLayout.removeView(localRender);
                    localRender.setVisibility(View.GONE);
                    remoteRender.setVisibility(View.GONE);
                    localRender.setZOrderMediaOverlay(true);
                    remoteRender.setZOrderMediaOverlay(false);*/
                    // localRenderLayout.addView(mLocalRender, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
                    // remoteRenderLayout.addView(mRemoteRender, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
                    // localRender.setVisibility(View.VISIBLE);
                    // remoteRender.setVisibility(View.VISIBLE);
                    // localRender.setZOrderMediaOverlay(true);
                    //  screenRender.setVisibility(View.INVISIBLE);

                    /* if (peerConnectionClient2 != null) {
                        peerConnectionClient2.close();
                        peerConnectionClient2 = null;
                      }*/

                    //   screenRenderLayout.setPosition(SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT);
                    //   screenRender.setScalingType(scalingType);
                    //   screenRender.setMirror(false);
                    //   screenRender.requestLayout();
                    //  updateVideoView();
                }

            }
        }
    };

    @Override
    public void onWebSocketMessage(String message) {

    }

    @Override
    public void onWebSocketClose() {

    }
}