package com.wdkl.ncs.janus.rtc;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.content.Intent;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.projection.MediaProjection;
import android.os.Build;
import android.util.Log;
import android.view.View;


import com.wdkl.ncs.janus.render.ProxyVideoSink;
import com.wdkl.ncs.janus.rtc.observer.CreatePeerConnectionCallback;
import com.wdkl.ncs.janus.util.JanusConstant;

import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Enumerator;
import org.webrtc.CameraEnumerator;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RendererCommon;
import org.webrtc.ScreenCapturerAndroid;
import org.webrtc.SurfaceTextureHelper;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoCapturer;
import org.webrtc.VideoDecoderFactory;
import org.webrtc.VideoEncoderFactory;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import org.webrtc.audio.AudioDeviceModule;
import org.webrtc.audio.JavaAudioDeviceModule;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class WebRTCEngine {
    private static final String TAG = "WebRTCEngine";
    private PeerConnectionFactory factory;
    private EglBase mRootEglBase;
    private MediaStream _localStream;
    private VideoSource videoSource;
    private AudioSource audioSource;
    private AudioTrack _localAudioTrack;
    private VideoCapturer captureAndroid;
    private SurfaceTextureHelper surfaceTextureHelper;

    private ProxyVideoSink localSink;
    private SurfaceViewRenderer localRenderer;

    private static final String VIDEO_TRACK_ID = "ARDAMSv0";
    private static final String AUDIO_TRACK_ID = "ARDAMSa0";
    public static final String VIDEO_CODEC_H264 = "H264";
    public static final String VIDEO_TRACK_TYPE = "video";
    private static final String VIDEO_CODEC_VP8 = "VP8";
    private static final String VIDEO_CODEC_VP9 = "VP9";
    private static final String DTLS_SRTP_KEY_AGREEMENT_CONSTRAINT = "DtlsSrtpKeyAgreement";
    private static final int VIDEO_RESOLUTION_WIDTH = 720;
    private static final int VIDEO_RESOLUTION_HEIGHT = 1280;
    private static final int FPS = 30;
    private String preferredVideoCodec;
    private PeerConnectionParameters peerConnectionParameters;
    private PeerConnectionFactory.Options options = null;

    // 对话实例列表
    private ConcurrentHashMap<BigInteger, Peer> peerMap;
    // 服务器实例列表
    private List<PeerConnection.IceServer> iceServers = new ArrayList<>();

    public boolean mIsAudioOnly;
    private Context mContext;
    private AudioManager audioManager;
    private boolean isSpeakerOn = true;

    private AudioFocusManager audioFocusManager;
    // 是否使用录屏
    private boolean screencaptureEnabled = false;
    private boolean isSwitch = false; // 是否正在切换摄像头

    private ScheduledExecutorService executor;
    private static final WebRTCEngine instance = new WebRTCEngine();
    private WebRTCEngine() {
        // Executor thread is started once in private ctor and is used for all
        // peer connection API calls to ensure new peer connection factory is
        // created on the same thread as previously destroyed factory.
        executor = Executors.newSingleThreadScheduledExecutor();
        peerMap = new ConcurrentHashMap<>();
        // 初始化ice地址
        initIceServer();
    }
    public static WebRTCEngine getInstance() {
        return instance;
    }

    private void initIceServer(){
        PeerConnection.IceServer iceServer;
        if (JanusConstant.STUN_SERVER != null) {
            for (String stunServer : JanusConstant.STUN_SERVER) {
                if (stunServer.contains("|")) {
                    String[] stunParams = stunServer.split("|");
                    iceServer = PeerConnection.IceServer
                            .builder(stunParams[0])
                            .setUsername(stunParams[1])
                            .setPassword(stunParams[2])
                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
                            .createIceServer();
                } else {
                    iceServer = PeerConnection.IceServer
                            .builder(stunServer)
                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
                            .createIceServer();
                }
                iceServers.add(iceServer);
            }
        }
        if (JanusConstant.TURN_SERVER != null){
            for(String turnServer: JanusConstant.TURN_SERVER){
                if (turnServer.contains("|"))
                {
                    String[] turnParams = turnServer.split("|");
                    iceServer = PeerConnection.IceServer
                            .builder(turnParams[0])
                            .setUsername(turnParams[1])
                            .setPassword(turnParams[2])
                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
                            .createIceServer();
                } else {
                    iceServer = PeerConnection.IceServer
                            .builder(turnServer)
                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
                            .createIceServer();
                }
                iceServers.add(iceServer);
            }
        }
    }

    public static class PeerConnectionParameters {
        public final boolean tracing;
        public final int videoWidth;
        public final int videoHeight;
        public final int videoFps;
        public final String videoCodec;
        public final boolean videoCodecHwAcceleration;
        public final int audioStartBitrate;
        public final String audioCodec;
        public final boolean noAudioProcessing;
        public final boolean useOpenSLES;
        public final boolean disableBuiltInAEC;
        public final boolean disableBuiltInAGC;
        public final boolean disableBuiltInNS;

        public PeerConnectionParameters(boolean tracing,
                                        int videoWidth, int videoHeight, int videoFps, String videoCodec,
                                        boolean videoCodecHwAcceleration, int audioStartBitrate, String audioCodec,
                                        boolean noAudioProcessing, boolean useOpenSLES, boolean disableBuiltInAEC,
                                        boolean disableBuiltInAGC, boolean disableBuiltInNS) {
            this.tracing = tracing;
            this.videoWidth = videoWidth;
            this.videoHeight = videoHeight;
            this.videoFps = videoFps;
            this.videoCodec = videoCodec;
            this.videoCodecHwAcceleration = videoCodecHwAcceleration;
            this.audioStartBitrate = audioStartBitrate;
            this.audioCodec = audioCodec;
            this.noAudioProcessing = noAudioProcessing;
            this.useOpenSLES = useOpenSLES;
            this.disableBuiltInAEC = disableBuiltInAEC;
            this.disableBuiltInAGC = disableBuiltInAGC;
            this.disableBuiltInNS = disableBuiltInNS;
        }
    }

    public void setOptions(PeerConnectionFactory.Options options) {
        this.options = options;
    }

    public PeerConnectionFactory createPeerConnectionFactory() {

        // 1. 初始化的方法，必须在开始之前调用
        PeerConnectionFactory.initialize(PeerConnectionFactory
                .InitializationOptions
                .builder(mContext)
                .createInitializationOptions());

        // 2. 设置编解码方式：默认方法
        final VideoEncoderFactory encoderFactory;
        final VideoDecoderFactory decoderFactory;

        encoderFactory = new DefaultVideoEncoderFactory(
                mRootEglBase.getEglBaseContext(),
                true,
                true);
        decoderFactory = new DefaultVideoDecoderFactory(mRootEglBase.getEglBaseContext());
        if (encoderFactory == null || decoderFactory == null){

        }

        // 构造Factory
        AudioDeviceModule audioDeviceModule = JavaAudioDeviceModule.builder(mContext).createAudioDeviceModule();
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        return PeerConnectionFactory.builder()
                .setOptions(options)
                .setAudioDeviceModule(audioDeviceModule)
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .createPeerConnectionFactory();
    }

    private PeerConnectionFactory createPeerConnectionFactory1() {

        final VideoEncoderFactory encoderFactory;
        final VideoDecoderFactory decoderFactory;

        encoderFactory = new DefaultVideoEncoderFactory(
                mRootEglBase.getEglBaseContext(), false /* enableIntelVp8Encoder */, true);
        decoderFactory = new DefaultVideoDecoderFactory(mRootEglBase.getEglBaseContext());

        PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(mContext)
                .setEnableInternalTracer(true)
                .createInitializationOptions());

        PeerConnectionFactory.Builder builder = PeerConnectionFactory.builder()
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory);

        Log.d(TAG,
                "Create peer connection factory. Use video: true");

        // Initialize field trials.
        PeerConnectionFactory.initializeFieldTrials("");

        // Check preferred video codec.
        preferredVideoCodec = VIDEO_CODEC_VP8;
        if (peerConnectionParameters!=null) {
            if (peerConnectionParameters.videoCodec != null) {
                if (peerConnectionParameters.videoCodec.equals(VIDEO_CODEC_VP9)) {
                    preferredVideoCodec = VIDEO_CODEC_VP9;
                } else if (peerConnectionParameters.videoCodec.equals(VIDEO_CODEC_H264)) {
                    preferredVideoCodec = VIDEO_CODEC_H264;
                }
            }
        }
        Log.d(TAG, "Pereferred video codec: " + preferredVideoCodec);

        // Enable/disable OpenSL ES playback.
        if (peerConnectionParameters!=null && !peerConnectionParameters.useOpenSLES) {
            Log.d(TAG, "Disable OpenSL ES audio even if device supports it");
            WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true /* enable */);
        } else {
            Log.d(TAG, "Allow OpenSL ES audio if device supports it");
            WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(false);
        }

        if (peerConnectionParameters!=null && peerConnectionParameters.disableBuiltInAEC) {
            Log.d(TAG, "Disable built-in AEC even if device supports it");
            WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
        } else {
            Log.d(TAG, "Enable built-in AEC if device supports it");
            WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(false);
        }

        if (peerConnectionParameters!=null && peerConnectionParameters.disableBuiltInAGC) {
            Log.d(TAG, "Disable built-in AGC even if device supports it");
            WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(true);
        } else {
            Log.d(TAG, "Enable built-in AGC if device supports it");
            WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(false);
        }

        if (peerConnectionParameters!=null && peerConnectionParameters.disableBuiltInNS) {
            Log.d(TAG, "Disable built-in NS even if device supports it");
            WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(true);
        } else {
            Log.d(TAG, "Enable built-in NS if device supports it");
            WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(false);
        }

        if (options != null) {
            builder.setOptions(options);
            Log.d(TAG, "Factory networkIgnoreMask option: " + options.networkIgnoreMask);
        }
        factory = builder.createPeerConnectionFactory();
        Log.d(TAG, "Peer connection factory created.");
        return factory;
    }

    /**
     * 创建媒体方式
     *
     * @return VideoCapturer
     */
    private VideoCapturer createVideoCapture() {
        if (screencaptureEnabled) {
            return createScreenCapturer();
        }

        return createCameraCapture(new Camera1Enumerator(true));
    }

    private static Intent mediaProjectionPermissionResultData;
    private static int mediaProjectionPermissionResultCode;

    @TargetApi(21)
    private VideoCapturer createScreenCapturer() {
        if (mediaProjectionPermissionResultCode != Activity.RESULT_OK) {
            return null;
        }
        return new ScreenCapturerAndroid(
                mediaProjectionPermissionResultData, new MediaProjection.Callback() {
            @Override
            public void onStop() {
                Log.e(TAG, "User revoked permission to capture the screen.");
            }
        });
    }

    /**
     * 创建相机媒体流
     */
    private VideoCapturer createCameraCapture(CameraEnumerator enumerator) {
        final String[] deviceNames = enumerator.getDeviceNames();
        Log.d(TAG, "createCameraCapture devices: " + deviceNames.length);

        // First, try to find front facing camera
        for (String deviceName : deviceNames) {
            Log.d(TAG, "createCameraCapture device name: " + deviceName);
            if (enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        // Front facing camera not found, try something else
        for (String deviceName : deviceNames) {
            if (!enumerator.isFrontFacing(deviceName)) {
                VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);

                if (videoCapturer != null) {
                    return videoCapturer;
                }
            }
        }

        return null;
    }

    // -----------------------------------约束---------------------------------------------
    // 配置音频参数
    private MediaConstraints createAudioConstraints() {
        MediaConstraints audioConstraints = new MediaConstraints();

        //回声消除
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation2", "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googDAEchoCancellation", "true"));
        //自动增益
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl2", "true"));
        //噪音处理
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression2", "true"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googTypingNoiseDetection", "true"));
        //高音过滤
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAudioMirroring", "false"));
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
        return audioConstraints;
    }

    // -----------------------------------对外方法------------------------------------------
    public void init(boolean mIsAudioOnly, Context mContext) {
        this.mIsAudioOnly = mIsAudioOnly;
        this.mContext = mContext;
        audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);

        if (mRootEglBase == null) {
            mRootEglBase = EglBase.create();
        }
        if (factory == null) {
            factory = createPeerConnectionFactory();
        }
        if (_localStream == null) {
            createLocalStream();
        }
    }

    /**
     * 创建本地流
     */
    public void createLocalStream() {
        _localStream = factory.createLocalMediaStream("ARDAMS");
        // 音频
        audioSource = factory.createAudioSource(createAudioConstraints());
        _localAudioTrack = factory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
        _localStream.addTrack(_localAudioTrack);

        // 视频
        if (!mIsAudioOnly) {
            captureAndroid = createVideoCapture();
            surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", mRootEglBase.getEglBaseContext());
            videoSource = factory.createVideoSource(captureAndroid.isScreencast());

            captureAndroid.initialize(surfaceTextureHelper, mContext, videoSource.getCapturerObserver());
            captureAndroid.startCapture(VIDEO_RESOLUTION_WIDTH, VIDEO_RESOLUTION_HEIGHT, FPS);

            VideoTrack _localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
            _localStream.addTrack(_localVideoTrack);
        }
    }

    /**
     * 开始本地预览
     * @param isOverlay
     * @return
     */
    public View startPreview(boolean isOverlay) {
        if (mRootEglBase == null) {
            return null;
        }
        localRenderer = new SurfaceViewRenderer(mContext);
        localRenderer.init(mRootEglBase.getEglBaseContext(), null);
        localRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
        localRenderer.setMirror(true);
        localRenderer.setZOrderMediaOverlay(isOverlay);

        localSink = new ProxyVideoSink();
        localSink.setTarget(localRenderer);
        if (_localStream.videoTracks.size() > 0) {
            _localStream.videoTracks.get(0).addSink(localSink);
        }
        return localRenderer;
    }

    /**
     * 静音
     * @param enable
     * @return
     */
    public boolean muteAudio(boolean enable) {
        if (_localAudioTrack != null) {
            _localAudioTrack.setEnabled(!enable);
            return true;
        }
        return false;
    }

    /**
     * 结束本地预览
     */
    public void stopPreview() {
        if (localSink != null) {
            localSink.setTarget(null);
            localSink = null;
        }
        if (audioSource != null) {
            audioSource.dispose();
            audioSource = null;
        }
        // 释放摄像头
        if (captureAndroid != null) {
            try {
                captureAndroid.stopCapture();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            captureAndroid.dispose();
            captureAndroid = null;
        }
        // 释放画布
        if (surfaceTextureHelper != null) {
            surfaceTextureHelper.dispose();
            surfaceTextureHelper = null;
        }

        if (videoSource != null) {
            videoSource.dispose();
            videoSource = null;
        }
        if (_localStream != null) {
            _localStream = null;
        }
        if (localRenderer != null) {
            localRenderer.release();
        }
    }

    /**
     * 切换外放
     * @param enable
     * @return
     */
    public boolean toggleSpeaker(boolean enable) {
        //Log.d("call", Log.getStackTraceString(new Throwable()));
        if (audioManager != null) {
            isSpeakerOn = enable;
            audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);

            if (enable) {
                if (!setBluetoothHeadsetOn()) {   //优先蓝牙
                    audioManager.setMode(AudioManager.MODE_NORMAL);
                    audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                            audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL),
                            AudioManager.FX_KEY_CLICK);
                    audioManager.setSpeakerphoneOn(true);
                }
            } else {
                //5.0以上
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    //设置mode
                    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                } else {
                    //设置mode
                    audioManager.setMode(AudioManager.MODE_IN_CALL);
                }
                //设置音量，解决有些机型切换后没声音或者声音突然变大的问题
                audioManager.setStreamVolume(
                        AudioManager.STREAM_VOICE_CALL,
                        audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL),
                        AudioManager.FX_KEY_CLICK
                );
                audioManager.setSpeakerphoneOn(false);
            }
            return true;
        }
        return false;
    }

    /**
     * 切换耳机
     * @param isHeadset
     * @return
     */
    public boolean toggleHeadset(boolean isHeadset) {
        if (audioManager != null) {
            if (isHeadset) {
                //5.0以上
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    //设置mode
                    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                } else {
                    //设置mode
                    audioManager.setMode(AudioManager.MODE_IN_CALL);
                }
                audioManager.setSpeakerphoneOn(false);
            } else {
                if (mIsAudioOnly) {
                    toggleSpeaker(isSpeakerOn);
                }
            }
        }
        return false;
    }

    /**
     * 蓝牙
     * @return
     */
    public boolean setBluetoothHeadsetOn(){
        if (!isBluetoothHeadsetConnected()){
            return false;
        }
        if (audioManager != null) {
            audioManager.setStreamVolume(
                    AudioManager.STREAM_MUSIC,
                    audioManager.getStreamVolume(AudioManager.STREAM_MUSIC),
                    AudioManager.FX_KEY_CLICK
            );
            audioManager.setSpeakerphoneOn(false);

            audioManager.startBluetoothSco();
            audioManager.setBluetoothScoOn(true);

            audioFocusManager = new AudioFocusManager(audioManager);
            audioFocusManager.requestFocus();

            return true;
        }
        return false;
    }

    /**
     * 蓝牙是否连接
     * @return
     */
    public boolean isBluetoothHeadsetConnected(){
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        boolean isBluetoothHeadsetConnected =  (bluetoothAdapter != null && bluetoothAdapter.isEnabled()
                && bluetoothAdapter.getProfileConnectionState(BluetoothHeadset.HEADSET) == BluetoothHeadset.STATE_CONNECTED);

        return isBluetoothHeadsetConnected;
    }

    public boolean isHeadphonesPlugged() {
        if (audioManager == null) {
            return false;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            @SuppressLint("WrongConstant") AudioDeviceInfo[] audioDevices = audioManager.getDevices(AudioManager.GET_DEVICES_ALL);
            for (AudioDeviceInfo deviceInfo : audioDevices) {
                if (deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
                        || deviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET) {
                    return true;
                }
            }
            return false;
        } else {
            return audioManager.isWiredHeadsetOn();
        }
    }

    /**
     * 切换摄像头
     */
    public void switchCamera() {
        if (isSwitch) return;
        isSwitch = true;
        if (captureAndroid == null) return;
        if (captureAndroid instanceof CameraVideoCapturer) {
            CameraVideoCapturer cameraVideoCapturer = (CameraVideoCapturer) captureAndroid;
            try {
                cameraVideoCapturer.switchCamera(new CameraVideoCapturer.CameraSwitchHandler() {
                    @Override
                    public void onCameraSwitchDone(boolean isFrontCamera) {
                        isSwitch = false;
                    }

                    @Override
                    public void onCameraSwitchError(String errorDescription) {
                        isSwitch = false;
                    }
                });
            } catch (Exception e) {
                isSwitch = false;
            }
        } else {
            Log.d(TAG, "Will not switch camera, video caputurer is not a camera");
        }
    }

    public void release() {
        if (audioManager != null) {
            audioManager.setMode(AudioManager.MODE_NORMAL);

            if (isBluetoothHeadsetConnected()) {
                audioManager.stopBluetoothSco();
                audioManager.setBluetoothScoOn(false);
            }
        }
        if (audioFocusManager!=null){
            audioFocusManager.releaseAudioFocus();
        }

        //释放所有连接
        if (peerMap != null) {
            for (Map.Entry<BigInteger, Peer> entry: peerMap.entrySet()) {
                if (entry.getValue() != null) {
                    entry.getValue().close();
                }
            }
            peerMap.clear();
        }

        // 停止预览
        stopPreview();

//        if (factory != null) {
//            factory.dispose();
//            factory = null;
//        }
//
//        if (mRootEglBase != null) {
//            mRootEglBase.release();
//            mRootEglBase = null;
//        }

        PeerConnectionFactory.stopInternalTracingCapture();
        PeerConnectionFactory.shutdownInternalTracer();
    }

    // ---------------------------------------webrtc
    public void createLocalPeer(List<BigInteger> userIds, CreatePeerConnectionCallback peerConnectionCallback){
        for(BigInteger userId:userIds){
            Peer peer = new Peer(factory,iceServers,peerConnectionCallback,executor,userId);
            peer.addLocalStream(_localStream);
            peerMap.put(userId, peer);
        }
        if (isHeadphonesPlugged()) {
            toggleHeadset(true);
        } else {
            audioManager.setMode(AudioManager.MODE_NORMAL);
        }
    }

    public void createLocalPeer(BigInteger userId, CreatePeerConnectionCallback peerConnectionCallback){
        List<BigInteger> userIds = new ArrayList<>();
        userIds.add(userId);
        createLocalPeer(userIds,peerConnectionCallback);
    }

    public void createRemotePeer(BigInteger userId, CreatePeerConnectionCallback peerConnectionCallback){
        Peer peer = new Peer(factory,iceServers,peerConnectionCallback,executor,userId);
        peerMap.put(userId, peer);
    }

    public void leaveRoom(BigInteger userId) {
        Peer peer = peerMap.get(userId);
        if (peer != null) {
            peer.close();
            peerMap.remove(userId);
        }
        Log.d(TAG, "leaveRoom peers.size() = " + peerMap.size());
        if (peerMap.size() <= 1) {
            if (peerMap.size() == 1) {
                for (Map.Entry<BigInteger, Peer> set : peerMap.entrySet()) {
                    set.getValue().close();
                }
                peerMap.clear();
            }
        }
    }

    public View setupRemoteVideo(BigInteger userId, boolean isO) {
        Peer peer = peerMap.get(userId);
        if (peer == null) return null;

        if (peer.renderer == null) {
            peer.createRender(mRootEglBase, mContext, isO);
        }

        return peer.renderer;
    }

    public Peer getPeer(BigInteger userId) {
        return peerMap.get(userId);
    }
}
