package com.mogo.cloud.live.manager;

import static im.zego.zegoexpress.constants.ZegoRoomState.DISCONNECTED;

import android.app.Application;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceView;
import android.view.TextureView;

import com.mogo.cloud.live.listener.ILiveCurrentRoomStatusListener;
import com.mogo.cloud.live.listener.ILiveMultiRoomStatusListener;
import com.mogo.cloud.live.listener.ILiveProgressListener;
import com.mogo.cloud.live.listener.ILivePullStateListener;
import com.mogo.cloud.live.listener.ILivePushStatusListener;
import com.mogo.cloud.live.listener.ILiveRoomPersonListener;
import com.mogo.cloud.live.model.LiveStatusModel;
import com.mogo.cloud.live.server.PushService;
import com.mogo.cloud.passport.MoGoAiCloudClientConfig;

import org.json.JSONObject;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import im.zego.zegoexpress.ZegoExpressEngine;
import im.zego.zegoexpress.callback.IZegoCustomVideoCaptureHandler;
import im.zego.zegoexpress.callback.IZegoEventHandler;
import im.zego.zegoexpress.constants.ZegoEngineState;
import im.zego.zegoexpress.constants.ZegoPlayerMediaEvent;
import im.zego.zegoexpress.constants.ZegoPlayerState;
import im.zego.zegoexpress.constants.ZegoPublishChannel;
import im.zego.zegoexpress.constants.ZegoPublisherState;
import im.zego.zegoexpress.constants.ZegoRoomMode;
import im.zego.zegoexpress.constants.ZegoRoomState;
import im.zego.zegoexpress.constants.ZegoScenario;
import im.zego.zegoexpress.constants.ZegoStreamEvent;
import im.zego.zegoexpress.constants.ZegoUpdateType;
import im.zego.zegoexpress.constants.ZegoVideoBufferType;
import im.zego.zegoexpress.constants.ZegoVideoCodecID;
import im.zego.zegoexpress.constants.ZegoVideoConfigPreset;
import im.zego.zegoexpress.constants.ZegoVideoFrameFormat;
import im.zego.zegoexpress.constants.ZegoViewMode;
import im.zego.zegoexpress.entity.ZegoCanvas;
import im.zego.zegoexpress.entity.ZegoCustomVideoCaptureConfig;
import im.zego.zegoexpress.entity.ZegoEngineConfig;
import im.zego.zegoexpress.entity.ZegoEngineProfile;
import im.zego.zegoexpress.entity.ZegoPlayStreamQuality;
import im.zego.zegoexpress.entity.ZegoPlayerConfig;
import im.zego.zegoexpress.entity.ZegoPublisherConfig;
import im.zego.zegoexpress.entity.ZegoRoomConfig;
import im.zego.zegoexpress.entity.ZegoUser;
import im.zego.zegoexpress.entity.ZegoVideoConfig;
import im.zego.zegoexpress.entity.ZegoVideoFrameParam;

/**
 * 即构直播管理
 */
public class MoGoLiveManager {
    public static final String TAG = "MoGoLiveManager";

    //这个只是根据业务需求进行设置的变量，具体应用需根据开发者自定义安排。仅供参考
    public static boolean isFirstLogin = true;
    /**
     * 即构平台分配 APP_ID
     */
    private long appId = 1759603340;
    /**
     * 即构平台分配的 APP_KEY
     */
    private String appKey = "a9b02ca6122c585b434c498417bb623c5e9f07c71e8a1b5143dc3dc2e9e4439d";
    /**
     * 存储即构的日志路径
     */
    private Application mApplication;
    /**
     * 直播推送配置对象
     */
    private MoGoLivePushConfig mLivePushConfig;
    /**
     * 直播会议ID，使用推流端的车机信息建立房间ID，这里采用格式为：ROOM_ID_车机SN编号
     */
    public static final String ROOM_ID_PREFIX = "ROOM_ID_";
    /**
     * 直播用户名称的
     */
    public static final String NAME_PREFIX = "MoGoCar_";
    /**
     * 直播流ID，发起推送的直播流ID
     */
    public static final String STREAM_ID_PREFIX = "STREAM_ID_";  //+ "_" + System.currentTimeMillis()
    /**
     * 定义 即构SDK 引擎对象
     */
    private ZegoExpressEngine mExpressEngine;
    /**
     * 创建自定义视频采集对象
     */
    private ZegoCustomVideoCaptureConfig customVideoCaptureConfig;
    /**
     * 直播进度回调用
     */
    private final List<ILiveProgressListener> mProgressListener = new ArrayList<>();
    /**
     * 直播房间连接状态
     */
    private final List<ILiveCurrentRoomStatusListener> mRoomStatusListener = new ArrayList<>();
    /**
     * 直播第二个房间连接状态
     */
    private final List<ILiveMultiRoomStatusListener> mMultiRoomStatusListener = new ArrayList<>();
    /**
     * 直播房间人员状态
     */
    private static final List<ILiveRoomPersonListener> mRoomPersonListener = new ArrayList<>();
    /**
     * 直播推流状态回调
     */
    private static final List<ILivePushStatusListener> mLiveStatusListener = new ArrayList<>();
    /**
     * 直播拉流观看状态回调
     */
    private static final List<ILivePullStateListener> mLivePullStateListener = new ArrayList<>();
    /**
     * 直播数据
     */
    private final LiveStatusModel mLiveStatusModel;
    /**
     * 房间配置
     */
    private final ZegoRoomConfig zeGoRoomConfig;
    private ZegoUser zegoUserCurrent;

