Commit 7a9181f0 by 万齐军

网络质量

parent 83eda2bd
......@@ -190,4 +190,6 @@ interface IImService : IProvider {
fun dismissConsultServiceDialog();
/**群聊*/
fun startTeamSession(activity: Activity, tid: String, doctorId: String)
fun getSystemConfig(key:String)
}
\ No newline at end of file
......@@ -168,6 +168,8 @@ android {
packagingOptions {
exclude 'META-INF/proguard/coroutines.pro'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
}
dataBinding {
enabled true
......@@ -177,6 +179,9 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
debugImplementation('com.ydl.debugkit:debugkit:1.0.0'){
exclude group: "androidx.sqlite"
}
implementation 'com.github.feeeei:CircleSeekbar:v1.1.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation(rootProject.ext.dependencies["appcompat-v7"])
......
......@@ -52,7 +52,6 @@ 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.listener.RtcNetInterface
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydl_image.config.SimpleImageOpConfiger
import com.ydl.ydl_image.manager.YDLImageCacheManager
......@@ -67,7 +66,6 @@ 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.log.XLog
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.ydl.ydlnet.YDLHttpUtils
import com.yidianling.common.tools.ToastUtil
......@@ -98,9 +96,6 @@ import java.util.concurrent.TimeUnit
class AudioHomeActivity :
BaseMvpActivity<IAudioHomeActivityContract.View, IAudioHomeActivityContract.Presenter>(),
IAudioHomeActivityContract.View, SensorEventListener {
companion object {
const val EFFECT_HANGUP = 3001
}
/**
* 专家头像地址
......@@ -1120,7 +1115,19 @@ class AudioHomeActivity :
voiceManage?.attachVoiceEventHandler(mRtcEventHandler)
voiceManage?.getVoiceApi()?.setAudioProfile(Constants.AUDIO_PROFILE_DEFAULT, Constants.AUDIO_SCENARIO_CHATROOM_GAMING)
voiceManage?.attachNetQualityListener(NetQuality())
voiceManage?.attachNetQualityListener(
NetQuality(
this,
channelId,
voiceManage,
tvNetUp,
ivNetQuality,
tvNetQuality,
tvNetDown,
tvNetDelay,
layoutQualityGroup
)
)
AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.initSdk))
}
......@@ -1328,7 +1335,7 @@ class AudioHomeActivity :
if (mPlayer == null) {
mPlayer = AudioPlayer(this)
}
mPlayer?.setDataSource(R.raw.audioim_hand_down_music)
mPlayer?.setDataSource(R.raw.effect_hand_up)
mPlayer?.switchPlayType(iv_hands_free.isSelected)
mPlayer?.setCompletionListener(MediaPlayer.OnCompletionListener {
LogUtil.e("播放结束")
......@@ -1513,7 +1520,6 @@ class AudioHomeActivity :
//播放结束音频
playFinishMusic()
// 声网离开房间
voiceManage?.getVoiceApi()?.playEffect(EFFECT_HANGUP, "res://raw/${R.raw.effect_hand_up}")
AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.leave))
voiceManage?.getVoiceApi()?.leaveChannel()
}
......@@ -1702,7 +1708,6 @@ class AudioHomeActivity :
if (null != voiceManage && null != voiceManage?.getVoiceApi()) {
if (!isLeavelChannel) {
// 声网离开房间
voiceManage?.getVoiceApi()?.playEffect(EFFECT_HANGUP, "res://raw/${R.raw.effect_hand_up}")
voiceManage?.getVoiceApi()?.leaveChannel()
}
// voiceManage?.getVoiceApi()?.destroy()
......@@ -1719,60 +1724,6 @@ class AudioHomeActivity :
override fun onBackPressed() {
}
inner class NetQuality : RtcNetInterface {
override fun onLocalAudioStats(bitrate: Int, packetLossRate: Int) {
XLog.i("NetQuality", "bitrate:$bitrate,packetLossRate:$packetLossRate")
runOnUiThread {
tvNetUp.text = "${bitrate}Kbps"
}
}
override fun onNetQuality(uid: Int, tx: Int, rx: Int) {
if (tx in 4..6 || rx in 4..6) {
XLog.i("NetQuality", "$uid,tx:$tx,rx:$rx")
}
runOnUiThread {
if (uid == 0) {
when (rx) {
1 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_excellent)
tvNetQuality.text = "网络优秀"
}
2, 3 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_good)
tvNetQuality.text = "网络良好"
}
4, 5, 6 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_poor)
tvNetQuality.text = "网络极差"
}
}
}
}
}
override fun onNetworkTypeChanged(type: Int) {
AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.networkTypeChanged), retCode = type)
}
override fun onRemoteAudioFeel(frozenRate: Int, qoeQuality: Int, reason: Int, mos: Int) {
XLog.i("NetQuality", "frozenRate:$frozenRate,qoeQuality:$qoeQuality,reason:$reason,mos:$mos")
}
override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {
XLog.i("NetQuality", "uid:$uid,state:$state,reason:$reason,elapsed:$elapsed")
}
override fun onRemoteAudioStats(quality: Int, delay: Int, bitrate: Int, audioLossRate: Int) {
runOnUiThread {
tvNetDown.text = "${bitrate}Kbps"
tvNetDelay.text = "${delay}ms"
layoutQualityGroup.visibility = View.VISIBLE
}
}
}
/**
* 倾诉日志
* @param session 通话业务id
......
package com.ydl.audioim
import android.app.Activity
import android.content.Context
import android.text.TextUtils
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.tencent.mmkv.MMKV
import com.ydl.audioim.http.AudioApiRequestUtil
import com.ydl.audioim.http.RtcEvent
import com.ydl.ydl_av.voice.listener.RtcNetInterface
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydlcommon.utils.log.XLog
import io.agora.rtc.Constants
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import java.io.File
import java.io.FileOutputStream
class NetQuality(
val activity: Activity,
val channelId: String?,
val voiceManage: YDLVoiceManager?,
val tvNetUp: TextView,
val ivNetQuality: ImageView,
val tvNetQuality: TextView,
val tvNetDown: TextView,
val tvNetDelay: TextView,
val layoutQualityGroup: View
) : RtcNetInterface {
private var lastOnNetQualityDownReport = 0L
private var lastOnNetQualityUpReport = 0L
private var lastOnRemoteNetworkCongestion = 0L
override fun onLocalAudioStats(bitrate: Int, packetLossRate: Int) {
XLog.i("NetQuality", "bitrate:$bitrate,packetLossRate:$packetLossRate")
activity.runOnUiThread {
tvNetUp.text = "${bitrate}Kbps"
}
}
override fun onNetQuality(uid: Int, tx: Int, rx: Int) {
if (tx in 4..6 || rx in 4..6) {
XLog.i("NetQuality", "$uid,tx:$tx,rx:$rx")
}
activity.runOnUiThread {
if (uid == 0) {
when (rx) {
1 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_excellent)
tvNetQuality.text = "网络优秀"
}
2, 3 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_good)
tvNetQuality.text = "网络良好"
}
4, 5, 6 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_poor)
tvNetQuality.text = "网络极差"
if (System.currentTimeMillis() - lastOnNetQualityDownReport > 10 * 1000) {
lastOnNetQualityDownReport = System.currentTimeMillis()
AudioApiRequestUtil.reportCallEvent(
channelId,
RtcEvent(RtcEvent.Event.networkDownPoor),
retCode = rx
)
}
}
}
if (tx in 4..6) {
if (System.currentTimeMillis() - lastOnNetQualityUpReport > 10 * 1000) {
lastOnNetQualityUpReport = System.currentTimeMillis()
AudioApiRequestUtil.reportCallEvent(
channelId,
RtcEvent(RtcEvent.Event.networkUpPoor),
retCode = rx
)
}
}
}
}
}
override fun onNetworkTypeChanged(type: Int) {
AudioApiRequestUtil.reportCallEvent(channelId, RtcEvent(RtcEvent.Event.networkTypeChanged), retCode = type)
}
override fun onRemoteAudioFeel(frozenRate: Int, qoeQuality: Int, reason: Int, mos: Int) {
XLog.i("NetQuality", "frozenRate:$frozenRate,qoeQuality:$qoeQuality,reason:$reason,mos:$mos")
}
override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {
XLog.i("NetQuality", "uid:$uid,state:$state,reason:$reason,elapsed:$elapsed")
if (reason == Constants.REMOTE_AUDIO_REASON_NETWORK_CONGESTION && state == Constants.REMOTE_AUDIO_STATE_FROZEN) {
val qualityValue = MMKV.defaultMMKV().getString("network_quality_config", "0")
if (TextUtils.equals(qualityValue, "1")) {
if (System.currentTimeMillis() - lastOnRemoteNetworkCongestion > 10 * 1000) {
lastOnRemoteNetworkCongestion = System.currentTimeMillis()
voiceManage?.getVoiceApi()
?.playEffect(3001, getNetLowEffect(activity))
}
}
}
}
override fun onRemoteAudioStats(quality: Int, delay: Int, bitrate: Int, audioLossRate: Int) {
XLog.i("NetQuality", "quality:$quality,delay:$delay,bitrate:$bitrate,audioLossRate:$audioLossRate")
activity.runOnUiThread {
tvNetDown.text = "${bitrate}Kbps"
tvNetDelay.text = "${delay}ms"
layoutQualityGroup.visibility = View.VISIBLE
}
}
companion object {
fun getHandUpEffect(context: Context): String {
return context.filesDir.absolutePath + "/sounds/effect_hand_up.mp3"
}
fun getNetLowEffect(context: Context): String {
return context.filesDir.absolutePath + "/sounds/effect_net_quality_low.mp3"
}
fun copySoundFile(context: Context?) {
if (context == null) return
Single.create<Int> {
val filesDir = context.filesDir
val soundFile = File(filesDir, "sounds")
if (!soundFile.exists()) {
soundFile.mkdir()
}
val filesName = arrayOf("effect_hand_up.mp3", "effect_net_quality_low.mp3")
filesName.forEach {
val file = File(soundFile, it)
if (!file.exists()) {
file.createNewFile()
val fileOutputStream = FileOutputStream(file)
context.assets.open(it).copyTo(fileOutputStream)
}
}
}
.observeOn(Schedulers.io())
.subscribe()
}
}
}
\ No newline at end of file
......@@ -186,6 +186,8 @@ class RtcEvent(val event: Event) :
localFirstFrame("本地音频首帧", REPORT_LEVEL_WARN),
remoteFirstFrame("远端音频首帧", REPORT_LEVEL_WARN),
networkTypeChanged("网络变化", REPORT_LEVEL_WARN),
networkDownPoor("网络下行质量差", REPORT_LEVEL_WARN),
networkUpPoor("网络上行质量差", REPORT_LEVEL_WARN),
connectionChanged("连接状态变化", REPORT_LEVEL_WARN),
errorOccurred("错误发生", REPORT_LEVEL_ERROR),
}
......
......@@ -7,19 +7,18 @@ import android.net.Uri
import com.alibaba.android.arouter.facade.annotation.Route
import com.google.gson.Gson
import com.ydl.audioim.BuildConfig
import com.ydl.audioim.NetQuality
import com.ydl.audioim.YDLavManager
import com.ydl.audioim.api.IAudioImService
import com.ydl.audioim.http.AudioApiRequestUtil
import com.ydl.audioim.http.AudioNetAPi
import com.ydl.audioim.http.REPORT_LEVEL_INFO
import com.ydl.audioim.utils.CallCheck
import com.ydl.audioim.widget.AxbConfirmDialog
import com.ydl.devicesidlib.DeviceIDHelper
import com.ydl.ydl_av.voice.listener.RtcGlobalNet
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydlcommon.modular.findRouteService
import com.ydl.ydlcommon.utils.log.XLog
import com.ydl.ydlnet.YDLHttpUtils
import io.reactivex.schedulers.Schedulers
import com.yidianling.im.api.service.IImService
/**
* Created by Ykai on 2022/7/26.
......@@ -72,6 +71,7 @@ class AudioImServiceImp : IAudioImService {
override fun initAgoraRtc(context: Context) {
YDLVoiceManager.init(context.applicationContext, BuildConfig.AGORA_APPID)
findRouteService(IImService::class.java).getSystemConfig("network_quality_config")
}
override fun reportCallEvent(type: String, name: String, desc: String, retCode: Int?) {
......@@ -93,30 +93,18 @@ class AudioImServiceImp : IAudioImService {
}
override fun init(context: Context?) {
NetQuality.copySoundFile(context)
}
}
internal class RtcGlobalNetQuality(private val threshold: Int) : RtcGlobalNet {
private var average = 0.0
private var count = 0
override fun onLastmileQuality(quality: Int) {
if (quality in 1..6) {
average = (average * count + quality) / (count + 1)
if (quality in 4..6) {
count++
if (quality > 3) {
if (quality > 3 && count % 10 == 0) {
XLog.i("RtcGlobalNetQuality", quality.toString())
}
if (count >= threshold) {
//上报
val req = hashMapOf(
"deviceId" to DeviceIDHelper.getInstance().deviceId,
"rscp" to average
)
YDLHttpUtils.obtainApi(AudioNetAPi::class.java).report(req).subscribeOn(Schedulers.io()).subscribe()
average = 0.0
count = 0
}
}
}
}
\ No newline at end of file
......@@ -25,6 +25,7 @@ import com.alibaba.android.arouter.launcher.ARouter
import com.google.gson.Gson
import com.tbruyelle.rxpermissions2.RxPermissions
import com.tencent.mmkv.MMKV
import com.ydl.audioim.NetQuality
import com.ydl.audioim.R
import com.ydl.audioim.YDLavManager
import com.ydl.audioim.http.AudioApiRequestUtil
......@@ -44,7 +45,6 @@ import com.ydl.consultantim.utils.VibratorUtil
import com.ydl.devicesidlib.DeviceIDHelper
import com.ydl.ydl_av.chat.bean.AudioMessageBean
import com.ydl.ydl_av.voice.listener.IYDLVoiceEventHandler
import com.ydl.ydl_av.voice.listener.RtcNetInterface
import com.ydl.ydl_av.voice.manager.YDLVoiceManager
import com.ydl.ydl_image.config.SimpleImageOpConfiger
import com.ydl.ydl_image.manager.YDLImageCacheManager
......@@ -59,7 +59,6 @@ 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.log.XLog
import com.ydl.ydlcommon.utils.remind.ToastHelper
import com.ydl.ydlnet.YDLHttpUtils
import com.yidianling.user.api.service.IUserService
......@@ -720,7 +719,19 @@ class ConsultantAudioHomeActivity :
*/
voiceManage = YDLVoiceManager()
voiceManage?.attachVoiceEventHandler(mRtcEventHandler)
voiceManage?.attachNetQualityListener(NetQuality())
voiceManage?.attachNetQualityListener(
NetQuality(
this,
mAudioMessageBean?.channelId,
voiceManage,
tvNetUp,
ivNetQuality,
tvNetQuality,
tvNetDown,
tvNetDelay,
layoutQualityGroup
)
)
voiceManage?.getVoiceApi()?.setAudioProfile(Constants.AUDIO_PROFILE_DEFAULT, Constants.AUDIO_SCENARIO_CHATROOM_GAMING)
AudioApiRequestUtil.reportCallEvent(mAudioMessageBean?.channelId, RtcEvent(RtcEvent.Event.initSdk))
......@@ -1045,7 +1056,7 @@ class ConsultantAudioHomeActivity :
if (mPlayer == null) {
mPlayer = AudioPlayer(this, true)
}
mPlayer!!.setDataSource(R.raw.audioim_hand_down_music)
mPlayer!!.setDataSource(R.raw.effect_hand_up)
// mPlayer!!.switchPlayType(true)
mPlayer!!.start(isLooping = false, isSetOnCompletionListener = false)
}
......@@ -1172,60 +1183,6 @@ class ConsultantAudioHomeActivity :
super.onDestroy()
}
inner class NetQuality : RtcNetInterface {
override fun onLocalAudioStats(bitrate: Int, packetLossRate: Int) {
XLog.i("NetQuality", "bitrate:$bitrate,packetLossRate:$packetLossRate")
runOnUiThread {
tvNetUp.text = "${bitrate}Kbps"
}
}
override fun onNetQuality(uid: Int, tx: Int, rx: Int) {
if (tx in 4..6 || rx in 4..6) {
XLog.i("NetQuality", "$uid,tx:$tx,rx:$rx")
}
runOnUiThread {
if (uid == 0) {
when (rx) {
1 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_excellent)
tvNetQuality.text = "网络优秀"
}
2, 3 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_good)
tvNetQuality.text = "网络良好"
}
4, 5, 6 -> {
ivNetQuality.setImageResource(R.drawable.audioim_bg_net_poor)
tvNetQuality.text = "网络极差"
}
}
}
}
}
override fun onNetworkTypeChanged(type: Int) {
AudioApiRequestUtil.reportCallEvent(mAudioMessageBean?.channelId, RtcEvent(RtcEvent.Event.networkTypeChanged), retCode = type)
}
override fun onRemoteAudioFeel(frozenRate: Int, qoeQuality: Int, reason: Int, mos: Int) {
XLog.i("NetQuality", "frozenRate:$frozenRate,qoeQuality:$qoeQuality,reason:$reason,mos:$mos")
}
override fun onRemoteAudioStateChanged(uid: Int, state: Int, reason: Int, elapsed: Int) {
XLog.i("NetQuality", "uid:$uid,state:$state,reason:$reason,elapsed:$elapsed")
}
override fun onRemoteAudioStats(quality: Int, delay: Int, bitrate: Int, audioLossRate: Int) {
runOnUiThread {
tvNetDown.text = "${bitrate}Kbps"
tvNetDelay.text = "${delay}ms"
layoutQualityGroup.visibility = View.VISIBLE
}
}
}
/**
* 倾诉日志
* @param session 通话业务id
......
......@@ -16,6 +16,8 @@ import com.netease.nimlib.sdk.msg.MsgService
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
import com.netease.nimlib.sdk.msg.model.CustomNotification
import com.netease.nimlib.sdk.msg.model.CustomNotificationConfig
import com.tencent.mmkv.MMKV
import com.ydl.ydlcommon.data.http.RxUtils
import com.ydl.ydlcommon.router.YdlCommonOut
import com.ydl.ydlcommon.utils.StringUtils
import com.ydl.ydlcommon.utils.remind.HttpErrorUtils
......@@ -440,4 +442,15 @@ class IMServiceImpl : IImService {
P2PCustomActionHandlerImpl(doctorId + "")
)
}
@SuppressLint("CheckResult")
override fun getSystemConfig(key: String) {
ImRetrofitApi.getImRetrofitApi()
.getSystemConfigByKeyword(key)
.compose(RxUtils.resultJavaData())
.subscribeOn(Schedulers.io())
.subscribe {
MMKV.defaultMMKV().putString(key, it.value1)
}
}
}
\ No newline at end of file
......@@ -66,7 +66,7 @@ public class MsgViewHolderConsultCallStatus extends MsgViewHolderBase {
long messageTime = message.getTime();
boolean isExpired = System.currentTimeMillis() - messageTime > 60 * 1000;
Integer pullCall = customAttachTipMsg.getPullCall();
if (!isExpired && pullCall != null && pullCall == 1) {
if (!isExpired && pullCall != null && pullCall == 1 && isReceivedMessage()) {
lineView.setVisibility(View.VISIBLE);
btnView.setVisibility(View.VISIBLE);
btnView.setOnClickListener(v -> {
......
package com.ydl.ydlcommon.utils.log
import com.apm.insight.log.VLog
import com.ydl.ydlcommon.BuildConfig
object XLog {
fun d(tag: String, msg: String) {
if (BuildConfig.DEBUG) {
android.util.Log.d(tag, msg)
}
VLog.i(tag, msg)
}
fun i(tag: String, msg: String) {
if (BuildConfig.DEBUG) {
android.util.Log.i(tag, msg)
}
VLog.i(tag, msg)
}
fun w(tag: String, msg: String) {
if (BuildConfig.DEBUG) {
android.util.Log.w(tag, msg)
}
VLog.i(tag, msg)
}
fun e(tag: String, msg: String) {
if (BuildConfig.DEBUG) {
android.util.Log.e(tag, msg)
}
VLog.e(tag, msg)
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment