package com.ydl.audioim

import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.Paint
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.media.MediaPlayer
import android.net.Uri
import android.os.*
import android.provider.Settings
import android.text.TextUtils
import android.view.View
import android.view.WindowManager
import android.view.animation.AccelerateInterpolator
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.google.gson.Gson
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.XXPermissions
import com.ydl.audioim.bean.AgoraInvitationBean
import com.ydl.audioim.bean.AgoraLogInfoBean
import com.ydl.audioim.contract.IAudioHomeActivityContract
import com.ydl.audioim.http.command.ConnectCommand
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.http.command.NoticePushCommand
import com.ydl.audioim.http.command.PayLoad
import com.ydl.audioim.player.AudioPlayer
import com.ydl.audioim.presenter.AudioHomePresenterImpl
import com.ydl.audioim.router.AudioImIn
import com.ydl.audioim.utils.AudioLogUtils
import com.ydl.audioim.utils.DateUtils
import com.ydl.audioim.utils.onConfideEvent
import com.ydl.audioim.widget.AxbConfirmDialog
import com.ydl.audioim.widget.ZDialog
import com.ydl.webview.H5Params
import com.ydl.webview.NewH5Activity
import com.ydl.webview.RefreshWebEvent
import com.ydl.ydl_av.chat.bean.AudioMessageBean
import com.ydl.ydl_av.voice.listener.IYDLVoiceEventHandler
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydl_image.config.SimpleImageOpConfiger
import com.ydl.ydl_image.manager.YDLImageCacheManager
import com.ydl.ydlcommon.app.Apm
import com.ydl.ydlcommon.base.BaseMvpActivity
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.modular.findRouteService
import com.ydl.ydlcommon.router.YdlCommonRouterManager
import com.ydl.ydlcommon.utils.LogUtil
import com.ydl.ydlcommon.utils.StatusBarUtils
import com.ydl.ydlcommon.utils.Utils
import com.ydl.ydlcommon.utils.actionutil.ActionCountUtils
import com.ydl.ydlcommon.utils.log.AliYunLogConfig
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper
import com.ydl.ydlcommon.utils.log.LogHelper
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.service.IImService
import com.yidianling.user.api.service.IUserService
import de.greenrobot.event.EventBus
import io.agora.rtc.Constants
import io.agora.rtc.IRtcEngineEventHandler
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.audioim_activity_audio_home.*
import java.util.*
import java.util.concurrent.TimeUnit

/**
 * @author jiucheng
 * @描述: 倾诉声网通话页面（拨打电话界面）
 * @Copyright Copyright (c) 2018
 * @Company 壹点灵
 * @date 2018/10/30
 */
@Route(path = "/av/AudioHomeActivity")
class AudioHomeActivity :
    BaseMvpActivity<IAudioHomeActivityContract.View, IAudioHomeActivityContract.Presenter>(),
    IAudioHomeActivityContract.View, SensorEventListener {

    /**
     * 专家头像地址
     */
    private var expertHeadUrl: String? = null

    /**
     * 专家姓名
     */
    private var expertName: String? = null

    /**
     * 专家文案
     */
    private var expertTips: String? = null

    /**
     * 声网点对点聊天房间id
     */
    private var channelId: String? = null

    /**
     * 通话开始时间（接通）
     */
    private var callStartTime: Long? = null

    /**
     * 倾诉剩余时长（时长单位s，eg：剩余2min15s，返回135）
     */
    private var remainTime: String? = null

    /**
     *聆听者id（不是聆听者的uid）
     */
    private var listenId: String? = null

    /**
     * token
     */
    private var token: String? = null

    /**
     * commentUrl 评价页URL
     */
    private var commentUrl: String? = null

    /**
     * callId
     */
    private var callId: String? = null

    /**
     * relation_id
     */
    private var relationId: String? = null

    /**
     * listenerUid专家uid
     */
    private var listenerUid: String? = null

    /**
     * 倾述总时长
     */
    private var totalDuration: Int? = 0

    /**
     * 本地记录的当前剩余时间
     */
    private var localRemainTime: Int? = 0

    /**
     * 挂断电话需要等待时间
     */
    private var onlineCallTime: Long? = 0

    /**
     * 跳转传统电话需要等待时间
     */
    private var traditionCallTime: Long? = 0

    /**
     * 50s自动挂断倒计时
     */
    private var waitDisposable: Disposable? = null

    /**
     * 45s倒计时
     */
    private var disposable: Disposable? = null

    /**
     * 本次倾述倒计时
     */
    private var totalDisposable: Disposable? = null

    /**
     * 是否连接成功
     */
    private var isConnectSuccess: Boolean = false

    //电源管理对象
    private var localPowerManager: PowerManager? = null

    //电源锁
    private var localWakeLock: PowerManager.WakeLock? = null
    private var sensorManager: SensorManager? = null
    private var sendDoctocrMsg: String? = null
    private var axbPhone: String? = null

    //是否跳转到拨号页面
    private var isJumpDail: Boolean = false
    private var isShowAXB: Boolean = true
    private var mPlayer: AudioPlayer? = null
    private var vibrator: Vibrator? = null
    private var handler: Handler? = null
    private var phoneHandler: Handler? = Handler(Looper.getMainLooper())

    //声网
    private var voiceManage: YDLVoiceManager? = null


    //频道管理器
//    private var channelManager: ChannelManager? = null

    private var isLeavelChannel: Boolean = false
    private var hasUpLoadLog = false

    private var callStatus: Int = -1

    /**
     * dialStatus 专家通话状态。
     */
    private var dialStatus: String? = null

    private var mStorageDialog: ZDialog? = null

    private var mHangUpTimeTraditionalDialog: ZDialog? = null

    private var mHangUpTimeOnlineDialog: ZDialog? = null

    private var canHangUp: Boolean = false

    private var canChangeRoute: Boolean = false

    private var hasHandleRefused = false

    private val notificationCallback = object : IMRegisterObserverCustomNotificationCallBack {
        override fun onObserverCustomNotification(fromUid: String, toUid: String, content: String) {
            if (fromUid == listenerUid) {
                try {
                    val bean = Gson().fromJson(content, AgoraInvitationBean::class.java)
                    when (bean.callType) {
                        "2" -> {//接受
                            runOnUiThread {
                                joinChannel()
                            }
                        }
                        "4" -> {//拒绝
                            onCallRefused()
                        }
                    }
                } catch (throwable: Throwable) {
                    LogUtil.e(throwable.message)
                }
            }
        }
    }

    fun onCallRefused() {
        runOnUiThread {
            if (hasHandleRefused) return@runOnUiThread
            hasHandleRefused = true
            YDLavManager.instances.callEndStatusUpdate(channelId ?: "", 2, "被叫拒绝")
            ToastUtil.toastShort("对方已挂断")
            writeAgoraLog("被叫（专家）拒绝了通话邀请")
            //通话结束或挂断时，上传日志文件
            uploadLog()
            leaveChannel()
            uploadExceptionStatus("对方已拒绝", 2)
        }
    }

    /**
     * 声网事件回调 （SDK 通过指定的事件通知应用程序 SDK 的运行事件，如: 加入或离开频道，新用户加入频道等）
     */
    private val mRtcEventHandler = object : IYDLVoiceEventHandler() {

        override fun onUserMuteAudio(uid: Int, muted: Boolean) {
        }

        override fun onWarning(warn: Int) {
            super.onWarning(warn)
            uploadException("mRtcEventHandler-onWarning:warnCode--%${warn}", callback = null)
            LogUtil.e("[agora]发生警告回调$warn")
            writeAgoraLog("声网警告回调($warn)")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "声网警告回调($warn)   channelId:${channelId}")
            //103：没有可用的频道资源。可能是因为服务端没法分配频道资源
            //104：查找频道超时。在加入频道时 SDK 先要查找指定的频道，出现该警告一般是因为网络太差，连接不到服务器
            //105：查找频道请求被服务器拒绝。服务器可能没有办法处理这个请求或请求是非法的
            //106：打开频道超时。查找到指定频道后，SDK 接着打开该频道，超时一般是因为网络太差，连接不到服务器
            //107：打开频道请求被服务器拒绝。服务器可能没有办法处理该请求或该请求是非法的
            // 声网发出警告错误码，不应该直接离开房间

        }

        /**
         * https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
         * */
        override fun onError(err: Int) {
            super.onError(err)
            uploadException("mRtcEventHandler-onError:errorCode--%${err}", callback = null)
            writeAgoraLog("声网错误回调errorCode--%${err}")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err}    channelId:${channelId}")
            //3：SDK 初始化失败。Agora 建议尝试以下处理方法
            //7：SDK 尚未初始化，就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化
            //9：没有操作权限。请检查用户是否授予 app 音视频设备使用权限。
            //10：API 调用超时。有些 API 调用需要 SDK 返回结果，如果 SDK 处理时间过长，超过 10 秒没有返回，会出现此错误
            //17：加入频道被拒绝。一般有以下原因：
            //用户已进入频道，再次调用加入频道的 API，例如 joinChannel，会返回此错误。停止调用该方法即可。
            //用户在做 Echo 测试时尝试加入频道。等待 Echo test 结束后再加入频道即可。
            //101：不是有效的 APP ID。请更换有效的 APP ID 重新加入频道
            //102：不是有效的 频道名。请更换有效的频道名重新加入频道
            //109：当前使用的 Token 过期，不再有效
            //110：生成的 Token 无效
            //123：此用户被服务器禁止
            LogUtil.e("[agora]发生错误回调$err")
            if (err == 0 || err == 18) {
                return
            }
            Apm.reportEvent("agora_android", "occur_error", "$err")
            channelId?.let { YDLavManager.instances.callEndStatusUpdate(it, 4, "频道的错误回调信息$err") }
        }

        override fun onApiCallExecuted(error: Int, api: String?, result: String?) {
            super.onApiCallExecuted(error, api, result)
//            LogUtil.e("[agora]$api 已执行回调 $result")
            //注销原因，产生大量无效数据，会被频繁调用
//            AliYunRichLogsHelper.getInstance()
//                .sendLog(AliYunLogConfig.AGORA, "$api 已执行回调 $result")
        }

        override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onJoinChannelSuccess(channel, uid, elapsed)
            onMeJoined()
            callEventSave("20", "$uid 用户声网加入频道成功:channel=$channel")

            LogUtil.e("[agora]$uid 用户声网加入频道成功:channel=$channel")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "$uid 用户声网加入频道成功:channel=$channel")
            //更新ui
