ConsultantAudioHomeActivity.kt 37.9 KB
Newer Older
严久程 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package com.ydl.consultantim

import android.Manifest
import android.annotation.SuppressLint
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.net.Uri
import android.os.PowerManager
import android.provider.Settings
YKai committed
16
import androidx.core.content.ContextCompat
严久程 committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30
import android.text.TextUtils
import android.view.View
import android.view.animation.AccelerateInterpolator
import com.alibaba.android.arouter.facade.annotation.Route
import com.alibaba.android.arouter.launcher.ARouter
import com.google.gson.Gson
import com.tbruyelle.rxpermissions2.RxPermissions
import com.ydl.audioim.BuildConfig
import com.ydl.audioim.R
import com.ydl.audioim.YDLavManager
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.http.command.PayLoad
import com.ydl.audioim.player.AudioPlayer
import com.ydl.audioim.utils.AudioLogUtils
严久程 committed
31
import com.ydl.audioim.utils.DateUtils
严久程 committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
import com.ydl.consultantim.contract.IConsultantAudioHomeActivityContract
import com.ydl.consultantim.event.AudioHomeEvent
import com.ydl.consultantim.presenter.ConsultantAudioHomePresenterImpl
import com.ydl.consultantim.utils.ConsultantAudioUtils
import com.ydl.consultantim.utils.VibratorUtil
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.base.BaseMvpActivity
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.ydl.ydlcommon.router.YdlCommonRouterManager
import com.ydl.ydlcommon.utils.ActivityManager
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
50
import com.ydl.ydlcommon.utils.log.AliYunLogConfig
51
import com.ydl.ydlcommon.utils.log.AliYunRichLogsHelper
严久程 committed
52 53 54 55
import com.ydl.ydlcommon.utils.log.LogHelper
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.yidianling.user.api.service.IUserService
import de.greenrobot.event.EventBus
严久程 committed
56
import io.agora.rtc.Constants
严久程 committed
57 58
import io.agora.rtc.IRtcEngineEventHandler
import io.reactivex.Observable
严久程 committed
59
import io.reactivex.android.schedulers.AndroidSchedulers
严久程 committed
60 61 62
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.audioim_cativity_consultant_audio_home.*
YKai committed
63
import java.util.*
严久程 committed
64
import java.util.concurrent.TimeUnit
严久程 committed
65 66 67

/**
 * @author jiucheng
YKai committed
68
 * @描述: 咨询声网通话页面(用户接受电话界面)
严久程 committed
69 70 71 72
 * @Copyright Copyright (c) 2018
 * @Company 壹点灵
 * @date 2018/10/30
 */
严久程 committed
73
@Route(path = "/av/ConsultantAudioHomeActivity")
74 75 76
class ConsultantAudioHomeActivity :
    BaseMvpActivity<IConsultantAudioHomeActivityContract.View, IConsultantAudioHomeActivityContract.Presenter>(),
    IConsultantAudioHomeActivityContract.View, SensorEventListener {
严久程 committed
77 78 79

    //语音管理类
    private var voiceManage: YDLVoiceManager? = null
80

严久程 committed
81 82
    //音视频数据
    private var mAudioMessageBean: AudioMessageBean? = null
83

严久程 committed
84 85
    //音频播放
    private var mPlayer: AudioPlayer? = null
86

严久程 committed
87 88
    //当前状态 0.未接听 1.已接听
    public var status = STATUS_NOT_ANSWERED
89

严久程 committed
90 91
    //电源管理对象
    private var localPowerManager: PowerManager? = null
92

严久程 committed
93 94 95 96 97 98 99 100
    //电源锁
    private var localWakeLock: PowerManager.WakeLock? = null
    private var sensorManager: SensorManager? = null

    /**
     * 通话开始时间(接通)
     */
    private var callStartTime: Long? = null
101

严久程 committed
102 103 104 105
    /**
     * 本次倾述倒计时
     */
    private var totalDisposable: Disposable? = null
严久程 committed
106
    private var connectingStatusDisposable: Disposable? = null
严久程 committed
107 108

    //频道管理器
109
    //    private var channelManager: ChannelManager? = null
严久程 committed
110 111 112 113

    //频道token
    private var channelToken: String? = null
    private var hasUpLoadLog = false
114
    private var callStatus: Int = -1
严久程 committed
115
    private var userId = -1
严久程 committed
116 117 118 119 120

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

严久程 committed
122 123 124 125 126 127 128 129 130 131 132
    /**
     * 事件回调 (SDK 通过指定的事件通知应用程序 SDK 的运行事件,如: 加入或离开频道,新用户加入频道等)
     */
    private val mRtcEventHandler = object : IYDLVoiceEventHandler() {

        /**
         * 远端用户静音回调
         * @param uid 用户 ID
         * @param muted 该用户是否静音:true: 该用户已静音音频 false: 该用户已取消音频静音
         */
        override fun onUserMuteAudio(uid: Int, muted: Boolean) {
严久程 committed
133 134 135
//            runOnUiThread {
//                showToast("对方静音了,提醒他打开!")
//            }
严久程 committed
136 137 138 139 140
        }

        override fun onJoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onJoinChannelSuccess(channel, uid, elapsed)
            LogUtil.e("[agora]$uid 加入频道回调")
YKai committed
141
            writeAgoraLog("被叫(用户)加入声网($channel)频道成功")
142
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "被叫(用户)加入声网($channel)频道成功")
严久程 committed
143
            runOnUiThread {
严久程 committed
144
                // 加入频道后再通知用户已接受
145
                //        YDLRTMClient.instances.acceptCall(mAudioMessageBean?.channelId)
146 147 148 149 150
                YDLavManager.instances.acceptCall(
                    mAudioMessageBean!!.userId!!,
                    mAudioMessageBean?.channelId,
                    Gson().toJson(mAudioMessageBean)
                )
严久程 committed
151

严久程 committed
152 153
                tv_toast.visibility = View.VISIBLE
                tv_toast.text = "连接中..."
严久程 committed
154 155 156 157

                voiceManage!!.getVoiceApi().setEnableSpeakerphone(false)

                connectingStatusWaitingTimeCount()
158

159
                tv_tips.visibility = View.INVISIBLE
严久程 committed
160 161 162
            }
        }

严久程 committed
163 164 165 166 167 168
        /**
         * 重新加入频道回调
         */
        override fun onRejoinChannelSuccess(channel: String?, uid: Int, elapsed: Int) {
            super.onRejoinChannelSuccess(channel, uid, elapsed)
            LogUtil.e("[agora]$uid 重新加入频道回调")
YKai committed
169
            writeAgoraLog("被叫(用户)重新加入声网频道($channel)成功")
170 171
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "被叫(用户)重新加入声网频道($channel)成功")
172

严久程 committed
173 174 175 176 177 178 179 180 181 182 183 184 185
            runOnUiThread {
                if (!isConnectSuccess) {
                    tv_toast.visibility = View.VISIBLE
                    tv_toast.text = "连接中..."


                    voiceManage!!.getVoiceApi().setEnableSpeakerphone(false)

                    connectingStatusWaitingTimeCount()
                }
            }
        }

严久程 committed
186 187 188
        override fun onUserJoined(uid: Int, elapsed: Int) {
            super.onUserJoined(uid, elapsed)
            LogUtil.e("[agora]远端用户加入频道回调")
YKai committed
189
            writeAgoraLog("主叫(专家)加入声网频道成功")
190
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "主叫(专家)加入声网频道成功")
191

严久程 committed
192 193
            //另一方加入频道成功
            runOnUiThread {
严久程 committed
194
                isConnectSuccess = true
严久程 committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
                //通话开始,刷新ui开始倒计时
                updateStartUi()
                status = STATUS_ANSWERED
                //接通开始回调
                callStartTime = System.currentTimeMillis()
            }
        }

        override fun onRtcStats(stats: IRtcEngineEventHandler.RtcStats?) {
        }

        override fun onConnectionStateChanged(state: Int, reason: Int) {
            super.onConnectionStateChanged(state, reason)
            // 3 网络连接被服务器中止  该情况现在是因为后端踢人逻辑
            if (reason == 3) {
严久程 committed
210
                showToast("对方已挂断")
211 212 213 214 215
                YDLavManager.instances.callEndStatusUpdate(
                    mAudioMessageBean?.channelId!!,
                    4,
                    "服务端踢人触发的回调"
                )
216

YKai committed
217
                writeAgoraLog("通话挂断:网络连接被服务器(后端)中止")
严久程 committed
218 219
                //通话结束或挂断时,上传日志文件
                uploadLog()
YKai committed
220 221 222
//                leaveChannel()
//                finish()
                close(RESULT_ANSWERED_CODE, "")
严久程 committed
223 224 225 226 227 228 229 230 231 232
            }
        }

        /**
         * 离开频道回调(自己)
         *
         */
        override fun onLeaveChannel(stats: IRtcEngineEventHandler.RtcStats?) {
            super.onLeaveChannel(stats)
            LogUtil.e("[agora]自己离开频道回调")
233
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "自己离开频道回调")
234

YKai committed
235 236
            //通知php 通话已结束
            close(RESULT_ANSWERED_CODE, "")
严久程 committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
        }

        /**
         * 主播离开频道回调
         * 提示有主播离开了频道(或掉线)。
         * SDK 判断用户离开频道(或掉线)的依据是超时:在一定时间内(20 秒)没有收到对方的任何数据包,判定为对方掉线。
         * 在网络较差的情况下,可能会有误报。建议可靠的掉线检测应该由信令来做
         * @param uid 主播 ID
         * @param reason 离线原因:
         *                         USER_OFFLINE_QUIT(0):用户主动离开
         *                         USER_OFFLINE_DROPPED(1):因过长时间收不到对方数据包,超时掉线。注意:由于 SDK 使用的是不可靠通道,也有可能对方主动离开本方没收到对方离开消息而误判为超时掉线
         *                         USER_OFFLINE_BECOME_AUDIENCE(2):用户身份从主播切换为观众(直播模式下)
         */
        override fun onUserOffline(uid: Int, elapsed: Int) {
            super.onUserOffline(uid, elapsed)
            LogUtil.e("[agora]$uid 主播离开频道回调")
            runOnUiThread {
254 255 256 257 258
                YDLavManager.instances.callEndStatusUpdate(
                    mAudioMessageBean?.channelId!!,
                    4,
                    "对方离开频道"
                )
严久程 committed
259
                showToast("对方已挂断")
YKai committed
260
                writeAgoraLog("通话接通后挂断:主叫(专家)离开频道")
261
                AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "通话接通后挂断:主叫(专家)离开频道")
262

严久程 committed
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
                if (null != totalDisposable) {
                    totalDisposable!!.dispose()
                }
                //通知php 通话已结束
                close(RESULT_ANSWERED_CODE, "")
            }
        }

        override fun onWarning(warn: Int) {
            super.onWarning(warn)
            // 过滤1031 录制声音模糊
            if (warn != 1031) {
                uploadException("mRtcEventHandler-onWarning:warnCode--%${warn}")
            }
            LogUtil.e("[agora]发生警告回调=$warn")
YKai committed
278
            writeAgoraLog("声网警告回调码:($warn)")
279
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "声网警告回调码:($warn)")
280

严久程 committed
281 282 283 284 285
            //103:没有可用的频道资源。可能是因为服务端没法分配频道资源
            //104:查找频道超时。在加入频道时 SDK 先要查找指定的频道,出现该警告一般是因为网络太差,连接不到服务器
            //105:查找频道请求被服务器拒绝。服务器可能没有办法处理这个请求或请求是非法的
            //106:打开频道超时。查找到指定频道后,SDK 接着打开该频道,超时一般是因为网络太差,连接不到服务器
            //107:打开频道请求被服务器拒绝。服务器可能没有办法处理该请求或该请求是非法的
286 287 288 289 290 291 292 293 294 295 296 297 298
            // 声网发出警告错误码,不应该直接离开房间
//            runOnUiThread {
//                when (warn) {
//                    103, 105, 107 -> {
//                        YDLavManager.instances.callEndStatusUpdate(mAudioMessageBean?.channelId!!, 4, "收到频道回调警告信息${warn}")
//                        writeAgoraLog("通话挂断:网络异常($warn)")
//                        showToast("当前网络较差,请更换网络!")
//                        //通话结束或挂断时,上传日志文件
//                        uploadLog()
//                        close(RESULT_NOT_ANSWERED_CODE, "[agora]专家网络较差")
//                    }
//                }
//            }
严久程 committed
299 300 301 302 303 304
        }

        override fun onError(err: Int) {
            super.onError(err)
            uploadException("mRtcEventHandler-onError:errorCode--%${err}")
            LogUtil.e("[agora] 发生错误回调 =$err")
YKai committed
305
            writeAgoraLog("声网错误回调errorCode--%${err}")
306
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "声网错误回调errorCode--%${err}")
307

严久程 committed
308 309 310 311 312 313 314 315 316 317 318 319 320 321
            //3:SDK 初始化失败。Agora 建议尝试以下处理方法
            //7:SDK 尚未初始化,就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化
            //10:API 调用超时。有些 API 调用需要 SDK 返回结果,如果 SDK 处理时间过长,超过 10 秒没有返回,会出现此错误
            //17:加入频道被拒绝。一般有以下原因:
            //用户已进入频道,再次调用加入频道的 API,例如 joinChannel,会返回此错误。停止调用该方法即可。
            //用户在做 Echo 测试时尝试加入频道。等待 Echo test 结束后再加入频道即可。
            //101:不是有效的 APP ID。请更换有效的 APP ID 重新加入频道
            //102:不是有效的 频道名。请更换有效的频道名重新加入频道
            //109:当前使用的 Token 过期,不再有效
            //110:生成的 Token 无效
            //123:此用户被服务器禁止
            runOnUiThread {
                when (err) {
                    3, 7, 109, 110 -> {
严久程 committed
322
                        showToast("请退出应用,重新打开")
严久程 committed
323 324
                        close(RESULT_NOT_ANSWERED_CODE, "咨询师已挂断")
                    }
325
                    10 -> {
严久程 committed
326
                        showToast("当前网络较差,请更换网络")
严久程 committed
327 328 329
                        close(RESULT_NOT_ANSWERED_CODE, "专家网络较差")
                    }
                    101 -> {
严久程 committed
330
                        showToast("安装包有问题,请联系技术")
严久程 committed
331 332 333
                        close(RESULT_NOT_ANSWERED_CODE, "安装包有问题,请联系技术")
                    }
                    102 -> {
严久程 committed
334
                        showToast("频道错误,请联系技术")
严久程 committed
335 336 337
                        close(RESULT_NOT_ANSWERED_CODE, "频道错误,请联系技术")
                    }
                    123 -> {
338 339
                        //                        showToast("对方不允许接听电话,请联系客服")
                        //                        close(RESULT_NOT_ANSWERED_CODE, "该专家不允许接听电话,请联系客服")
严久程 committed
340 341 342 343
                    }
                    else -> {
                    }
                }
344 345 346 347 348
                YDLavManager.instances.callEndStatusUpdate(
                    mAudioMessageBean?.channelId!!,
                    4,
                    "频道的错误回调信息${err}"
                )
严久程 committed
349 350 351
            }
        }