    private static final class Holder {
        private static final MoGoLiveManager manager = new MoGoLiveManager();
    }

    /**
     * 获取即构直播管理
     */
    public static MoGoLiveManager getInstance() {
        return Holder.manager;
    }

    private MoGoLiveManager() {
        Log.i(TAG, "初始化 MoGoLiveManager");
        mLiveStatusModel = new LiveStatusModel();

        zeGoRoomConfig = new ZegoRoomConfig();
        zeGoRoomConfig.isUserStatusNotify = true;

    }

    public void setAppId(long appId) {
        this.appId = appId;
    }

    public void setAppKey(String appKey) {
        this.appKey = appKey;
    }

    public LiveStatusModel getLiveStatusModel() {
        return mLiveStatusModel;
    }

    /**
     * 初始化直播SDK
     *
     * @param application    上下文
     * @param livePushConfig 是否需要配置
     */
    public MoGoLiveManager init(Application application, MoGoLivePushConfig livePushConfig) {
        mApplication = application;
        mLivePushConfig = livePushConfig;
        initExpressEngine();
        return this;
    }

    /**
     * 事件回调用
     */
    private final IZegoEventHandler mEventHandler = new IZegoEventHandler() {

        // 调试错误信息回调
        @Override
        public void onDebugError(int errorCode, String funcName, String info) {
            super.onDebugError(errorCode, funcName, info);
            Log.i(TAG, "调试错误信息回调 onDebugError errorCode : " + errorCode);
            for (ILiveProgressListener iLiveProgressListener : mProgressListener) {
                iLiveProgressListener.onDebugError(errorCode, funcName, info);
            }
            // 是否处于发布状态
            if (mLiveStatusModel != null && mLiveStatusModel.isPushing()) {
                // 停止推送数据
                stopPublish();
            }
        }

        // 音视频引擎状态更新回调
        @Override
        public void onEngineStateUpdate(ZegoEngineState state) {
            super.onEngineStateUpdate(state);
            Log.i(TAG, "音视频引擎状态更新回调 onEngineStateUpdate state : " + state.name());
            if (state == ZegoEngineState.START) {
                for (ILiveProgressListener iLiveProgressListener : mProgressListener) {
                    iLiveProgressListener.onEngineStart();
                }
            } else {
                for (ILiveProgressListener iLiveProgressListener : mProgressListener) {
                    iLiveProgressListener.onEngineStop();
                }
            }
        }

        // 房间状态变化通知
        @Override
        public void onRoomStateUpdate(String roomID, ZegoRoomState state, int errorCode, JSONObject extendedData) {
            super.onRoomStateUpdate(roomID, state, errorCode, extendedData);
            // 这里回调的是当前用户的房间状态
            if (mLiveStatusModel.getCurrentRoomId().equals(roomID)) {
                Log.i(TAG, "房间状态变化通知 onRoomStateUpdate currentRoomId : " + roomID +
                        " state:" + state +
                        " errorCode:" + errorCode +
                        " extendedData:" + extendedData.toString());

                // 设置当前登录状态
                mLiveStatusModel.setLoginCurrentRoom(state != DISCONNECTED);
                //房间状态更新
                if (state == ZegoRoomState.CONNECTING) {
                    for (ILiveCurrentRoomStatusListener iLiveRoomStatusListener : mRoomStatusListener) {
                        iLiveRoomStatusListener.onCurrentRoomConnecting();
                    }
                } else if (state == ZegoRoomState.CONNECTED) {
                    for (ILiveCurrentRoomStatusListener iLiveRoomStatusListener : mRoomStatusListener) {
                        iLiveRoomStatusListener.onCurrentRoomConnected();
                    }
                } else {
                    mLiveStatusModel.setLoginCurrentRoom(false);
                    for (ILiveCurrentRoomStatusListener iLiveRoomStatusListener : mRoomStatusListener) {
                        iLiveRoomStatusListener.onCurrentRoomDisconnected();
                    }
                    //errorCode 不为 0 时，房间状态异常，完整错误状态可参考错误码说明 https://doc-zh.zego.im/article/4378
                    // 处理被踢掉的情况
                    if (errorCode != 0) {
                        Log.w(TAG, "用户被踢出房间，尝试再次登录……");
                        if (errorCode == 1002053) {
                            //房间连接断开并且重试超时
                            //此时可以在业务中退出房间/直播间/课堂，或者手动调用接口再次登录
                            loginRoom();
                        } else if (errorCode == 1002050) {
                            //用户被踢出房间（由于 userID 相同的用户在其他地方登录）
                            // 再次登录
                            loginRoom();
                        } else if (errorCode == 1002055) {
                            //用户被踢出房间（开发者主动调用后台的踢人接口）

                        } else if (errorCode == 1002033) {
                            //当使用登录房间鉴权的功能时，传入的 token 出错导

                        }
                    }
                }
            }
            // 这里回调的是登录的他人房间的状态
            else if (mLiveStatusModel.getMultiRoomId().equals(roomID)) {
                // 1. 当收到该回调通知且 state 为 PLAYING 时，表示拉流成功
                // 2. 当收到该回调通知且 state 为 PLAY_REQUESTING 时，表示可能是正在拉流或者由于网络中断等原因导致 SDK 正在重试拉流
                // 3. 当收到该回调通知且 state 为 NO_PLAY 时，表示拉流停止
                Log.i(TAG, "这里回调的是登录的他人房间的状态 onRoomStateUpdate multiRoomId : " + roomID +
                        " state:" + state +
                        " errorCode:" + errorCode +
                        " extendedData:" + extendedData.toString());
                // 设置第二个房间登录状态
                mLiveStatusModel.setLoginMultiRoom(state != DISCONNECTED);
                //房间状态更新
                if (state == ZegoRoomState.CONNECTING) {
                    for (ILiveMultiRoomStatusListener iLiveMultiRoomStatusListener : mMultiRoomStatusListener) {
                        iLiveMultiRoomStatusListener.onMultiRoomConnecting();
                    }
                } else if (state == ZegoRoomState.CONNECTED) {
                    for (ILiveMultiRoomStatusListener iLiveMultiRoomStatusListener : mMultiRoomStatusListener) {
                        iLiveMultiRoomStatusListener.onMultiRoomConnected();
                    }
                } else {
                    for (ILiveMultiRoomStatusListener iLiveMultiRoomStatusListener : mMultiRoomStatusListener) {
                        iLiveMultiRoomStatusListener.onMultiRoomDisconnected();
                    }
                }
            }
        }

        // 房间内当前在线用户数量回调
        @Override
        public void onRoomOnlineUserCountUpdate(String roomID, int count) {
            super.onRoomOnlineUserCountUpdate(roomID, count);
            // 这里只处理「当前设备-观看者」登录的房间中的用户总数
            if (mLiveStatusModel.getCurrentRoomId().equals(roomID)) {
                // 更新真实的在线人数
                mLiveStatusModel.setOnlineNumber(count);
                if (count > 2) {
                    PushService.startService(mApplication, PushService.ACTION_START_RTMP_PUSH);
                }
                Log.i(TAG, "「自己」房间内当前在线用户数量回调 onRoomOnlineUserCountUpdate roomID : " + roomID +
                        " , online user number : " + mLiveStatusModel.getOnlineNumber());
                for (ILiveRoomPersonListener iLiveRoomPersonListener : mRoomPersonListener) {
                    if (iLiveRoomPersonListener != null) {
                        iLiveRoomPersonListener.onRoomOnlineUserCountUpdate(count);
                    }
                }
            }
            // 这里只处理登录的「他人-被直播者」房间中的用户总数
            else if (mLiveStatusModel.getMultiRoomId().equals(roomID)) {
                Log.i(TAG, "「他人」房间内当前在线用户数量回调 onRoomOnlineUserCountUpdate roomID : " + roomID +
                        " , online user number : " + count);
            }
        }

        // 房间内其他用户增加或减少的通知回调
        @Override
        public void onRoomUserUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoUser> userList) {
            super.onRoomUserUpdate(roomID, updateType, userList);
            // 这里只处理当前设备登录的房间中的用户总数
            synchronized (MoGoLiveManager.this) {
                if (mLiveStatusModel.getCurrentRoomId().equals(roomID)) {
                    if (updateType == ZegoUpdateType.ADD) {
                        mLiveStatusModel.setOnlineNumber(mLiveStatusModel.getOnlineNumber() + userList.size());
                    } else if (updateType == ZegoUpdateType.DELETE) {
                        mLiveStatusModel.setOnlineNumber(mLiveStatusModel.getOnlineNumber() - userList.size());
                    }

                    Log.i(TAG, "「自己」房间内其他用户增加或减少的通知回调 onRoomUserUpdate roomId : " + roomID +
                            " , updateType : " + updateType.name() +
                            " , online user number : " + mLiveStatusModel.getOnlineNumber());
                    for (ILiveRoomPersonListener iLiveRoomPersonListener : mRoomPersonListener) {
                        if (iLiveRoomPersonListener != null) {
                            iLiveRoomPersonListener.onRoomUserUpdate(updateType, userList);
                        }
                    }
                }
                // 这里查看的是别人的房间
                else if (mLiveStatusModel.getMultiStreamId().equals(roomID)) {
                    Log.i(TAG, "「他人」房间内其他用户增加或减少的通知回调 onRoomUserUpdate roomId : " + roomID +
                            " , updateType : " + updateType.name() +
                            " , online user number : " + mLiveStatusModel.getOnlineNumber());
                }
            }
        }