//            onJoinChannelSuccess()

            //更新：现在专家先加入频道，所以不会有等待的过程，
            runOnUiThread {
                writeAgoraLog("主叫加入频道成功")
                //自己加入频道成功
                connectSuccess()
            }

        }

        override fun onRejoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onRejoinChannelSuccess(channel, uid, elapsed)
            callEventSave("70", "$uid 用户声网加入频道成功:channel=$channel")

            LogUtil.e("[agora]$uid 用户声网重新加入频道成功:channel=$channel")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "$uid 用户声网重新加入频道成功:channel=$channel")
            runOnUiThread {
                //自己加入频道成功
                if (!isConnectSuccess) {
                    writeAgoraLog("主叫重新加入频道成功")
                    connectSuccess()
                }
            }
        }


        override fun onRtcStats(stats: IRtcEngineEventHandler.RtcStats?) {
            super.onRtcStats(stats)
            writeAgoraLog("声网onRtcStats：users:${stats?.users}")
//            AliYunRichLogsHelper.getInstance()
//                .sendRichLog(AliYunLogConfig.AGORA, "声网onRtcStats：users:${stats?.users}   channelId:${channelId}")
            // 不需要移动端做离开房间逻辑，服务端会判断进行踢人逻辑
            //因为用户端直接加入了频道，防止该回调执行时，专家还未加入频道，因此在连接成功之后，才进行频道人数判断
//            if (isConnectSuccess && null != stats?.users && stats.users == 1) {
//                writeAgoraLog("通话结束：用户加入了频道，但频道内只有一个人")
//                com.yidianling.common.tools.ToastUtil.toastShort("专家已挂断")
//                //通话结束或挂断时，上传日志文件
//                uploadLog()
//                leaveChannel()
//            }
        }

        /**
         * https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler.html#a31b2974a574ec45e62bb768e17d1f49e
         * */
        override fun onConnectionStateChanged(state: Int, reason: Int) {
            super.onConnectionStateChanged(state, reason)
            // 3 网络连接被服务器中止  该情况现在是因为后端踢人逻辑
            Apm.reportEvent("agora_android", "rtc_connection_failure", "$state,$reason")
            if (reason == 3) {
                callEventSave("50", "通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}")
                writeAgoraLog("通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}）")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(
                        AliYunLogConfig.AGORA,
                        "通话结束：网络连接被服务器中止  该情况现在是因为后端踢人逻辑,原因（${reason}）   channelId:${channelId}"
                    )
//                com.yidianling.common.tools.ToastUtil.toastShort("专家已挂断")
                //通话结束或挂断时，上传日志文件
                uploadLog()
                leaveChannel()
                YDLavManager.instances.callEndStatusUpdate(channelId!!, 4, "服务端踢人触发的回调")
            }
        }

        override fun onLeaveChannel(stats: IRtcEngineEventHandler.RtcStats?) {
            super.onLeaveChannel(stats)
            callEventSave("51", "离开频道回调stats=${stats}")

            LogUtil.e("[agora]离开频道回调")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "离开频道回调  channelId:${channelId}")
            //通话结束或挂断时，上传日志文件
            uploadLog()
        }


        override fun onUserJoined(uid: Int, elapsed: Int) {
            super.onUserJoined(uid, elapsed)
            callEventSave("20", "${uid}加入频道回调")
            LogUtil.e("[agora]远端用户/主播加入频道回调")
            onPeerJoined()
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "远端用户/主播加入频道回调   channelId:${channelId}")
        }

        override fun onUserOffline(uid: Int, elapsed: Int) {
            super.onUserOffline(uid, elapsed)
            callEventSave("51", "uid:${uid}离开频道回调   elapsed:${elapsed}")

            LogUtil.e("[agora]远端用户$uid 离开频道回调")
            writeAgoraLog("接通后通话结束：对方已挂断")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "接通后通话结束：对方已挂断  channelId:${channelId}")
            //通话结束或挂断时，上传日志文件
            uploadLog()
            showToast("专家已挂断")
            //UserOffLine之后，销毁界面，解决，userOffline有回调之后，onConnectionStateChanged(服务端踢人方法没有调)，导致记录时长异常。
            leaveChannel()
            YDLavManager.instances.callEndStatusUpdate(channelId!!, 4, "对方离开频道")

            if (totalDisposable != null) {
                totalDisposable?.dispose()
            }
            handler?.postDelayed({
                //另一方离开频道
                updateExpertStatus(false, 1)
            }, 500)


        }


        //本地音频状态变化
        override fun onLocalAudioStateChanged(localVideoState: Int, error: Int) {
            super.onLocalAudioStateChanged(localVideoState, error)
            writeAgoraLog("本地音频回调$error")
        }

        override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
            super.onNetworkQuality(uid, txQuality, rxQuality)
            LogUtil.e("onNetworkQuality:-------uid=$uid,txQuality=$txQuality,rxQuality=$rxQuality")
            runOnUiThread {
                var status = -1
                var netStatus = when (uid) {
                    0 -> {
                        if (txQuality in 1..2 && rxQuality in 1..2) {
                            ""
                        } else if (txQuality >= 5 || rxQuality >= 5) {
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "您的网络已断开  channelId:${channelId}")
                            "您的网络已断开"
                        } else {
                            status = if (txQuality >= 4 || rxQuality >= 4) {
                                0
                            } else {
                                1
                            }
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "您的网络状况不佳  channelId:${channelId}")
                            "您的网络状况不佳"
                        }
                    }
                    else -> {
                        if (txQuality in 1..2 && rxQuality in 1..2) {
                            ""
                        } else if (txQuality >= 5 || rxQuality >= 5) {
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "对方的网络已断开  channelId:${channelId}")
                            "对方的网络已断开"
                        } else {
                            status = if (txQuality >= 4 || rxQuality >= 4) {
                                0
                            } else {
                                1
                            }
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(AliYunLogConfig.AGORA, "对方的网络状况不佳  channelId:${channelId}")
                            "对方的网络状况不佳"
                        }
                    }
                }
                showNetStatus(netStatus, status)
            }
        }
    }