严久程 committed
352 353 354 355
        override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
            super.onNetworkQuality(uid, txQuality, rxQuality)
            var status = -1
            var netStatus = when (uid) {
356
                0 -> {
严久程 committed
357 358 359
                    if (txQuality in 1..2 && rxQuality in 1..2) {
                        ""
                    } else if (txQuality >= 5 || rxQuality >= 5) {
360
                        "您的网络已断开"
严久程 committed
361
                    } else {
362
                        status = if (txQuality >= 4 || rxQuality >= 4) {
严久程 committed
363 364 365 366
                            0
                        } else {
                            1
                        }
367
                        "您的网络状况不佳"
严久程 committed
368 369
                    }
                }
370
                else -> {
严久程 committed
371 372 373
                    if (txQuality in 1..2 && rxQuality in 1..2) {
                        ""
                    } else if (txQuality >= 5 || rxQuality >= 5) {
374
                        "对方的网络已断开"
严久程 committed
375
                    } else {
376
                        status = if (txQuality >= 4 || rxQuality >= 4) {
严久程 committed
377 378 379 380
                            0
                        } else {
                            1
                        }
381
                        "对方的网络状况不佳"
严久程 committed
382 383 384 385 386 387
                    }
                }
            }

            showNetStatus(netStatus, status)
        }
严久程 committed
388 389 390 391 392 393 394 395 396 397 398 399
    }

    override fun createPresenter(): IConsultantAudioHomeActivityContract.Presenter {
        return ConsultantAudioHomePresenterImpl()
    }

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

    companion object {
        const val PARAM: String = "param"
400

严久程 committed
401 402 403
        //0.未接听 1.已接听
        const val STATUS_NOT_ANSWERED = 0
        const val STATUS_ANSWERED = 1
404

严久程 committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
        //666.未接听,直接挂断 667.已接听,正常挂断  668:未接听,用户端取消了
        const val RESULT_NOT_ANSWERED_CODE = 666
        const val RESULT_ANSWERED_CODE = 667
        const val RESULT_USER_CANCEL = 668
    }

    override fun initDataAndEvent() {
        EventBus.getDefault().register(this)
        //状态栏颜色
        setWindowStatusBarColor()
        //点亮屏幕 并解锁
        ConsultantAudioUtils.wakeUpAndUnlock(this)
        //页面传递数据初始化
        getParam()
        //初始化传感器
        initSensorManager()
        initUser()
        initData()
        //获取声网频道号
        getChannelToken()
    }

    private fun setWindowStatusBarColor() {
        StatusBarUtils.setWindowStatusBarColor(this, R.color.audioim_color_40353535)
    }

    private fun getParam() {
        if (null == intent) {
            close(RESULT_NOT_ANSWERED_CODE, "通话异常")
            return
        }
        if (null != intent.getStringExtra(PARAM)) {
            val json = intent.getStringExtra(PARAM)
            if (!TextUtils.isEmpty(json)) {
严久程 committed
439
                writeAgoraLog("收到邀请通话消息内容:$json")
严久程 committed
440
                mAudioMessageBean = Gson().fromJson(json, AudioMessageBean::class.java)
严久程 committed
441

严久程 committed
442 443
                if (YDLavManager.sdkStatus != Constants.CONNECTION_STATE_CONNECTED) {
                    writeAgoraLog("RMT状态:${YDLavManager.sdkStatus},重新登录RMT")
444 445
                    val uid =
                        ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid
严久程 committed
446 447 448 449 450
                    YDLavManager.instances.login(uid) { _isSuccess, _msg ->
                        writeAgoraLog("登录RTM的uid=${uid}")
                        val result = if (_isSuccess) "RMT登录成功" else "RMT登录失败:$_msg"
                        writeAgoraLog(result)
                    }
严久程 committed
451 452
                } else {
                    writeAgoraLog("当前RMT状态:${YDLavManager.sdkStatus}")
严久程 committed
453
                }
严久程 committed
454 455 456 457 458 459 460 461 462 463 464 465
            }
        } else {
            close(RESULT_NOT_ANSWERED_CODE, "通话异常")
            return
        }
    }

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

        localPowerManager = getSystemService(POWER_SERVICE) as PowerManager?
466 467 468 469
        localWakeLock = localPowerManager!!.newWakeLock(
            PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
            "yidianling"
        )
严久程 committed
470 471 472 473 474 475
    }

    /**
     * 初始化界面用户信息
     */
    private fun initUser() {
严久程 committed
476
        var userName = "咨询用户"
严久程 committed
477 478 479 480 481 482 483 484 485 486 487 488 489
        if (null != mAudioMessageBean) {
            if (!TextUtils.isEmpty(mAudioMessageBean!!.userName)) {
                userName = mAudioMessageBean!!.userName!!
            }
            if (!TextUtils.isEmpty(mAudioMessageBean!!.userIcon)) {
                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, mAudioMessageBean!!.userIcon, iv_head, option)
            } else {
                iv_head.setBackgroundResource(R.drawable.audioim_head_place_hold_pic)
            }
严久程 committed
490
            userId = mAudioMessageBean!!.userId?.toInt() ?: -1
严久程 committed
491 492 493 494
        } else {
            iv_head.setBackgroundResource(R.drawable.audioim_head_place_hold_pic)
        }
        tv_name.text = userName
YKai committed
495
        writeAgoraLog("用户接收电话界面开启")
严久程 committed
496 497 498 499 500 501 502 503 504 505 506
    }

    private fun initData() {
        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))
        //启动背景动画
        wave_view.start()
507
        mPlayer = AudioPlayer(this, true)
严久程 committed
508 509 510 511 512 513 514 515 516 517 518
        mPlayer!!.setDataSource(R.raw.audioim_call_music)
        mPlayer!!.start(isLooping = true, isSetOnCompletionListener = false)

        //间接性震动手机
        VibratorUtil.vibrate(AudioHomeActivity@ this, longArrayOf(1000, 1000, 1000, 1000), true)
    }

    /**
     *  //获取声网频道号
     */
    private fun getChannelToken() {
严久程 committed
519
        writeAgoraLog("获取声网token")
严久程 committed
520 521 522 523 524 525 526
        //获取频道token
        mPresenter.getChannelToken(mAudioMessageBean, false)
    }

    override fun channelTokenResponse(token: String?, needJoinChannel: Boolean) {
        if (TextUtils.isEmpty(token)) {
            LogUtil.e("[agora]token not null")
527
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "token isEmpty ")
528

严久程 committed
529
            showToast("通话频道不存在")
严久程 committed
530 531 532 533
            finish()
            return
        }
        this.channelToken = token
严久程 committed
534
        writeAgoraLog("返回的声网token=$channelToken")
严久程 committed
535 536 537 538 539 540
        if (needJoinChannel) {
            //权限申请
            requestPermission()
        }
    }

严久程 committed
541 542 543 544 545 546 547 548 549 550 551
    /**
     * 更新ui
     */
    private fun updateUI() {
        tv_toast.visibility = View.VISIBLE
        tv_toast.text = "正在建立连接..."

        rl_call.visibility = View.GONE
        rl_hands_free.visibility = View.VISIBLE
    }

严久程 committed
552 553 554 555
    //申请音频权限
    @SuppressLint("CheckResult")
    private fun requestPermission() {
        val rxPermissions = RxPermissions(this)
556 557 558 559 560 561 562 563 564
        rxPermissions.requestEach(Manifest.permission.RECORD_AUDIO).subscribe { permission ->
            when {
                //权限已申请 进行初始化操作
                permission.granted -> init()
                //权限为申请 重新申请
                permission.shouldShowRequestPermissionRationale -> requestPermission()
                //跳转设置界面
                else -> {
                    ToastHelper.show(getString(R.string.audioim_need_storage_permission_hint))
严久程 committed
565

566 567 568 569 570
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    val uri = Uri.fromParts("package", packageName, null)
                    intent.data = uri
                    startActivity(intent)
                    finish()
严久程 committed
571 572
                }
            }
573
        }
严久程 committed
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    }

    private fun init() {
        //初始化语音
        initializeAgoraEngine()
        joinChannel()
    }

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

    /**
     * 加入频道
     */
    private fun joinChannel() {
        val account = YdlCommonRouterManager.getYdlCommonRoute().getUid()
        if (!TextUtils.isEmpty(mAudioMessageBean?.channelId)) {
            LogUtil.e("[agora] joinChannel:$account")
602
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "joinChannel:$account")
603

604 605 606 607
            voiceManage?.getVoiceApi()?.joinChannel(
                channelToken
                    ?: "", mAudioMessageBean!!.channelId!!, "Extra Optional Data", account
            )
严久程 committed
608 609 610 611
        }
    }

    override fun executeFinish() {
严久程 committed
612
        showToast("对方已挂断")
严久程 committed
613 614 615 616 617 618 619 620 621 622
        close(RESULT_ANSWERED_CODE, "")
    }

    /**
     * 通话开始后更新ui
     */
    private fun updateStartUi() {
        tv_toast.text = "已接通"
        tv_toast.postDelayed({ tv_toast.visibility = View.GONE }, 500)
        rl_remain_time.visibility = View.VISIBLE
严久程 committed
623 624


625 626 627
        totalDisposable =
            Observable.interval(0, 1, TimeUnit.SECONDS).subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread()).subscribe({
YKai committed
628 629 630 631
                    tv_remain_time.text = DateUtils.formatTime(it.toString())
                }, {
                    close(RESULT_NOT_ANSWERED_CODE, "对方异常")
                })
严久程 committed
632 633 634 635 636 637 638 639 640 641
    }

    /**
     * 通话结束
     */
    private fun callFinish() {
        status = STATUS_NOT_ANSWERED
    }

    private fun showStopService() {
严久程 committed
642
        if (status == STATUS_NOT_ANSWERED) {
643
            YDLavManager.instances.callEndStatusUpdate(mAudioMessageBean?.channelId!!, 2, "被叫主动拒绝")
YKai committed
644
            writeAgoraLog("通话未接通挂断:用户主动挂断")
严久程 committed
645 646 647
            //当未接听 直接挂断 要发送给老师一条消息
            close(RESULT_NOT_ANSWERED_CODE, "用户已挂断")
        } else if (status == STATUS_ANSWERED) {
648
            YDLavManager.instances.callEndStatusUpdate(mAudioMessageBean?.channelId!!, 3, "被叫主动拒绝")
严久程 committed
649
            writeAgoraLog("通话接通后挂断:专家主动挂断")
严久程 committed
650 651
            //正常接听 挂断电话 需要重置信令管理类状态
            close(RESULT_ANSWERED_CODE, "")
严久程 committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
        }
    }

    override fun listenStatusPushResponse() {
    }

    /**
     * 挂断
     */
    fun hangUpClick(view: View) {
        if (Utils.isFastClick()) {
            //防止连击
            return
        }
        showStopService()
YKai committed
667
        writeAgoraLog("用户点击挂断按钮")
668 669 670 671 672
        ActionCountUtils.count(
            "shengwang_popup_layer_page|shengwang_popup_layer_refuse_click",
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        )
严久程 committed
673 674 675 676 677 678 679 680 681 682 683 684 685
    }

    /**
     * 接听
     */
    fun onCall(view: View) {
        if (Utils.isFastClick()) {
            //防止连击
            return
        }

        //调用接口判断邀请专家的用户当前是否在频道内,如果在,则专家加入频道,如果不在,则提示用户已挂断
        //更改逻辑:现在是专家先进频道,这个接口暂时只作为参考
686 687
        //        presenter.userIsInChannel(mAudioMessageBean?.channelId ?: "", mAudioMessageBean?.userId
        //                ?: "")
严久程 committed
688 689 690 691

        executeCall(true)


692 693 694 695 696
        ActionCountUtils.count(
            "shengwang_popup_layer_page|shengwang_popup_layer_answer_click",
            YdlCommonRouterManager.getYdlCommonRoute().getUid().toString(),
            uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        )
严久程 committed
697 698 699 700 701 702 703 704 705 706
    }

    /**
     * 执行接听操作
     */
    override fun executeCall(canExcute: Boolean) {
        stopPlaying()
        //停止震动
        VibratorUtil.StopVibrate(this)
        if (!canExcute) {
严久程 committed
707
            showToast("对方已挂断")
严久程 committed
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
            finish()
        } else {
            if (null != mAudioMessageBean) {
                updateUI()
                //专家先加入频道,然后再接受用户邀请,保证专家比用户先加入频道
                if (!TextUtils.isEmpty(channelToken)) {
                    //权限申请完成后加入频道
                    requestPermission()
                } else {
                    //获取频道token
                    mPresenter.getChannelToken(mAudioMessageBean)
                }
            }
        }
    }

    /**
     * 打开扬声器 true:开启 false:关闭(听筒)
     */
    fun onSwitchSpeakerphoneClicked(view: View) {
        view.isSelected = !view.isSelected
        if (view.isSelected) {
            //扬声器模式
            iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free)
        } else {
            //听筒模式
            iv_hands_free.setImageResource(R.drawable.audioim_img_hands_free_unuse)
        }
        LogUtil.e("http---------------isSelected=" + !view.isSelected)
        if (null == voiceManage || null == voiceManage!!.getVoiceApi()) {
            return
        }

        voiceManage!!.getVoiceApi().setEnableSpeakerphone(view.isSelected)
    }

    override fun onResume() {
        super.onResume()
746 747 748 749 750
        sensorManager!!.registerListener(
            this,
            sensorManager!!.getDefaultSensor(Sensor.TYPE_PROXIMITY),
            SensorManager.SENSOR_DELAY_NORMAL
        )
严久程 committed
751

752 753 754 755 756
        ActionCountUtils.count(
            "shengwang_popup_layer_page|shengwang_popup_layer_page_visit",
            "",
            uid = YdlCommonRouterManager.getYdlCommonRoute().getUid().toString()
        )
严久程 committed
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
    }

    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) {
                        localWakeLock!!.acquire()
                    }
                } else {
                    //离开手机
                    //唤醒设备
                    if (localWakeLock!!.isHeld) {
                        localWakeLock!!.release()
                    }
                }
            }
        }
    }