        // 推流状态回调
        @Override
        public void onPublisherStateUpdate(String streamID, ZegoPublisherState state,
                                           int errorCode, JSONObject extendedData) {
            super.onPublisherStateUpdate(streamID, state, errorCode, extendedData);
            // 这里只处理当前设备登录的房间中的用户总数
            if (mLiveStatusModel.getCurrentStreamId().equals(streamID)) {
                // 判断不是非推流状态则为推流
                mLiveStatusModel.setPushing(state != ZegoPublisherState.NO_PUBLISH);
                Log.i(TAG, "推流状态回调 onPublisherStateUpdate streamID : " + streamID +
                        " , isPlaying : " + mLiveStatusModel.isPlaying() +
                        " , isPushing : " + mLiveStatusModel.isPushing() +
                        " , state : " + state.name() +
                        " , errorCode : " + errorCode +
                        " , extendedData : " + extendedData.toString());

//                // 判断如果处于非播放和非推流状态则进行登出操作,并释放引擎
//                if (!mLiveStatusModel.isPlaying()
//                        && !mLiveStatusModel.isPushing()
//                        && mLiveStatusModel.getOnlineNumber() <= 1) {
//                    logoutCurrentRoom();
//                }
                for (ILivePushStatusListener iLivePushStatusListener : mLiveStatusListener) {
                    if (iLivePushStatusListener != null) {
                        iLivePushStatusListener.onChange(mLiveStatusModel.isPushing() ? 0 : 1);
                    }
                }
            }
            // 这里查看的是别人的房间
            else if (mLiveStatusModel.getMultiStreamId().equals(streamID)) {

            }
        }