//

    override fun createPresenter(): IAudioHomeActivityContract.Presenter {
        return AudioHomePresenterImpl()
    }

    override fun layoutResId(): Int {
        return R.layout.audioim_activity_audio_home
    }

    override fun initDataAndEvent() {
        //状态栏颜色
        setWindowStatusBarColor()
        //初始化传感器
        initSensorManager()
        //页面传递数据初始化
        initIntentData()
        callEventSave("20", "用户进入通话页面")

        writeAgoraLog("通话页面打开的时候，RTM登录状态码：${YDLavManager.sdkStatus}")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.RTM, "通话页面打开的时候，RTM登录状态码：${YDLavManager.sdkStatus}   channelId:${channelId}")
        if (YDLavManager.sdkStatus != Constants.CONNECTION_STATE_CONNECTED) {
            //再次登录声网，确保声网登录状态
            reLoginRTM()
        }
        //view初始化
        initView()
        //点击事件
        setClickEvent()
        //权限申请
        requestPermission()
        findRouteService(IImService::class.java).registerObserveCustomNotification(notificationCallback)

        ActionCountUtils.record("call_phone_page", "call_phone_page_visit", listenerUid ?: "0", "1")
    }


    private fun setWindowStatusBarColor() {
        if (Build.VERSION.SDK_INT >= 21) {
            val decorView = window.decorView
            val option = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    or View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
            decorView.systemUiVisibility = option
            window.statusBarColor = Color.TRANSPARENT
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                window.attributes?.layoutInDisplayCutoutMode =
                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
            }
        } else {
            StatusBarUtils.setWindowStatusBarColor(this, R.color.audioim_color_40353535)
        }
    }

    @SuppressLint("InvalidWakeLockTag")
    private fun initSensorManager() {
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager?

        localPowerManager = getSystemService(POWER_SERVICE) as PowerManager?
        localWakeLock = localPowerManager?.newWakeLock(
            PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
            "yidianling"
        )

        // 获取电源管理器对象
        val screenOn = localPowerManager?.isScreenOn
        if (screenOn == false) {
            // 获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
            val wl = localPowerManager?.newWakeLock(
                PowerManager.ACQUIRE_CAUSES_WAKEUP or
                        PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"
            )
            wl?.acquire(10000) // 点亮屏幕
            wl?.release() // 释放
        }

    }

    private fun initIntentData() {
        expertHeadUrl = intent.getStringExtra(IntentConstants.INTENT_EXPERT_HEAD_URL)
        expertName = intent.getStringExtra(IntentConstants.INTENT_EXPERT_NAME)
        expertTips = intent.getStringExtra(IntentConstants.INTENT_EXPERT_TIPS)
        totalDuration = intent.getStringExtra(IntentConstants.INTENT_TOTAL_DURATION).toInt()
        channelId = intent.getStringExtra(IntentConstants.INTENT_ROOM_ID)
        remainTime = intent.getStringExtra(IntentConstants.INTENT_REMAIN_TIME)
        callId = intent.getStringExtra(IntentConstants.INTENT_CALL_ID)
        relationId = intent.getStringExtra(IntentConstants.INTENT_RELATION_ID)
        token = intent.getStringExtra(IntentConstants.INTENT_TOKEN)
        listenerUid = intent.getStringExtra(IntentConstants.INTENT_LISTENER_UID)
        listenId = intent.getStringExtra(IntentConstants.INTENT_LISTEN_ID)
        commentUrl = intent.getStringExtra(IntentConstants.INTENT_COMMENT_URL)
        dialStatus = intent.getStringExtra(IntentConstants.INTENT_DIALSTATUS)
        writeAgoraLog("专家的通话状态dialStatus：$dialStatus", false)
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "专家的通话状态dialStatus：$dialStatus   channelId:${channelId}")
        isShowAXB = intent.getBooleanExtra(IntentConstants.INTENT_ISSHOWAXB, true)

        val logBean = AgoraLogInfoBean(
            expertHeadUrl,
            expertName,
            channelId,
            remainTime,
            listenerUid,
            totalDuration,
            callId,
            listenId
        )
        val content = Gson().toJson(logBean)
        writeAgoraLog("主叫方发送的邀请通话消息内容：$content", true)
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "主叫方发送的邀请通话消息内容：$content    channelId:${channelId}")
        localRemainTime = remainTime?.toInt() ?: 1500
        handler = Handler()

        vibrator = getSystemService(Service.VIBRATOR_SERVICE) as Vibrator?

        var count = 0
        phoneHandler?.postDelayed(object : Runnable {
            override fun run() {
                if (count % 2 == 0) {
                    tv_tips.text = "正在发送倾诉请求…"
                } else {
                    tv_tips.text = "正在等待聆听者接受邀请…"
                }
                count++
                phoneHandler?.postDelayed({ this.run() }, 3000)
            }
        }, 3000)

    }

    private fun reLoginRTM() {
        callEventSave("80", "RMT状态:${YDLavManager.sdkStatus},重新登录RMT")

        writeAgoraLog("RMT状态:${YDLavManager.sdkStatus},重新登录RMT")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.RTM, "RMT状态:${YDLavManager.sdkStatus},重新登录RMTt   channelId:${channelId}")
        val uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        YDLavManager.instances.login(uid) { _isSuccess, _msg ->
//            writeAgoraLog("拨打电话界面打开RTM重新登录，uid=${uid}")
            val result =
                if (_isSuccess) "拨打电话界面打开RMT重新登录成功，uid=${uid}" else "拨打电话界面打开RMT登录失败:$_msg，uid=${uid}"
            writeAgoraLog(result)
        }
    }

    private fun initView() {
        callEventSave("20", "通话页面打开")
        writeAgoraLog("用户拨打电话界面开启")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "用户拨打电话界面开启   channelId:${channelId}")
        //水波纹view初始化
        wave_view.setDuration(6000)
        wave_view.setStyle(Paint.Style.STROKE)
        wave_view.setSpeed(1000)
        wave_view.setColor(Color.WHITE)
        wave_view.setInitialRadius(140f)
        wave_view.setInterpolator(AccelerateInterpolator(1.2f))
        //挂断按钮默认不可点击

        //设置默认关闭扬声器
        iv_hands_free.isSelected = false

        tv_name.text = expertName
//        tv_tips.text = expertTips
        var time = totalDuration?.minus(remainTime!!.toInt())
        tv_remain_time.text = DateUtils.formatTime((time).toString())
        val timeTotal= totalDuration?.div(60);
        tv_totalDuration.text="（满${timeTotal}分钟自动挂断,限24小时内拨打）"
        if (!TextUtils.isEmpty(expertHeadUrl)) {
            var option = SimpleImageOpConfiger()
            option.errorPic = R.drawable.audioim_head_place_hold_pic
            option.loadingPic = R.drawable.audioim_head_place_hold_pic
            option.transform = 0
            YDLImageCacheManager.showImage(this, expertHeadUrl, iv_head, option)
        }

        if (!isShowAXB) {
            ll_changeRoute.visibility = View.GONE
            tv_change_time_counter.visibility = View.GONE
        }
    }

    private fun setClickEvent() {
        //跳转客服小壹
        jump_kefu.setOnClickListener {
            if (!AudioImIn.getUserService().loginByOneKeyLogin(this@AudioHomeActivity,true)) {
                return@setOnClickListener
            }
            val imService = ARouter.getInstance().navigation(IImService::class.java)
            imService?.startKefuChat(this, "", 0, 0)
        }
        //静音开启
        rl_mute_on_off.setOnClickListener {
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "2")
            if (iv_mute_on_off.isSelected) {
                iv_mute_on_off.isSelected = false
                iv_mute_on_off.setImageResource(R.drawable.audiohome_muteoff)
                audio_mute_text.text = "麦克风已关"
                voiceManage?.getVoiceApi()?.enableLocalAudio(false)
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：麦克风已关   channelId:${channelId}")
            } else {
                iv_mute_on_off.isSelected = true
                iv_mute_on_off.setImageResource(R.drawable.audiohome_muteon)
                audio_mute_text.text = "麦克风已开"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：麦克风已开   channelId:${channelId}")
                voiceManage?.getVoiceApi()?.enableLocalAudio(true)
            }
        }
        //切换线路
        ll_changeRoute.setOnClickListener {

            if (!canChangeRoute) {
                showHangUpTimeTraditionalDialog()
                return@setOnClickListener
            }
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：切换线路   channelId:${channelId}")

            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "4")
            showChooseDialog(1)
        }
        //挂断
        iv_hang_up.setOnClickListener {
            if (!canHangUp) {
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：挂断，展示提示弹窗   channelId:${channelId}")
                showHangUpTimeOnlineDialog()
                return@setOnClickListener
            }
            if (Utils.isFastClick()) {
                //防止连击
                return@setOnClickListener
            }
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "1")
            if (isConnectSuccess) {
                writeAgoraLog("已接通：主叫主动挂断")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "已接通：主叫主动挂断   channelId:${channelId}")
                updateExpertStatus(false, 1)
                leaveChannel()
                uploadLog()
                YDLavManager.instances.callEndStatusUpdate(channelId!!, 3, "主叫主动挂断")
                callEventSave("51", "已接通：主叫主动挂断")
            } else {
                userCloseCalling()
            }

            ActionCountUtils.count(
                "shengwang_popup_layer_page|shengwang_popup_layer_refuse_click",
                YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
                uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
            )

        }
        //免提
        iv_hands_free.setOnClickListener {
            ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "3")
            if (iv_hands_free.isSelected) {
                iv_hands_free.isSelected = false
                iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
                hands_free_text.text="扬声器已关"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：免提，扬声器已关   channelId:${channelId}")
            } else {
                iv_hands_free.isSelected = true
                iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free)
                hands_free_text.text="扬声器已开"
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "用户端点击：免提，扬声器已开   channelId:${channelId}")
            }

            //已经接通
            if (isConnectSuccess) {
                //是否开启外放
                voiceManage?.getVoiceApi()?.setEnableSpeakerphone(iv_hands_free.isSelected)
            } else {
                //未接通
                if (mPlayer != null) {
                    mPlayer?.switchPlayType(iv_hands_free.isSelected)
                }
            }
        }
    }

    /**
     * 请求权限
     */
    @SuppressLint("CheckResult")
    private fun requestPermission() {
        try {
            //申请音频权限
            XXPermissions.with(this) // 申请单个权限
                .permission(com.hjq.permissions.Permission.RECORD_AUDIO)
                .request(object : OnPermissionCallback {
                    override fun onGranted(p0: MutableList<String>?, p1: Boolean) {
                        callEventSave("80", "请求音频权限通过")

                        writeAgoraLog("请求音频权限通过")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "请求音频权限通过   channelId:${channelId}")
                        init()
                    }

                    override fun onDenied(permissions: MutableList<String>?, never: Boolean) {
                        // 拒绝权限操作发送给服务端
                        uploadException(
                            "AudioNotAuth",
                            "zhu",
                            YDLavManager.AUDIO_NO_AUTH_ERROR_CODE,
                            null
                        )
                        callEventSave("80", "拒绝请求音频权限")

                        writeAgoraLog("拒绝请求音频权限")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "拒绝请求音频权限   channelId:${channelId}")
                        uploadLog()
                        showStorageDialog()

                    }
                })

        } catch (e: Exception) {
            callEventSave("80", "请求音频权限异常${e.message}")

            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "请求音频权限异常${e.message}   channelId:${channelId}")
            init()
        }

    }

    private fun showStorageDialog() {
        if (mStorageDialog == null) {
            mStorageDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_permission_dialog)
                .setOnClickListener(R.id.cancel_dialog) {
                    mStorageDialog?.dismiss()
                    mStorageDialog = null
                    finish()
                }
                .setAnimation(0)//取消动画
                .setOnClickListener(R.id.dial_right_now) {
                    mStorageDialog?.dismiss()
                    mStorageDialog = null
                    finish()
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    val uri = Uri.fromParts("package", packageName, null)
                    intent.data = uri
                    startActivity(intent)
                }
                .show()
        }
    }

    private fun showHangUpTimeTraditionalDialog() {
        if (mHangUpTimeTraditionalDialog == null) {
            mHangUpTimeTraditionalDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_time_alarm_dialog)
                .setOnClickListener(R.id.dial_right_now) {
                    mHangUpTimeTraditionalDialog?.dismiss()
                    mHangUpTimeTraditionalDialog = null
                }
                .setCancelAble(false)
                .setAnimation(0)//取消动画
                .width((resources.displayMetrics.widthPixels * 0.8f).toInt())
                .show()

            val text = String.format(
                getString(R.string.audioim_audio_time_alarm_msg_tradition_dialog),
                traditionCallTime
            )

            (mHangUpTimeTraditionalDialog?.findDialogView(R.id.third_title) as TextView).text = text
        }
    }

    private fun dismissHangUpTimeTraditionalDialog() {
        if (mHangUpTimeTraditionalDialog != null && mHangUpTimeTraditionalDialog?.isShowing == true) {
            mHangUpTimeTraditionalDialog?.dismiss()
            mHangUpTimeTraditionalDialog = null
        }
    }

    private fun dismissHangUpTimeOnlineDialog() {
        if (mHangUpTimeOnlineDialog != null && mHangUpTimeOnlineDialog?.isShowing == true) {
            mHangUpTimeOnlineDialog?.dismiss()
            mHangUpTimeOnlineDialog = null
        }
    }


    private fun showHangUpTimeOnlineDialog() {
        if (mHangUpTimeOnlineDialog == null) {
            mHangUpTimeOnlineDialog = ZDialog.Builder(this)
                .setContentView(R.layout.audioim_activity_time_alarm_dialog)
                .setOnClickListener(R.id.dial_right_now) {
                    mHangUpTimeOnlineDialog?.dismiss()
                    mHangUpTimeOnlineDialog = null
                }
                .setCancelAble(false)
                .setAnimation(0)//取消动画
                .width((resources.displayMetrics.widthPixels * 0.8f).toInt())
                .show()

            val text = String.format(
                getString(R.string.audioim_audio_time_alarm_msg_online_dialog),
                onlineCallTime
            )
            (mHangUpTimeOnlineDialog?.findDialogView(R.id.third_title) as TextView).text = text
        }
    }


    @SuppressLint("CheckResult", "SetTextI18n")
    private fun init() {
        wave_view.start()
        //初始化声网
        initializeAgoraEngine()
        //发起呼叫
        var msgBean = AudioMessageBean(
            1,
            channelId!!,
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.headUrl,
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.userName,
            remainTime!!.toInt(),
            totalDuration ?: 1500,
            relationId,
            callId,
            null,
            channelId
        )
        sendDoctocrMsg = Gson().toJson(msgBean)

        writeAgoraLog("主叫(用户)发送通话邀请")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "主叫(用户)发送通话邀请$msgBean    channelId:${channelId}")
        rtcCall()

        //开始50s等待倒计时
        waitDisposable =
            Observable.interval(0, 100, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.computation())
                .take(600).observeOn(AndroidSchedulers.mainThread()).subscribe({
                    val remainTime = 50 - it / 10
                    traditionCallTime = remainTime
                    if (remainTime <= 0) {
                        dismissHangUpTimeTraditionalDialog()
                        waittingStatus()
                    } else {
                        tv_change_time_counter.text = "转传统电话（${remainTime}s）"
                        if (mHangUpTimeTraditionalDialog != null && mHangUpTimeTraditionalDialog?.isShowing == true) {
                            val callTime = String.format(
                                getString(R.string.audioim_audio_time_alarm_msg_tradition_dialog),
                                traditionCallTime
                            )
                            (mHangUpTimeTraditionalDialog?.findDialogView(R.id.third_title) as TextView).text =
                                callTime
                        }
                    }

                    onlineCallTime = remainTime - 20
                    if (remainTime <= 20) {
                        audio_hangup_text.text = "挂断"
                        dismissHangUpTimeOnlineDialog()
                    } else {
                        audio_hangup_text.text = "挂断(${remainTime - 20}s)"
                        if (mHangUpTimeOnlineDialog != null && mHangUpTimeOnlineDialog?.isShowing == true) {
                            val callTime = String.format(
                                getString(R.string.audioim_audio_time_alarm_msg_online_dialog),
                                onlineCallTime
                            )
                            (mHangUpTimeOnlineDialog?.findDialogView(R.id.third_title) as TextView).text =
                                callTime
                        }
                    }
                    var result = it.toFloat() / 3f
                    progress_view.setProgress(result)
                    if (result >= 100f && !canHangUp) {
                        audio_hangup_text.text = "挂断"
                        //挂断按钮可点击
                        canHangUp = true
                        iv_hang_up.setImageResource(R.drawable.audioim_img_hang_up)
                    }

                }, {
                    callEventSave("80", "倒计时异常${it.message}")

                    LogUtil.d(it.message)
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "倒计时异常${it.message}    channelId:${channelId}")

                    dismissHangUpTimeOnlineDialog()

                    dismissHangUpTimeTraditionalDialog()
                }) {
                    //                    waittingStatus()
                    if (!isConnectSuccess) {
                        //关闭音乐


                        dismissHangUpTimeOnlineDialog()

                        dismissHangUpTimeTraditionalDialog()

                        stopPlaying()
                        callEventSave("34", "未接通挂断：50s等待倒计时结束挂断")

                        writeAgoraLog("未接通挂断：50s等待倒计时结束挂断")
                        AliYunRichLogsHelper.getInstance()
                            .sendRichLog(AliYunLogConfig.AGORA, "未接通挂断：50s等待倒计时结束挂断    channelId:${channelId}")
                        //提示切换传统线路
                        //发送消息通知专家用户已挂断
                        YDLavManager.instances.cancelCall(
                            listenerUid!!,
                            channelId!!,
                            sendDoctocrMsg!!
                        ) { msg, code ->
                            callEventSave("51", "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")

                            writeAgoraLog("未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")
                            AliYunRichLogsHelper.getInstance()
                                .sendRichLog(
                                    AliYunLogConfig.AGORA,
                                    "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断    channelId:${channelId}"
                                )
                        }
                        //通话结束或挂断时，上传日志文件
                        uploadLog()

                        showToast("暂时无法接通，建议稍后尝试")
                        userCloseCalling()
                    }
                }

        //双重保险：加入频道成功，通过服务端发推送给专家
        noticeServerPush(true)
    }

    fun rtcCall() {
        YDLavManager.instances.rtcCall(listenerUid, channelId, sendDoctocrMsg)
        onStartCall()
    }

    /**
     * 声网初始化
     */
    private fun initializeAgoraEngine() {
        /**
         * 创建一个实例
         * param appId            应用id
         * param mRtcEventHandler 事件回调（SDK 通过指定的事件通知应用程序 SDK 的运行事件，如: 加入或离开频道，新用户加入频道等）
         */
        voiceManage = YDLVoiceManager(this, BuildConfig.AGORA_APPID, mRtcEventHandler)
        voiceManage?.init()
        voiceManage?.getVoiceApi()?.setAudioProfile(Constants.AUDIO_PROFILE_DEFAULT,Constants.AUDIO_SCENARIO_CHATROOM_GAMING)
    }

    /**
     * 声网加入频道
     */
    fun joinChannel() {
        callEventSave("20", "对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")

        writeAgoraLog("对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "对方（专家）接受了通话邀请，主叫（用户）开始加入频道：$channelId")
        voiceManage?.getVoiceApi()?.joinChannel(
            token!!,
            channelId!!,
            "Extra Optional Data",
            YdlCommonRouterManager.getYdlCommonRoute().getUid()
        )
    }

    /**
     * 用户主动挂断（包括：60s专家未接听自动挂断）
     * 注意：这个方法只在专家还未接听的状态才能调用
     *
     */
    private fun userCloseCalling() {
        callEventSave("32", "未接听时：主叫（用户）主动挂断，取消呼叫")

        writeAgoraLog("未接听时：主叫（用户）主动挂断，取消呼叫")
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫（用户）主动挂断，取消呼叫   channelId:${channelId}")
        LogUtil.e("未接听挂断")
        //发送消息通知专家用户已挂断
        YDLavManager.instances.cancelCall(
            listenerUid!!,
            channelId!!,
            sendDoctocrMsg!!
        ) { msg, code ->
            callEventSave("51", "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")

            writeAgoraLog("未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断")
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫（用户）主动挂断失败，msg=$msg($code)，再次挂断    channelId:${channelId}")
        }
        //通话结束或挂断时，上传日志文件
        uploadLog()
        handler?.postDelayed({
            LogUtil.e("离开频道")
            leaveChannel()
        }, 100)
    }

    /**
     * 更新专家状态
     *@param isSwitchAxb 是否切换axb
     * @param finishStatus 状态值：     0：开始         1：结束
     */
    private fun updateExpertStatus(isSwitchAxb: Boolean, finishStatus: Int) {
        if (isSwitchAxb) {
            dialPhone()
        }

        if (finishStatus == 0) {
            callStartTime = System.currentTimeMillis()
        }
    }

    /**
     * 线路选择弹窗
     */
    private fun showChooseDialog(type: Int) {
        val dialog =
            AxbConfirmDialog(mContext, type, object : AxbConfirmDialog.OnClickEnsureListener {
                override fun onClickEnsure() {
                    callEventSave("80", "主叫点击切换AXB按钮")

                    writeAgoraLog("主叫点击切换AXB按钮")
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "主叫点击切换AXB按钮   channelId:${channelId}")
                    switchAXB()
                }

                override fun onClose() {
                    // 如果声网未连接成功，切换axb的弹框是自动弹出的，当关闭弹框的时候，执行用户挂断操作
                    // 如果声网连接成功，点击右上角按钮弹出切换axb弹框，但是关闭时用户不执行挂断操作
                    if (!isConnectSuccess) {
                        userCloseCalling()
                    }
                }
            })
        dialog.show()
    }

    /**
     * 切换成axb路线请求
     */
    private fun switchAXB() {
        if (isConnectSuccess) {
            uploadException("", "zhu", "108", object : YDLavManager.UploadExceptionCallback {
                override fun onSuccess() {
                    callEventSave("80", "离开房间成功,主叫切换AXB之后")

                    writeAgoraLog("离开房间成功,主叫切换AXB之后")
                    AliYunRichLogsHelper.getInstance()
                        .sendRichLog(AliYunLogConfig.AGORA, "离开房间成功,主叫切换AXB之后    channelId:${channelId}")
                    mPresenter.getAXBPhone(ConnectCommand(listenId!!, "1"))
                }

            })
            YDLavManager.instances.callEndStatusUpdate(channelId!!, 3, "接通中：主叫主动切换AXB")

        } else {
            mPresenter.getAXBPhone(ConnectCommand(listenId!!, "1"))
        }
    }

    /**
     * 切换axb网络请求结果:axb电话
     *w
     */
    override fun switchAXBResponse(axbPhone: String) {
        this.axbPhone = axbPhone
        isJumpDail = true
        if (isConnectSuccess) {
            //通话结束或挂断时，上传日志文件
            uploadLog()
            //已经连接成功，切换axb时需要更新专家状态
            updateExpertStatus(true, 1)
        } else {
            //未连接成功，切换axb时：需发送消息通知专家端用户已挂断
            //发送消息通知专家用户已挂断
            //发送消息通知专家用户已挂断
            YDLavManager.instances.cancelCall(
                listenerUid!!,
                channelId!!,
                sendDoctocrMsg!!
            ) { msg, code ->
                callEventSave("51", "未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断")

                writeAgoraLog("未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断")
                AliYunRichLogsHelper.getInstance()
                    .sendRichLog(AliYunLogConfig.AGORA, "未接听时：主叫主动挂断失败，msg=$msg($code)，再次挂断   channelId:${channelId}")
            }
            leaveChannel()
        }
    }


    /**
     * 跳转拨号界面
     */
    override fun dialPhone() {
        var phoneIntent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$axbPhone"))
        startActivity(phoneIntent)
        finish()
    }


    /**
     * 60s等待完成，专家未接听
     */
    private fun waittingStatus() {
        tv_change_time_counter.visibility = View.GONE
        //挂断按钮可点击
        canHangUp = true
        iv_hang_up.setImageResource(R.drawable.audioim_img_hang_up)
//        if (!isConnectSuccess) {
//            //页面等待文案调整
//            tv_waiting.visibility = View.GONE
//            tv_change_doctor.text = "对方暂无应答，正在为您切换线路重播"
//            tv_change_doctor.visibility = View.VISIBLE
//        }
        if (!isShowAXB) {
            ll_changeRoute.visibility = View.GONE
        } else {
            //切换线路按钮可见
            canChangeRoute = true
        }

    }

    /**
     * 播放等待音频
     */
    fun playWaitingMusic() {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        if ((Math.random() * 10 + 1).toInt() >= 5) {
            mPlayer?.setTwoDataAndStart(R.raw.audioim_audio_music_1, R.raw.audioim_loop_music)
        } else {
            mPlayer?.setTwoDataAndStart(R.raw.audioim_audio_music_2, R.raw.audioim_loop_music)
        }
    }

    /**
     * 播放结束音频，音频播放结束后，自动关闭页面
     */
    private fun playFinishMusic() {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        mPlayer?.setDataSource(R.raw.audioim_hand_down_music)
        mPlayer?.switchPlayType(iv_hands_free.isSelected)
        mPlayer?.setCompletionListener(MediaPlayer.OnCompletionListener {
            LogUtil.e("播放结束")
            //通话剩余时间不足60s时，默认
            if (localRemainTime!! <= 60 && !TextUtils.isEmpty(
                    commentUrl
                )
            ) {
                val h5Params = H5Params(commentUrl!!, "评价")
                NewH5Activity.start(this@AudioHomeActivity, h5Params)
            }
            if (isJumpDail) {
                //跳转拨号界面
                dialPhone()
            }
            finish()
        })
        mPlayer?.start(false, true)
    }

    /**
     * 停止播放
     */
    private fun stopPlaying() {
        if (mPlayer != null) {
            mPlayer?.pause()
        }
    }

    /**
     * sdk通话链接成功
     */
    private fun connectSuccess() {
        isConnectSuccess = true
        phoneHandler?.removeCallbacksAndMessages(null)
        //通知服务端，此次通话已经接通，服务端开始订单
        updateExpertStatus(false, 0)
        //是否开启外放
        voiceManage?.getVoiceApi()?.setEnableSpeakerphone(false)

        if (iv_mute_on_off.isSelected) {
            iv_mute_on_off.setImageResource(R.drawable.audiohome_muteoff)
            audio_mute_text.text = "麦克风已关"
        } else {
            iv_mute_on_off.isSelected = true
            iv_mute_on_off.setImageResource(R.drawable.audiohome_muteon)
            audio_mute_text.text = "麦克风已开"
        }

        hands_free_text.text="扬声器已关"
        iv_hands_free.isSelected = false
        iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
        disposable?.dispose()

        stopPlaying()
        vibrator?.vibrate(1000)

        //等待状态的相关ui隐藏(挂断按钮的倒计时不清除，挂断按钮必须在30s后才能点击)
        tv_change_doctor.visibility = View.GONE
        tv_tips.visibility = View.GONE
        //显示通话相关ui
        rl_remain_time.visibility = View.VISIBLE

        showToast("已接通")

        tv_tips.visibility = View.GONE

        //剩余倾诉时长倒计时
        totalDisposable =
            Observable.interval(0, 1, TimeUnit.SECONDS)
                .subscribeOn(Schedulers.computation())
                .take(remainTime!!.toLong() + 1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    localRemainTime = remainTime!!.toInt().minus(it.toInt())

                    if (localRemainTime == 180) {
                        //三分钟语音播报
                        playNoticeMusic(3)
                    }
                    if (localRemainTime == 60) {
                        //一分钟语音播报
                        playNoticeMusic(1)
                    }
                    if (localRemainTime!! <=60) {
                        if (canChangeRoute) {
                            canChangeRoute = false
                        }
                    }
                    tv_remain_time.text = DateUtils.formatTime(localRemainTime.toString())
                }, {
                    LogUtil.d(it.message)
                }, {
                    leaveChannel()
                    uploadLog()
                    callEventSave("50", "倾诉时间已用完")
                    YDLavManager.instances.callEndStatusUpdate(channelId!!, 3, "倾诉时间已用完")
                    //注意：自动挂断时，如果对方离开频道的回调已经触发，就不要再重复调用接口
                    showToast("通话已结束")
                    //通话结束或挂断时，上传日志文件
                    uploadLog()
                    updateExpertStatus(false, 1)
                })
    }

    /**
     * 剩余3min和1min时提示音
     * @param min 1 ：还剩1min   3：还剩3min
     *
     */
    private fun playNoticeMusic(min: Int) {
        if (mPlayer == null) {
            mPlayer = AudioPlayer(this)
        }
        when (min) {
            0 -> {
                //结束音
                mPlayer?.setDataSource(R.raw.audioim_audio_out_channel)
            }

            1 -> {
                //1分钟提示
                mPlayer?.setDataSource(R.raw.audioim_last_1_min)
            }
            3 -> {
                //3分钟提示
                mPlayer?.setDataSource(R.raw.audioim_last_3_min)
            }
        }

        mPlayer?.switchPlayType(iv_hands_free.isSelected)
        mPlayer?.start(false, false)
    }

    /**
     * 用户加入频道后
     *通知服务端发送推送
     * 通知专家加入频道
     * 这个功能已经有用信令通知，为了解决专家信令掉线的问题，增加推送逻辑
     *
     * @param isCall true 拨打   false 取消拨打
     */
    private fun noticeServerPush(isCall: Boolean) {
        var msgBean = AudioMessageBean(
            1,
            channelId!!,
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.headUrl,
            YdlCommonRouterManager.getYdlCommonRoute().getUserInfo()!!.userName,
            remainTime!!.toInt(),
            totalDuration ?: 1500,
            relationId,
            callId,
            null,
            channelId
        )
        var cmd = NoticePushCommand()
        cmd.data = msgBean
        cmd.pushId = listenerUid
        if (isCall) {
            cmd.status = "CALL"
        } else {
            cmd.status = "CALL_OFF"
        }
        AliYunRichLogsHelper.getInstance()
            .sendRichLog(AliYunLogConfig.AGORA, "用户加入频道后,通知服务端发送推送   channelId:${channelId}")
        mPresenter.noticeServerPush(cmd)
    }

    /**
     * 声网离开频道
     */
    fun leaveChannel() {
        LogUtil.e("调用leaveChannel方法，isLeavelChannel=$isLeavelChannel")
        if (!isLeavelChannel) {
            isLeavelChannel = true
            playNoticeMusic(0)
            //刷新h5页面
            EventBus.getDefault().post(RefreshWebEvent(false))
            stopPlaying()
            LogUtil.e("播放结束音频")
            //播放结束音频
            playFinishMusic()
        }
    }

    override fun onResume() {
        super.onResume()
        sensorManager?.registerListener(
            this,
            sensorManager?.getDefaultSensor(Sensor.TYPE_PROXIMITY),
            SensorManager.SENSOR_DELAY_NORMAL
        )
        ActionCountUtils.count(
            "shengwang_popup_layer_page|shengwang_popup_layer_page_visit",
            "",
            uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        )
    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
    }

    override fun onSensorChanged(event: SensorEvent?) {
        val values = event!!.values
        when (event.sensor.type) {
            Sensor.TYPE_PROXIMITY -> {
                if (values[0] == 0.0f) {
                    //贴近手机
                    if (localWakeLock?.isHeld == false) {
                        localWakeLock?.acquire()
                    }
                } else {
                    //离开手机
                    //唤醒设备
                    if (localWakeLock?.isHeld == true) {
                        localWakeLock?.release()
                    }
                }
            }
        }
    }

    /**
     * 显示自定义弹窗
     */
    private fun showToast(msg: String?) {
        runOnUiThread {
            ToastHelper.show(msg ?: "")
        }
    }

    /**
     * 网络状态
     */
    private fun showNetStatus(msg: String, status: Int = 0) {
        LogUtil.e("showNetStatus: msg=$msg,status=$status")
        if (tv_nte_status.visibility == View.VISIBLE) {
            return
        }
        if (TextUtils.isEmpty(msg)) {
            tv_nte_status.visibility = View.GONE
        } else {
            tv_nte_status.text = msg
            if (status == 0) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(
                        this,
                        R.drawable.av_audio_wifi_normal
                    ), null, null, null
                )
            }
            if (status == 1) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(
                        this,
                        R.drawable.av_audio_wifi_better
                    ), null, null, null
                )
            }
            if (status == -1) {
                tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
            }
            tv_nte_status.visibility = View.VISIBLE
            tv_nte_status.postDelayed({
                tv_nte_status.visibility = View.GONE
            }, 2000)
        }
    }

    override fun showProgressView() {
        try {
            showProgressDialog()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun dismissProgressView() {
        try {
            dismissProgressDialog()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun uploadLog() {
        if (!hasUpLoadLog) {
            hasUpLoadLog = true
            LogHelper.getInstance().uploadLog(false)
        }
    }

    fun uploadExceptionStatus(msg: String, status: Int) {
        callStatus = status
        uploadException(msg, zhu = "zhu", eventType = "108", callback = null)
    }

    /**
     * 上传错误日志
     * zhu 洪平要的，判别是移动端主动调的还是声网返的
     */
    private fun uploadException(
        message: String,
        zhu: String = "",
        eventType: String = "99",
        callback: YDLavManager.UploadExceptionCallback?
    ) {
        var time: String = (System.currentTimeMillis() / 1000).toString()
        var uid: String =
            ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid!!
        var payLoad = PayLoad(channelId ?: "0", time, uid, "1", "999", message)
        var connectException =
            ConnectExceptionCommand(time + zhu, "2", eventType, payLoad, callStatus)
        YDLavManager.instances.uploadException(connectException, callback)
    }

    fun writeAgoraLog(content: String, isAppend: Boolean = true) {
        try {
            AudioLogUtils.writeAgoraLog(
                "$content-------Time:${AudioLogUtils.format.format(Calendar.getInstance().time)}",
                "confide.log",
                isAppend
            )
        } catch (e: Exception) {
        }
    }

    override fun finishActivity() {
        leaveChannel()
    }

    override fun onDestroy() {
        super.onDestroy()
        findRouteService(IImService::class.java).unregisterObserveCustomNotification(notificationCallback)
        uploadLog()
        phoneHandler?.removeCallbacksAndMessages(null)
        if (isConnectSuccess) {
            uploadException("", "zhu", "108", callback = null)
        }
        if (handler != null) {
            handler = null
        }

        if (phoneHandler != null) {
            phoneHandler = null
        }

        hasUpLoadLog = false

        if (waitDisposable != null) {
            waitDisposable?.dispose()
        }
        if (disposable != null) {
            disposable?.dispose()
        }
        if (totalDisposable != null) {
            totalDisposable?.dispose()
        }
        if (sensorManager != null) {
            sensorManager?.unregisterListener(this)
        }
        //唤醒设备
        if (localWakeLock != null && localWakeLock!!.isHeld) {
            localWakeLock?.release()
        }
        sensorManager = null
        localWakeLock = null
        localPowerManager = null

        if (null != voiceManage && null != voiceManage?.getVoiceApi()) {
            voiceManage?.getVoiceApi()?.leaveChannel()
            voiceManage?.getVoiceApi()?.destroy()
            voiceManage = null
        }

        if (mPlayer != null) {
            mPlayer?.clear()
            mPlayer = null
        }
    }

    //重写物理返回按钮
    override fun onBackPressed() {
    }

    /**
     *  倾诉日志
     * @param session 通话业务id
     * @param status 状态:01通话中(不影响通话的事件) 10:拨打 20未拨通 30未接通 40 接通 50挂断 60断线 70重连 80 呼叫方信号 90 被呼叫方信号
     * @param res 上报的详细
     * @param line 载体:1.网易 2.中国移动(双呼)3.联通 4.华为 5.糖猫-联通 7:声网 8:微信 10:新移动
     * */
    fun callEventSave(
        status: String,
        res: String,
        session: String? = channelId,
        line: String = "7"
    ) {
        YDLavManager.instances.callEventSave(status, res, session, line)
    }

    private fun onStartCall() {
        val dimension = hashMapOf("conversation" to "start_call", "call" to "call_start")
        onConfideEvent(dimension, channelId)
    }

    private fun onMeJoined() {
        val dimension = hashMapOf("conversation" to "me_joined")
        onConfideEvent(dimension, channelId)
    }

    fun onPeerAccepted() {
        val dimension = hashMapOf("conversation" to "peer_accepted", "call" to "call_accepted")
        onConfideEvent(dimension, channelId)
    }

    private fun onPeerJoined() {
        val dimension = hashMapOf("conversation" to "peer_joined")
        onConfideEvent(dimension, channelId)
    }
}