严久程 committed
782 783 784 785 786 787 788
    /**
     * 显示自定义弹窗
     */
    private fun showToast(msg: String?) {
        runOnUiThread {
            ToastHelper.show(msg ?: "")
        }
严久程 committed
789 790
    }

严久程 committed
791 792 793 794 795 796 797 798 799 800
    /**
     * 网络状态
     */
    private fun showNetStatus(msg: String, status: Int = 0) {
        runOnUiThread {
            if (TextUtils.isEmpty(msg)) {
                tv_nte_status.visibility = View.GONE
            } else {
                tv_nte_status.text = msg
                if (status == 0) {
801 802 803 804 805 806
                    tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                        ContextCompat.getDrawable(
                            this,
                            R.drawable.av_audio_wifi_normal
                        ), null, null, null
                    )
严久程 committed
807 808
                }
                if (status == 1) {
809 810 811 812 813 814
                    tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(
                        ContextCompat.getDrawable(
                            this,
                            R.drawable.av_audio_wifi_better
                        ), null, null, null
                    )
严久程 committed
815 816 817 818 819 820 821 822 823
                }
                if (status == -1) {
                    tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
                }
                tv_nte_status.visibility = View.VISIBLE
            }
        }
    }

严久程 committed
824 825
    //关闭本页面
    fun close(code: Int, msg: String) {
严久程 committed
826 827
        runOnUiThread {
            LogUtil.e("[agora]close(code:$code,msg:$msg)")
828 829
            AliYunRichLogsHelper.getInstance()
                .sendRichLog(AliYunLogConfig.AGORA, "close(code:$code,msg:$msg)")
830

YKai committed
831 832
            //上传日志文件
            uploadLog()
严久程 committed
833 834 835
            stopMusic()
            //播放结束音频
            playFinishMusic()
836 837 838 839 840 841 842 843 844 845
            when (code) {
                RESULT_ANSWERED_CODE -> {
                    //已接听,正常挂断
                    //离开频道
                    leaveChannel()
                }
                RESULT_NOT_ANSWERED_CODE -> {
                    callStatus = 2
                    uploadException("被叫拒绝", zhu = "")
                    //未接听,直接挂断 发送消息
846 847 848 849 850 851
                    //        YDLRTMClient.instances.refuseCall(mAudioMessageBean?.channelId)
                    YDLavManager.instances.refuseCall(
                        mAudioMessageBean!!.userId!!,
                        mAudioMessageBean?.channelId,
                        Gson().toJson(mAudioMessageBean)
                    )
852 853 854 855 856 857
                }
                RESULT_USER_CANCEL -> {
                    callStatus = 1
                    uploadException("主叫取消", zhu = "")
                    showToast("对方已挂断")
                }
严久程 committed
858
            }
严久程 committed
859 860
            ActivityManager.getInstance().removeStack(activity = this)
            LogUtil.e("[agora]页面移除")
861
            AliYunRichLogsHelper.getInstance().sendRichLog(AliYunLogConfig.AGORA, "页面移除")
严久程 committed
862
            finish()
严久程 committed
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
        }
    }

    private fun stopMusic() {
        //停止播放音乐
        stopPlaying()
        //停止震动
        VibratorUtil.StopVibrate(AudioHomeActivity@ this)
    }

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

    /**
     * 播放结束音频
     */
    private fun playFinishMusic() {
        if (mPlayer == null) {
887
            mPlayer = AudioPlayer(this, true)
严久程 committed
888 889
        }
        mPlayer!!.setDataSource(R.raw.audioim_hand_down_music)
890
        //        mPlayer!!.switchPlayType(true)
严久程 committed
891 892 893 894 895 896 897
        mPlayer!!.start(isLooping = false, isSetOnCompletionListener = false)
    }

    fun onEventMainThread(event: AudioHomeEvent) {
        stopMusic()
    }