        // 拉流状态变更回调
        @Override
        public void onPlayerStateUpdate(String streamID, ZegoPlayerState state, int errorCode, JSONObject extendedData) {
            super.onPlayerStateUpdate(streamID, state, errorCode, extendedData);
            // 这里查看的是别人的房间
            if (mLiveStatusModel.getMultiStreamId().equals(streamID)) {
                // 如果不是非播放状态则判定为直播状态
                mLiveStatusModel.setPlaying(state == ZegoPlayerState.PLAYING);
                // 同步更新状态
                for (ILivePullStateListener iLivePullStateListener : mLivePullStateListener) {
                    if (iLivePullStateListener != null) {
                        iLivePullStateListener.onPlayerStateUpdate(state.value());
                    }
                }
                Log.i(TAG, "拉流状态变更回调 onPlayerStateUpdate streamId : " + streamID +
                        " , isPlaying : " + mLiveStatusModel.isPlaying() +
                        " , isPushing : " + mLiveStatusModel.isPushing() +
                        " , state : " + state.name() +
                        " , errorCode : " + errorCode +
                        " , extendData : " + extendedData.toString());

//                // 判断如果处于非播放和非推流状态则进行登出操作,并释放引擎
//                if (!mLiveStatusModel.isPlaying()
//                        && !mLiveStatusModel.isPushing()
//                        && mLiveStatusModel.getOnlineNumber() <= 1) {
//                    logoutCurrentRoom();
//                }
            }
        }

        @Override
        public void onPlayerMediaEvent(String streamID, ZegoPlayerMediaEvent zegoPlayerMediaEvent) {
            super.onPlayerMediaEvent(streamID, zegoPlayerMediaEvent);
            Log.i(TAG, "拉流媒体事件回调 onPlayerMediaEvent streamId : " + streamID +
                    " , isPlaying : " + mLiveStatusModel.isPlaying() +
                    " , isPushing : " + mLiveStatusModel.isPushing() +
                    " , zegoPlayerMediaEvent : " + zegoPlayerMediaEvent.name());
        }

