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.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.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.base.BaseMvpActivity import com.ydl.ydlcommon.modular.ModularServiceManager 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.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 /** * 声网事件回调 (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)") //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}") //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") YDLavManager.instances.callEndStatusUpdate(channelId!!, 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}") // 不需要移动端做离开房间逻辑,服务端会判断进行踢人逻辑 //因为用户端直接加入了频道,防止该回调执行时,专家还未加入频道,因此在连接成功之后,才进行频道人数判断 // 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 网络连接被服务器中止 该情况现在是因为后端踢人逻辑 if (reason == 3) { callEventSave("50", "通话结束:网络连接被服务器中止 该情况现在是因为后端踢人逻辑,原因(${reason}") writeAgoraLog("通话结束:网络连接被服务器中止 该情况现在是因为后端踢人逻辑,原因(${reason})") AliYunRichLogsHelper.getInstance() .sendRichLog( AliYunLogConfig.AGORA, "通话结束:网络连接被服务器中止 该情况现在是因为后端踢人逻辑,原因(${reason})" ) // 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, "离开频道回调") //通话结束或挂断时,上传日志文件 uploadLog() } override fun onUserJoined(uid: Int, elapsed: Int) { super.onUserJoined(uid, elapsed) callEventSave("20", "${uid}加入频道回调") LogUtil.e("[agora]远端用户/主播加入频道回调") onPeerJoined() AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.AGORA, "远端用户/主播加入频道回调") } 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, "接通后通话结束:对方已挂断") //通话结束或挂断时,上传日志文件 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) { "您的网络已断开" } else { status = if (txQuality >= 4 || rxQuality >= 4) { 0 } else { 1 } "您的网络状况不佳" } } else -> { if (txQuality in 1..2 && rxQuality in 1..2) { "" } else if (txQuality >= 5 || rxQuality >= 5) { "对方的网络已断开" } else { status = if (txQuality >= 4 || rxQuality >= 4) { 0 } else { 1 } "对方的网络状况不佳" } } } 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}") if (YDLavManager.sdkStatus != Constants.CONNECTION_STATE_CONNECTED) { //再次登录声网,确保声网登录状态 reLoginRTM() } //view初始化 initView() //点击事件 setClickEvent() //权限申请 requestPermission() 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") 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") 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") 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, "用户拨打电话界面开启") //水波纹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 { 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, "用户端点击:麦克风已关") } 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, "用户端点击:麦克风已开") voiceManage?.getVoiceApi()?.enableLocalAudio(true) } } //切换线路 ll_changeRoute.setOnClickListener { if (!canChangeRoute) { showHangUpTimeTraditionalDialog() return@setOnClickListener } AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.AGORA, "用户端点击:切换线路") ActionCountUtils.record("call_phone_page", "call_phone_icon_click", "0", "4") showChooseDialog(1) } //挂断 iv_hang_up.setOnClickListener { if (!canHangUp) { AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.AGORA, "用户端点击:挂断,展示提示弹窗") 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, "已接通:主叫主动挂断") 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, "用户端点击:免提,扬声器已关") } 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, "用户端点击:免提,扬声器已开") } //已经接通 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, "请求音频权限通过") 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, "拒绝请求音频权限") uploadLog() showStorageDialog() } }) } catch (e: Exception) { callEventSave("80", "请求音频权限异常${e.message}") AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.AGORA, "请求音频权限异常${e.message}") 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") 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}") dismissHangUpTimeOnlineDialog() dismissHangUpTimeTraditionalDialog() }) { // waittingStatus() if (!isConnectSuccess) { //关闭音乐 dismissHangUpTimeOnlineDialog() dismissHangUpTimeTraditionalDialog() stopPlaying() callEventSave("34", "未接通挂断:50s等待倒计时结束挂断") writeAgoraLog("未接通挂断:50s等待倒计时结束挂断") AliYunRichLogsHelper.getInstance() .sendRichLog(AliYunLogConfig.AGORA, "未接通挂断:50s等待倒计时结束挂断") //提示切换传统线路 //发送消息通知专家用户已挂断 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),再次挂断" ) } //通话结束或挂断时,上传日志文件 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() } /** * 声网加入频道 */ 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, "未接听时:主叫(用户)主动挂断,取消呼叫") 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),再次挂断") } //通话结束或挂断时,上传日志文件 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按钮") 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之后") 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),再次挂断") } 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, "用户加入频道后,通知服务端发送推送") 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() 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) } }