严久程 committed
898
    /**
899
     *连接中状态倒计时:15s后如果还是处于连接中,则直接退出当前页面
严久程 committed
900 901 902
     */
    private fun connectingStatusWaitingTimeCount() {
        if (connectingStatusDisposable == null) {
903 904
            connectingStatusDisposable =
                Observable.interval(0, 1, TimeUnit.SECONDS).subscribeOn(Schedulers.computation())
905
                    .take(16).observeOn(AndroidSchedulers.mainThread()).subscribe({}, {}, {
YKai committed
906 907 908 909 910 911 912 913 914 915 916
                        if (!isConnectSuccess) {
                            YDLavManager.instances.callEndStatusUpdate(
                                mAudioMessageBean?.channelId!!,
                                1,
                                "被叫加入频道后主叫未加入超时"
                            )
                            writeAgoraLog("通话未接通挂断:连接中的状态超过5s自动挂断")
                            showToast("用户已挂断")
                            close(RESULT_NOT_ANSWERED_CODE, "")
                        }
                    })
严久程 committed
917 918 919
        }
    }

严久程 committed
920 921 922 923 924 925 926 927
    /**
     * 离开频道
     */
    private fun leaveChannel() {
        uploadException("", "zhu", "108")
        if (totalDisposable != null) {
            totalDisposable!!.dispose()
        }
严久程 committed
928 929 930 931 932

        if (connectingStatusDisposable != null) {
            connectingStatusDisposable!!.dispose()
        }

严久程 committed
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
        if (null != voiceManage && null != voiceManage!!.getVoiceApi()) {
            voiceManage!!.getVoiceApi().leaveChannel()
            voiceManage!!.getVoiceApi().destroy()
            voiceManage = null
        }
        if (mPlayer != null) {
            mPlayer!!.clear()
        }
        if (null != sensorManager) {
            sensorManager!!.unregisterListener(this)
        }
        //唤醒设备
        if (null != localWakeLock && localWakeLock!!.isHeld) {
            localWakeLock!!.release()
        }
        sensorManager = null
        localWakeLock = null
        localPowerManager = null
    }

    private fun voiceDestory() {
        if (null != voiceManage && null != voiceManage!!.getVoiceApi()) {
            voiceManage!!.getVoiceApi().destroy()
        }
        voiceManage = null
    }

    /**
     * 重写返回键逻辑:屏蔽返回键
     */
    override fun onBackPressed() {
    }

    private fun writeAgoraLog(content: String) {
        Observable.create<Any> {
            try {
YKai committed
969
                AudioLogUtils.writeAgoraLog(
970 971 972 973 974
                    "$content-------Time:${
                        AudioLogUtils.format.format(
                            Calendar.getInstance().time
                        )
                    }", "consult.log"
YKai committed
975
                )
严久程 committed
976 977
            } catch (e: Exception) {
            }
978
        }.subscribeOn(Schedulers.io()).subscribe()
严久程 committed
979 980
    }

981 982
    fun uploadExceptionStatus(msg: String, status: Int) {
        callStatus = status
ydl committed
983
        uploadException(msg, zhu = "zhu", eventType = "108")
严久程 committed
984 985 986 987 988
    }

    /**
     * 上传错误日志
     */
989
    private fun uploadException(message: String, zhu: String = "", eventType: String = "99") {
严久程 committed
990
        var time: String = (System.currentTimeMillis() / 1000).toString()
991 992
        var uid: String =
            ModularServiceManager.provide(IUserService::class.java).getUserInfo()?.uid!!
严久程 committed
993
        var payLoad = PayLoad(mAudioMessageBean?.channelId ?: "0", time, uid, "1", "999", message)
994 995
        var connectException =
            ConnectExceptionCommand(time + zhu, "2", eventType, payLoad, callStatus)
ydl committed
996
        YDLavManager.instances.uploadException(connectException, null)
严久程 committed
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
    }

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

    override fun onDestroy() {
        LogUtil.e("http-------------onDestory")
        leaveChannel()
        voiceDestory()
严久程 committed
1010
        isConnectSuccess = false
严久程 committed
1011 1012 1013 1014 1015
        status = STATUS_NOT_ANSWERED
        hasUpLoadLog = false
        EventBus.getDefault().unregister(this)
        if (ActivityManager.getActivitySize() == 1) {
            try {
1016
                //                startActivity(MainActivity.newIntent(this, false))
1017 1018
                ARouter.getInstance().build("/main/main").addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                    .navigation()
严久程 committed
1019 1020 1021 1022 1023 1024 1025
            } catch (e: Exception) {

            }
        }
        super.onDestroy()
    }
}