        @Override
        public void onPlayerStreamEvent(ZegoStreamEvent eventID, String streamID, String extraInfo) {
            super.onPlayerStreamEvent(eventID, streamID, extraInfo);
            Log.i(TAG, "拉流事件回调 onPlayerStreamEvent streamId : " + streamID +
                    " , isPlaying : " + mLiveStatusModel.isPlaying() +
                    " , isPushing : " + mLiveStatusModel.isPushing() +
                    " , extraInfo : " + extraInfo);
        }

        @Override
        public void onPlayerQualityUpdate(String streamID, ZegoPlayStreamQuality quality) {
            super.onPlayerQualityUpdate(streamID, quality);
            Log.i(TAG, "拉流事件回调 onPlayerStreamEvent streamId : " + streamID +
                    " , isPlaying : " + mLiveStatusModel.isPlaying() +
                    " , isPushing : " + mLiveStatusModel.isPushing() +
                    " , quality.videoRecvFPS : " + quality.videoRecvFPS);

            if (quality.videoRecvFPS <= 0) {
                // 帧率为小于0即无数据，展示loading
                mLiveStatusModel.setPlaying(false);
                // 同步更新状态
                for (ILivePullStateListener iLivePullStateListener : mLivePullStateListener) {
                    if (iLivePullStateListener != null) {
                        iLivePullStateListener.onPlayerStateUpdate(1);
                    }
                }
            } else {
                // 帧率为大于0即有数据，进行播放
                mLiveStatusModel.setPlaying(true);
                // 同步更新状态
                for (ILivePullStateListener iLivePullStateListener : mLivePullStateListener) {
                    if (iLivePullStateListener != null) {
                        iLivePullStateListener.onPlayerStateUpdate(2);
                    }
                }
            }
        }

        @Override
        public void onPlayerRecvAudioFirstFrame(String streamID) {
            super.onPlayerRecvAudioFirstFrame(streamID);
            Log.d(TAG, "onPlayerRecvAudioFirstFrame");
        }

        @Override
        public void onPlayerRenderVideoFirstFrame(String streamID) {
            super.onPlayerRenderVideoFirstFrame(streamID);
            Log.d(TAG, "onPlayerRenderVideoFirstFrame");
        }

        @Override
        public void onPlayerRecvVideoFirstFrame(String streamID) {
            super.onPlayerRecvVideoFirstFrame(streamID);
            Log.d(TAG, "onPlayerRecvVideoFirstFrame");
            // 同步更新状态
            for (ILivePullStateListener iLivePullStateListener : mLivePullStateListener) {
                if (iLivePullStateListener != null) {
                    iLivePullStateListener.onVideoFirstFrame();
                }
            }
        }

        @Override
        public void onDeviceError(int errorCode, String deviceName) {
            super.onDeviceError(errorCode, deviceName);
            Log.e(TAG, "onDeviceError:" + errorCode);
            // 同步更新状态
            for (ILivePullStateListener iLivePullStateListener : mLivePullStateListener) {
                if (iLivePullStateListener != null) {
                    iLivePullStateListener.onDeviceError(errorCode);
                }
            }
        }
    };

    /**
     * 设置直播进度监听
     *
     * @param liveProgressListener 监听回调用
     */
    public void addLiveProgressListener(ILiveProgressListener liveProgressListener) {
        this.mProgressListener.add(liveProgressListener);
    }

    /**
     * 删除直播进度监听
     *
     * @param liveProgressListener 监听回调用
     */
    public void removeLiveProgressListener(ILiveProgressListener liveProgressListener) {
        this.mProgressListener.remove(liveProgressListener);
    }

    /**
     * 设置直播间连接状态监听
     *
     * @param roomStatusListener 监听回调用
     */
    public void addLiveRoomStatusListener(ILiveCurrentRoomStatusListener roomStatusListener) {
        this.mRoomStatusListener.add(roomStatusListener);
    }

    /**
     * 删除直播间连接状态监听
     *
     * @param roomStatusListener 监听回调用
     */
    public void removeLiveRoomStatusListener(ILiveCurrentRoomStatusListener roomStatusListener) {
        this.mRoomStatusListener.remove(roomStatusListener);
    }

    /**
     * 设置直播间的人员监听
     *
     * @param roomPersonListener 监听回调用
     */
    public static void addLiveRoomPersonListener(ILiveRoomPersonListener roomPersonListener) {
        mRoomPersonListener.add(roomPersonListener);
    }

    /**
     * 直播推送状态回调
     *
     * @param liveStatusListener 回调监听
     */
    public static void addLivePushStatusListener(ILivePushStatusListener liveStatusListener) {
        mLiveStatusListener.add(liveStatusListener);
    }

    /**
     * 直播拉流播放状态回调
     *
     * @param livePullStateListener 回调监听
     */
    public static void addLivePullStateListener(ILivePullStateListener livePullStateListener) {
        mLivePullStateListener.add(livePullStateListener);
    }

    /**
     * 初始化自定义采集
     */
    public void initExpressEngine() {
        Log.i(TAG, "initCustomVideoCapture 初始化引擎");
        mLiveStatusModel.setExpressEngineCanUse(true);
        // 创建 enging 对象, appID, appSign 为开发者在 ZEGO 管理控制台申请的凭证信息,
        // 未上线的开发者 isTestEnvironment 为 true, application 为安卓应用的上下文
        boolean isTestEnv = false;
        switch (MoGoAiCloudClientConfig.getInstance().getNetMode()) {
            case MoGoAiCloudClientConfig.HTTP_DNS_ENV_DEV:
            case MoGoAiCloudClientConfig.HTTP_DNS_ENV_QA:
                isTestEnv = true;
                break;
            case MoGoAiCloudClientConfig.HTTP_DNS_ENV_RELEASE:
            case MoGoAiCloudClientConfig.HTTP_DNS_ENV_DEMO:
                isTestEnv = false;
        }

        // 设置房间模式为多房间模式
        ZegoExpressEngine.setRoomMode(ZegoRoomMode.MULTI_ROOM);

        ZegoEngineConfig zegoEngineConfig = new ZegoEngineConfig();
        zegoEngineConfig.advancedConfig.put("language", "chinese");
        zegoEngineConfig.advancedConfig.put("set_verbose", MoGoAiCloudClientConfig.getInstance().isShowDebugLog() + "");
        ZegoExpressEngine.setEngineConfig(zegoEngineConfig);

        ZegoEngineProfile profile = new ZegoEngineProfile();
        /* 请通过官网注册获取，格式为 123456789L */
        profile.appID = appId;
        /* 64个字符，请通过官网注册获取，格式为"0123456789012345678901234567890123456789012345678901234567890123" */
        profile.appSign = appKey;
        /* 通用场景接入 */
        profile.scenario = ZegoScenario.GENERAL;
        /* 设置app的application 对象 */
        profile.application = mApplication;
        /* 创建引擎 */
        mExpressEngine = ZegoExpressEngine.createEngine(profile, mEventHandler);
        // true 表示静音（关闭）
        mExpressEngine.muteMicrophone(true);
        if (mLivePushConfig != null) {
            // 视频配置
            ZegoVideoConfig zegoVideoConfig = new ZegoVideoConfig(ZegoVideoConfigPreset.PRESET_720P);
            // 采集分辨率，控制摄像头图像采集的分辨率。SDK 要求将宽和高设置为偶数。
            zegoVideoConfig.setCaptureResolution(mLivePushConfig.getWidth(), mLivePushConfig.getHeight());
            // 编码分辨率，控制编码器编码推流的图像分辨率。SDK 要求将宽和高设置为偶数。推流前后设置均可生效
            zegoVideoConfig.setEncodeResolution(mLivePushConfig.getWidth(), mLivePushConfig.getHeight());
            // 设置视频帧率
            zegoVideoConfig.setVideoFPS(mLivePushConfig.getVideoFPS());
            // 设置视频比特率
            zegoVideoConfig.setVideoBitrate(mLivePushConfig.getVideoBitrate());
            // 设置转码的ID，使用H.264
            zegoVideoConfig.setCodecID(ZegoVideoCodecID.DEFAULT);

            // 将视频信息设置到推流引擎
            mExpressEngine.setVideoConfig(zegoVideoConfig);

            if (mLivePushConfig.isExpressEngine()) {
                initCustomVideoCapture();
            }
        }
        loginRoom();
    }

    /**
     * 初始化自定义视频采集
     */
    private void initCustomVideoCapture() {
        // 创建自定义视频采集对象
        customVideoCaptureConfig = new ZegoCustomVideoCaptureConfig();
        // 设置自定义视频采集视频帧数据类型
        customVideoCaptureConfig.bufferType = ZegoVideoBufferType.RAW_DATA;
        // 开始或停止自定义视频采集，支持设置其他通道的推流
        mExpressEngine.enableCustomVideoCapture(true, customVideoCaptureConfig, ZegoPublishChannel.MAIN);
        // 设置自定义视频采集回调
        mExpressEngine.setCustomVideoCaptureHandler(new IZegoCustomVideoCaptureHandler() {
            @Override
            public void onStart(ZegoPublishChannel channel) {
                super.onStart(channel);
                Log.i(TAG, "SDK 通知将要开始采集视频帧 setCustomVideoCaptureHandler onStart");
                mLiveStatusModel.setCaptureStatus(true);
            }

            @Override
            public void onStop(ZegoPublishChannel channel) {
                super.onStop(channel);
                Log.i(TAG, "SDK 通知将要停止采集视频帧 setCustomVideoCaptureHandler onStop");
                mLiveStatusModel.setCaptureStatus(false);
            }
        });
    }

    /**
     * 进入自己房间
     */
    public synchronized void loginRoom() {
        // 当前用户ID
        String userId;
        if (MoGoAiCloudClientConfig.getInstance().isAnchor()) {
            // 这里为了方便直接使用原始的车机SN
            userId = mLivePushConfig.getDevicesId();
        } else {
            // 这里对观众添加标记，防止与主播的ID相同，导致踢下线的情况发生
            userId = "Audience_" + mLivePushConfig.getDevicesId();
        }
        mLiveStatusModel.setCurrentRoomId(ROOM_ID_PREFIX + userId);
        mLiveStatusModel.setCurrentStreamId(STREAM_ID_PREFIX + userId);
        Log.i(TAG,
                "尝试进入自己房间 loginRoom userId : " + userId
                        + " currentRoomId：" + mLiveStatusModel.getCurrentRoomId()
                        + " currentStreamId：" + mLiveStatusModel.getCurrentStreamId());
        if (!mLiveStatusModel.isLoginCurrentRoom()) {
            zegoUserCurrent = new ZegoUser(userId, NAME_PREFIX + userId);
            mExpressEngine.loginRoom(mLiveStatusModel.getCurrentRoomId(), zegoUserCurrent, zeGoRoomConfig);
        }
    }

    /**
     * 退出自己房间
     */
    public synchronized void logoutCurrentRoom() {
        Log.i(TAG, "尝试退出自己房间 logoutRoom : " + mLiveStatusModel.getCurrentRoomId());
        if (mExpressEngine != null) {
            if (!mLiveStatusModel.isLoginCurrentRoom()) {
                Log.w(TAG, "还未登录自己房间");
                return;
            }
            if (mLiveStatusModel.isPlaying()) {
                Log.w(TAG, "处于播放中，不可退出房间");
                return;
            }
            Log.i(TAG, "执行退出房间操作");
            mExpressEngine.logoutRoom(mLiveStatusModel.getCurrentRoomId());
        } else {
            Log.w(TAG, "ZeGo 引擎未初始化");
        }
    }

    /**
     * 进入多房间
     *
     * @param otherRoomId 房间ID
     */
    public synchronized void loginMultiRoom(String otherRoomId) {
        if (!mLiveStatusModel.isLoginCurrentRoom()) {
            loginRoom();
        }
        mLiveStatusModel.setMultiRoomId(ROOM_ID_PREFIX + otherRoomId);
        mLiveStatusModel.setMultiStreamId(STREAM_ID_PREFIX + otherRoomId);
        Log.i(TAG,
                "尝试进入多房间 loginMultiRoom multiRoomId : " + mLiveStatusModel.getMultiRoomId()
                        + " currentStreamId : " + mLiveStatusModel.getMultiStreamId());
//        if (!mLiveStatusModel.isLoginMultiRoom()) {
        Log.i(TAG, "执行登录多房间");
        mExpressEngine.loginRoom(mLiveStatusModel.getMultiRoomId(), zegoUserCurrent, zeGoRoomConfig);
//        } else {
//            Log.w(TAG, "已经登录了多房间");
//        }
    }

    /**
     * 退出多房间
     */
    public synchronized void logoutMultiRoom(String sn) {
        Log.i(TAG, "尝试退出多房间 logoutMultiRoom multiRoomId : " + mLiveStatusModel.getMultiRoomId());
        if (mExpressEngine != null) {
//            if (mLiveStatusModel.isLoginMultiRoom()) {
            Log.i(TAG, "执行退出多房间");
            mExpressEngine.logoutRoom(ROOM_ID_PREFIX + sn);
//            } else {
//                Log.w(TAG, "还未登录多房间");
//            }
        } else {
            Log.w(TAG, "ZeGo 引擎未初始化");
        }
    }

    /**
     * 开始推流到ZeGo
     */
    public void startPublish() {
        Log.i(TAG, "开始推流到ZeGo startPublish currentStreamId : " + mLiveStatusModel.getCurrentStreamId());
        ZegoPublisherConfig config = new ZegoPublisherConfig();
        config.roomID = mLiveStatusModel.getCurrentRoomId();
        mExpressEngine.startPublishingStream(mLiveStatusModel.getCurrentStreamId(), config, ZegoPublishChannel.MAIN);
    }

    /**
     * 开始发布视频流
     *
     * @param byteBuffer               数据缓存
     * @param dataLength               数据长度
     * @param referenceTimeMillisecond 视频帧参考时间，UNIX时间戳，以毫秒为单位。音视频同步用的，
     */
    public void startPublishingStream(ByteBuffer byteBuffer, int dataLength, long referenceTimeMillisecond) {
        if (mExpressEngine != null) {
            ZegoVideoFrameParam zegoVideoFrameParam = new ZegoVideoFrameParam();
            zegoVideoFrameParam.format = ZegoVideoFrameFormat.I420;
            zegoVideoFrameParam.width = mLivePushConfig.getWidth();
            zegoVideoFrameParam.height = mLivePushConfig.getHeight();
            zegoVideoFrameParam.strides[0] = mLivePushConfig.getWidth();
            zegoVideoFrameParam.strides[1] = mLivePushConfig.getWidth();
            mExpressEngine.sendCustomVideoCaptureRawData(byteBuffer, dataLength, zegoVideoFrameParam, referenceTimeMillisecond);
        }
    }

    /**
     * 停止推流到ZeGo
     */
    public void stopPublish() {
        Log.i(TAG, "停止推流到ZeGo stopPublish currentStreamId : " + mLiveStatusModel.getCurrentStreamId());
        if (mExpressEngine == null) {
            return;
        }
        // 停止推送
        mExpressEngine.stopPublishingStream();
    }

    /**
     * 开始播放直播
     *
     * @param surfaceView 渲染直播的视图
     */
    public void startLive(SurfaceView surfaceView) {
        Log.i(TAG, "尝试开始播放直播 startLive multiStreamId : " + mLiveStatusModel.getMultiStreamId());
        if (!TextUtils.isEmpty(mLiveStatusModel.getMultiStreamId()) &&
                mLiveStatusModel.getMultiStreamId().startsWith(STREAM_ID_PREFIX)) {
            ZegoCanvas zegoCanvas = new ZegoCanvas(surfaceView);
            zegoCanvas.viewMode = ZegoViewMode.SCALE_TO_FILL;

            ZegoPlayerConfig config = new ZegoPlayerConfig();
            config.roomID = mLiveStatusModel.getMultiRoomId();

            mExpressEngine.startPlayingStream(mLiveStatusModel.getMultiStreamId(), zegoCanvas, config);
        } else {
            Log.e(TAG, "直播ID有误，请重试");
        }
    }

    public void startLive(TextureView textureView) {
        Log.i(TAG, "尝试开始播放直播 startLive multiStreamId : " + mLiveStatusModel.getMultiStreamId());
        if (!TextUtils.isEmpty(mLiveStatusModel.getMultiStreamId()) &&
                mLiveStatusModel.getMultiStreamId().startsWith(STREAM_ID_PREFIX)) {
            ZegoCanvas zegoCanvas = new ZegoCanvas(textureView);
            zegoCanvas.viewMode = ZegoViewMode.SCALE_TO_FILL;

            ZegoPlayerConfig config = new ZegoPlayerConfig();
            config.roomID = mLiveStatusModel.getMultiRoomId();

            mExpressEngine.startPlayingStream(mLiveStatusModel.getMultiStreamId(), zegoCanvas, config);
        } else {
            Log.e(TAG, "直播ID有误，请重试");
        }
    }

    /**
     * 停止播放直播
     */
    public void stopLive(String sn) {
        Log.i(TAG, "尝试停止播放直播 stopLive multiStreamId : " + mLiveStatusModel.getMultiStreamId());
        if (mExpressEngine == null) {
            Log.w(TAG, "ZeGo 引擎未初始化");
            return;
        }
        // 停止播放直播流
        mExpressEngine.stopPlayingStream(mLiveStatusModel.getMultiStreamId());
        mExpressEngine.stopPreview();
        // 退出正在查看的多房间
        logoutMultiRoom(sn);
    }

    /**
     * 销毁即构引擎
     */
    private void destroyEngine() {
        mExpressEngine.enableCustomVideoCapture(false, customVideoCaptureConfig, ZegoPublishChannel.MAIN);
        ZegoExpressEngine.destroyEngine(() -> {
            Log.i(TAG, "销毁ZeGo引擎");
            mLiveStatusModel.setExpressEngineCanUse(false);
        });
    }
}

