将车聊聊工程代码加入到项目中,保证能跑起来了,后续做架构升级

Signed-off-by: 董宏宇 <martindhy@gmail.com>
This commit is contained in:
董宏宇
2021-10-25 20:29:09 +08:00
parent 3bfad3d31f
commit 17f17ba459
348 changed files with 16837 additions and 9 deletions

View File

@@ -0,0 +1,29 @@
package com.mogo.chat.model
import com.mogo.chat.base.BaseRepository
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.constant.HttpConstants.Companion.getConfig
import com.mogo.chat.model.bean.OnLineStatus
import com.mogo.chat.model.bean.UserInfoBySns
import com.mogo.chat.model.bean.UserInfoBySnsRequest
class ChatServiceModel : BaseRepository() {
//传入对方SN需要注意以后扩展时传参的改变
suspend fun isOnLine(sn: String): BaseResponse<OnLineStatus> {
val map = hashMapOf<String, String>()
map["sn"] = sn
return apiCall {
getNetWorkApi().isOnLine(map)
}
}
suspend fun queryUserInfo(sn: String): BaseResponse<UserInfoBySns> {
val sns = arrayListOf(sn)
val requestData = UserInfoBySnsRequest(sns)
return apiCall {
getNetWorkApi(getConfig()).queryUserInfoBySnS(requestData)
}
}
}

View File

@@ -0,0 +1,33 @@
package com.mogo.chat.model
import com.google.gson.Gson
import com.mogo.chat.base.BaseRepository
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.model.bean.FocusBlackListRequest
import com.mogo.chat.model.bean.FocusData
import com.mogo.chat.model.bean.FriendRequest
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
class FocusModel : BaseRepository() {
companion object {
const val TAG = "FocusModel"
}
suspend fun getFocusPage(pageIndex: Int): BaseResponse<FocusData> {
val friendRequest = Gson().toJson(FriendRequest(pageIndex, 10))
val map = mapOf("sn" to MoGoAiCloudClientConfig.getInstance().sn, "data" to friendRequest)
return apiCall { getNetWorkApi().getFocusPage(map) }
}
/**
* targetSn:要操作的目标SN
* operate: 2:拉黑 3:取消拉黑
*/
suspend fun dealBlackList(targetSn: String, operate: Int): BaseResponse<Any> {
val focusBlackListRequest = Gson().toJson(FocusBlackListRequest(targetSn, operate))
val map = mapOf("sn" to MoGoAiCloudClientConfig.getInstance().sn, "data" to focusBlackListRequest)
return apiCall { getNetWorkApi().dealBlackList(map) }
}
}

View File

@@ -0,0 +1,29 @@
package com.mogo.chat.model
import com.google.gson.Gson
import com.mogo.chat.base.BaseRepository
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.model.bean.FriendData
import com.mogo.chat.model.bean.FriendOrSelfOnLine
import com.mogo.chat.model.bean.FriendRequest
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
class FriendModel : BaseRepository() {
companion object {
const val TAG = "FriendModel"
}
suspend fun getFriendPage(pageIndex: Int): BaseResponse<FriendData> {
val friendRequest = Gson().toJson(FriendRequest(pageIndex, 10))
val map = mapOf("sn" to MoGoAiCloudClientConfig.getInstance().sn, "data" to friendRequest)
return apiCall { getNetWorkApi().getFriendPage(map) }
}
suspend fun canCallToFocus(snReceiver: String): BaseResponse<Any> {
val canCallStatus = Gson().toJson(FriendOrSelfOnLine(MoGoAiCloudClientConfig.getInstance().sn, snReceiver))
val map = mapOf("sn" to MoGoAiCloudClientConfig.getInstance().sn, "data" to canCallStatus)
return apiCall { getNetWorkApi().getChatStatus(map) }
}
}

View File

@@ -0,0 +1,6 @@
package com.mogo.chat.model.bean
/**
* 添加好友的push消息内容
*/
data class AddFriendMessage(val sn:String,val nickName: String, val headImgUrl: String, val message: String,val alertType: Int)

View File

@@ -0,0 +1,26 @@
package com.mogo.chat.model.bean
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
fun AllUnit.toSns(): Sns {
return Sns(MoGoAiCloudClientConfig.getInstance().sn,
localNickName,
localHeadImgUrl,
localCarInfo,
cardIdSex,
cityName,
cardIdAge
)
}
data class AllUnit(
var localUserId: Int,
var localNickName: String,
var localHeadImgUrl: String,
var localCarInfo: String,
var sns: List<Sns>,
var cardIdAge: String,
var cityName: String,
var cardIdSex: String
)

View File

@@ -0,0 +1,13 @@
package com.mogo.chat.model.bean
import com.mogo.chat.constant.CALL_TYPE_VOICE
class CallRequestParam(var snSender: String, var snReceiver: String, var nickName:String, var headImgUrl:String, var carInfo:String, var lat: Double?, var lon:Double?, callType: Int = CALL_TYPE_VOICE) {
var type: Int = callType
override fun toString(): String {
return "RoomParam(snSender='$snSender', snReceiver='$snReceiver', nickName='$nickName', headImgUrl='$headImgUrl', carInfo='$carInfo', lat=$lat, lon=$lon, type=$type)"
}
}

View File

@@ -0,0 +1,9 @@
package com.mogo.chat.model.bean
data class CarMessage(
val `receiver`: Int,
val message: Message,
val msgType: Int,
val pkgName: String,
val title: String
)

View File

@@ -0,0 +1,12 @@
package com.mogo.chat.model.bean
class CarSwitchStatus {
var sn:String
var status:Int
constructor(sn: String, status: Int) {
this.sn = sn
this.status = status
}
}

View File

@@ -0,0 +1,38 @@
package com.mogo.chat.model.bean
class ConnectStatusParam {
var snSender:String
var snReceiver:String
var roomId:Int
var status:Int
var type:Int
var lat: Double? = null//发送方的纬度
var lon: Double? = null//发送方的经度
var nickName: String? = null//发送方的昵称
var headImgUrl: String? = null//发送方的用户头像
var carInfo: String? = null//发送方的车辆信息
var cardIdAge: String? = null//年龄
var cardIdSex: String? = null//性别
var cityName: String? = null//城市
constructor(snSender: String, snReceiver: String, roomId: Int, status: Int,type:Int) {
this.snSender = snSender
this.snReceiver = snReceiver
this.roomId = roomId
this.status = status
this.type = type
}
override fun toString(): String {
return "ConnectStatusParam(snSender='$snSender', snReceiver='$snReceiver', roomId=$roomId, status=$status, type=$type, lat=$lat, lon=$lon, nickName=$nickName, headImgUrl=$headImgUrl, carInfo=$carInfo, cardIdAge=$cardIdAge, cardIdSex=$cardIdSex, cityName=$cityName)"
}
}

View File

@@ -0,0 +1,3 @@
package com.mogo.chat.model.bean
data class FocusStatus(val isFocus: Int)

View File

@@ -0,0 +1,87 @@
package com.mogo.chat.model.bean
data class FriendData(
val pageIndex: Int,
val pageSize: Int,
val totalPages: Int,
val totalElements: Int,
val friendList: List<FriendList>
)
data class FocusData(
val pageIndex: Int,
val pageSize: Int,
val totalPages: Int,
val totalElements: Int,
val friendList: List<FocusList>
)
/**
* carStatus == 1 可拨打
* carStatus == 0 不可拨打
*/
fun FriendList.canCall(): Boolean {
return carStatus == 1
}
fun FriendList.toSns(): Sns {
return Sns(sn, nickName, headImgUrl, carInfo, cardIdSex, cityName, cardIdAge)
}
data class FriendList(
val sn: String,
val nickName: String?,
val headImgUrl: String,
val carStatus: Int,
val cardIdSex: String,
val cityName: String,
val cardIdAge: String,
val carInfo: String
)
fun FocusList.isInBlackList(): Boolean {
return blackFlag == 1
}
data class FocusList(
val sn: String,
val nickName: String,
val headImgUrl: String,
var carStatus: Int, //车机是否在线 0是不在线 1是在线
val cardIdSex: String,
val cityName: String,
val cardIdAge: String,
val carInfo: String,
var eachFocusFlag: Boolean,//是否互粉
var blackFlag: Int //是否加入黑名单 0是未加入 1是加入
)
class FriendOrSelfOnLine {
var snSender: String
var snReceiver: String
constructor(snSender: String, snReceiver: String) {
this.snSender = snSender
this.snReceiver = snReceiver
}
}
class FriendRequest {
var pageIndex: Int
var pageSize: Int
constructor(pageIndex: Int, pageSize: Int) {
this.pageIndex = pageIndex
this.pageSize = pageSize
}
}
class FocusBlackListRequest {
var focusSn: String
var operate: Int
constructor(focusSn: String, operate: Int) {
this.focusSn = focusSn
this.operate = operate
}
}

View File

@@ -0,0 +1,8 @@
package com.mogo.chat.model.bean
data class Header(
val delayTime: Int,
val maxSpeed: Int,
val stayTime: Int,
val type: Int
)

View File

@@ -0,0 +1,3 @@
package com.mogo.chat.model.bean
data class InflectionBean(val inflectionId:Int,val inflectionName:String,val normalRes:Int,val checkedRes:Int,val exampleVoiceRaw:Int)

View File

@@ -0,0 +1,6 @@
package com.mogo.chat.model.bean
/**
* 长连接初步建立时的初始化信息封装
*/
data class InitMessage(val nickName:String,val headImg:String,val localUserId:Int)

View File

@@ -0,0 +1,22 @@
package com.mogo.chat.model.bean
class LiveBroadcast {
var eventId: String? = null
var sn: String
var type: Int = 0
var videoChannel: String
constructor(sn: String, videoChannel: String) {
this.sn = sn
this.videoChannel = videoChannel
}
constructor(eventId: String, sn: String, type: Int, videoChannel: String) {
this.eventId = eventId
this.sn = sn
this.type = type
this.videoChannel = videoChannel
}
}

View File

@@ -0,0 +1,16 @@
package com.mogo.chat.model.bean
class LiveBroadcastResult {
var videoChannel: String
var livePlayUrl: String
var playUrl: PlayUrl
constructor(videoChannel: String, livePlayUrl: String, playUrl: PlayUrl) {
this.videoChannel = videoChannel
this.livePlayUrl = livePlayUrl
this.playUrl = playUrl
}
}

View File

@@ -0,0 +1,14 @@
package com.mogo.chat.model.bean
class LocationCarsWithRadius {
var coordinates: List<Double>
var radius: Int
var type: String
var keyWord: String? = null
constructor(coordinates: List<Double>, radius: Int, type: String) {
this.coordinates = coordinates
this.radius = radius
this.type = type
}
}

View File

@@ -0,0 +1,12 @@
package com.mogo.chat.model.bean
data class MatchRequestParam(
var nickName: String,
var headImgUrl: String,
var carInfo: String,
var lat: Double,
var lon: Double,
var age: Int,
var cardIdSex: String? = null,
var cityName: String? = null,
)

View File

@@ -0,0 +1,55 @@
package com.mogo.chat.model.bean
import com.mogo.chat.constant.CALL_TYPE_MATCHING
import com.mogo.chat.constant.CALL_TYPE_VEHICLE_TEAM
import com.mogo.chat.constant.CALL_TYPE_VOICE
import java.io.Serializable
fun Message.isMatch(): Boolean {
return type == CALL_TYPE_MATCHING
}
fun Message.isCall(): Boolean {
return type == CALL_TYPE_VOICE
}
fun Message.isVehicleTeam(): Boolean {
return type == CALL_TYPE_VEHICLE_TEAM
}
//Message返回数据结构根据匹配传入信息 返回具体字段,服务端做转发,
//在Launcher2.0中传入数据不存在经纬度信息的而在车聊聊单独App中是存在经纬度但是不存在性别、城市、车型信息
//因此后期如若需要在车聊聊中添加缺少信息 需要做数据合并
fun Message.toSns(): Sns {
return Sns(
snSender,
roomId,
nickName,
headImgUrl,
carInfo,
cardIdSex,
cityName,
cardIdAge,
lat,
lon
)
}
data class Message(
val roomId: Int,
val snReceiver: String,
val snSender: String,
val status: Int,
val type: Int, //0语音通话 1匹配模式 2直播 3;车队
val nickName: String?,
val headImgUrl: String?,
val carInfo: String?,
val lat: Double,
val lon: Double,
val cardIdSex: String?,
val cityName: String?,
val cardIdAge: String?,
val teamMember: List<TeammateInfo>?
) : Serializable

View File

@@ -0,0 +1,11 @@
package com.mogo.chat.model.bean
fun OnLineStatus.onLine(): Boolean {
return carOnLine == 1 && onLine == 1
}
/**
* carOnLineACC ON状态 1:在线 2:不在线
* onLine:是否隐身 1:在线 2:隐身
*/
data class OnLineStatus(val carOnLine: Int, val onLine: Int)

View File

@@ -0,0 +1,14 @@
package com.mogo.chat.model.bean
class PlayUrl {
var rtmp: String
var flv: String
var hls: String
constructor(rtmp: String, flv: String, hls: String) {
this.rtmp = rtmp
this.flv = flv
this.hls = hls
}
}

View File

@@ -0,0 +1,5 @@
package com.mogo.chat.model.bean
class Results<out T>(val t :T) {
}

View File

@@ -0,0 +1,10 @@
package com.mogo.chat.model.bean
class RoomInfo {
var roomId:Int
constructor(roomId: Int) {
this.roomId = roomId
}
}

View File

@@ -0,0 +1,107 @@
package com.mogo.chat.model.bean
import android.text.TextUtils
import java.io.Serializable
class Sns : Serializable {
var sn: String = ""
var lat: Double = 0.0
var lon: Double = 0.0
var direction: Int = 0
var canLive: Int = 0//1:可直播 0:不可直播
var canVoice: Int = 1 //1:可语音 0不可语音
var nickName: String? = null
set(value) {
field = if (TextUtils.isEmpty(value)) {
"小蘑菇"
} else {
value
}
}
var userId: Int = 0 //用户ID 进入语音通话间唯一识别号、
var headImgUrl: String? = null
var carInfo: String? = null
var cardIdSex: String? = null
var cityName: String? = null
var cardIdAge: String? = null
constructor(sn: String, nickName: String?, headImgUrl: String?) {
this.canVoice = 1
this.sn = sn
this.nickName = nickName
this.headImgUrl = headImgUrl
}
constructor(
sn: String,
userId: Int,
nickName: String?,
carInfo: String?,
headImgUrl: String?,
lat: Double,
lon: Double
) {
this.sn = sn
this.lat = lat
this.lon = lon
this.direction = 0
this.canLive = 1
this.canVoice = 1
this.userId = userId
this.nickName = nickName
this.headImgUrl = headImgUrl
this.carInfo = carInfo
}
/**
* 可能会创建空sns在ChatService的onReceive里面的有此需求
*/
constructor(
sn: String = "",
nickName: String? = "",
headImgUrl: String? = "",
carInfo: String? = "",
gender: String? = "",
cityName: String? = "",
userAge: String? = ""
) {
this.sn = sn
this.nickName = nickName
this.headImgUrl = headImgUrl
this.carInfo = carInfo
this.cardIdSex = gender
this.cityName = cityName
this.cardIdAge = userAge
}
constructor(
sn: String = "",
roomId: Int,
nickName: String? = "",
headImgUrl: String? = "",
carInfo: String? = "",
cardIdSex: String? = "",
cityName: String? = "",
cardIdAge: String? = "",
lat: Double,
lon: Double
){
this.sn = sn
this.userId = roomId
this.nickName = nickName
this.headImgUrl = headImgUrl
this.carInfo = carInfo
this.cardIdSex = cardIdSex
this.cityName = cityName
this.cardIdAge = cardIdAge
this.lat = lat
this.lon = lon
}
override fun toString(): String {
return "Sns(sn='$sn', lat=$lat, lon=$lon, direction=$direction, canLive=$canLive, canVoice=$canVoice, nickName=$nickName, userId=$userId, headImgUrl=$headImgUrl, carInfo=$carInfo, cardIdSex=$cardIdSex, cityName=$cityName, cardIdAge=$cardIdAge)"
}
}

View File

@@ -0,0 +1,20 @@
package com.mogo.chat.model.bean
class SocketMsg {
var msgType:Int = 0
var sn:String? = null
var roomId:Int = 0
constructor(msgType: Int, sn: String?) {
this.msgType = msgType
this.sn = sn
}
constructor(msgType: Int, sn: String, roomId: Int) {
this.msgType = msgType
this.sn = sn
this.roomId = roomId
}
}

View File

@@ -0,0 +1,14 @@
package com.mogo.chat.model.bean
/**
* image: String //图片地址
* displayTime: Int //Splash页面图片显示时间
* effectiveFlag: Long //授权配置
* content: String //语音内容
*/
data class SplashConfig(
val image: String,
val displayTime: Int,
val effectiveFlag: Long,
val content: String
)

View File

@@ -0,0 +1,6 @@
package com.mogo.chat.model.bean
data class SplashConfigRequest(
val dataSource: String,
val serverType: String
)

View File

@@ -0,0 +1,17 @@
package com.mogo.chat.model.bean
/**
* created by wujifei on 2020/11/17 11:43
* describe:队员信息
*/
data class TeammateInfo(
var sn: String,
var nickName: String,
var headImgUrl: String,
var cardIdAge: Int,
var cardIdSex: String,
var cityName: String,
var lat: Double,
var lon: Double,
var carInfo: String,
var vehicleTeamLeader: Boolean)

View File

@@ -0,0 +1,5 @@
package com.mogo.chat.model.bean
data class TopicRequest(var topicGuide: TopicGuide)
data class TopicGuide(var topicContent:ArrayList<String>)

View File

@@ -0,0 +1,28 @@
package com.mogo.chat.model.bean
class UserInfoBySnsRequest {
var sns: List<String>? = null
constructor(sns: List<String>?) {
this.sns = sns
}
}
data class UserInfoBySns(val info: List<Info>)
data class Info(
val carAndUserInfoRedisVo: CarAndUserInfoRedisVo,
val realTimeLocationVo: RealTimeLocationVo
)
data class CarAndUserInfoRedisVo(
val sn:String?,
val userNickName: String?,
val headImgUrl: String?,
val cardIdSex: String?,
val cardIdAge: String?,
val lastBrandName: String?,
val lastActiveCity: String?
)
data class RealTimeLocationVo(val lon: Double, val lat: Double)

View File

@@ -0,0 +1,177 @@
package com.mogo.chat.model.control
import com.mogo.chat.R
import com.mogo.chat.base.BaseController
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.callcenter.CallController.Companion.callController
import com.mogo.chat.callcenter.CallTypeManager.Companion.callTypeManager
import com.mogo.chat.callcenter.exchangeToCallType
import com.mogo.chat.common.gme.GMEApi
import com.mogo.chat.common.gme.IGMEEventCallBack
import com.mogo.chat.constant.CALL_TYPE_VOICE
import com.mogo.chat.constant.PUSH_MSG_DENY_ENTER
import com.mogo.chat.constant.PUSH_MSG_HANG_UP
import com.mogo.chat.constant.TAG
import com.mogo.chat.exception.ApiException.Companion.ENTER_ROOM_API_EXCEPTION
import com.mogo.chat.model.bean.RoomInfo
import com.mogo.chat.net.request
import com.mogo.chat.util.CallTimer.Companion.callTimer
import com.mogo.chat.util.MediaController
import com.mogo.chat.util.UserInfoHelper
import com.mogo.chat.util.audio.AudioFocusUtil
import com.mogo.chat.util.log
import com.mogo.chat.util.sp.saveRoomId
import com.mogo.chat.util.trackCall
import com.mogo.commons.AbsMogoApplication
object ChatController : BaseController(), IGMEEventCallBack {
private var roomId = 0
fun call(
snReceiver: String,
mRoomID: Int,
onSuccess: ((roomId: Int) -> Unit),
onError: (Exception) -> Unit
) {
log(TAG, "ChatController call ----- snReceiver: $snReceiver")
roomId = mRoomID
if (roomId == 0) {
requestRoomInfo(snReceiver, onSuccess, onError)
} else {
enterRoom(roomId)
callController.callingReceiver()
}
}
private fun requestRoomInfo(
snReceiver: String,
onSuccess: ((roomId: Int) -> Unit),
onError: (Exception) -> Unit
) {
request<BaseResponse<RoomInfo>> {
start {
playCallingAudio()
}
loader {
chatServiceModel.requestRoomInfo(
snReceiver,
callTypeManager.callStatus.exchangeToCallType()
)
}
onSuccess {
roomId = it.result.roomId
log(TAG, "ChatController 获取房间信息成功:$roomId")
//创建房间
if (roomId == 0 || GMEApi.isRoomEntered()) {
log(TAG, "ChatController 已经进入房间 ---> ${GMEApi.isRoomEntered()}")
onError.invoke(ENTER_ROOM_API_EXCEPTION)
return@onSuccess
}
callController.readyToCallSender()
onSuccess.invoke(roomId)
}
onError {
log(TAG, "ChatController 获取房间信息失败")
stopCallingAudio()
onError.invoke(it)
}
}
}
private var isPlayingCallingAudio = false
private fun playCallingAudio() {
if (!isPlayingCallingAudio) {
isPlayingCallingAudio = true
MediaController.startPlay(
AbsMogoApplication.getApp().applicationContext,
R.raw.call,
true
)
}
}
private fun stopCallingAudio() {
if (isPlayingCallingAudio) {
MediaController.release()
isPlayingCallingAudio = false
}
}
fun enterRoom(mRoomId: Int) {
log(TAG, "ChatController enterRoom ---> roomID:$mRoomId")
roomId = mRoomId
stopCallingAudio()
requestAudioFocus()
GMEApi.addEnterRoomEventCall(this@ChatController)
GMEApi.enterRoom(mRoomId.toString())
saveRoomId(mRoomId)
callTimer.start()
}
private fun requestAudioFocus() {
val isCan = AudioFocusUtil.getInstance().findMicFocus(AbsMogoApplication.getApp().applicationContext)
if (!isCan) {
AudioFocusUtil.getInstance().sendGetFocusIntent(AbsMogoApplication.getApp().applicationContext)
}
}
override fun gmeHangUp() {
requestConnectStatus(
UserInfoHelper.tmpSenderInfo.sn,
PUSH_MSG_HANG_UP
)
}
fun requestConnectStatus(
snReceiver: String,
status: Int,
onSuccess: (() -> Unit)? = null,
onError: ((Exception) -> Unit)? = null,
_roomId: Int = 0
) {
if (status != PUSH_MSG_HANG_UP) {
trackCall(callTypeManager.callStatus.exchangeToCallType(), status)
}
if (_roomId != 0) {
roomId = _roomId
}
request<BaseResponse<Any>> {
loader {
chatServiceModel.requestConnectStatus(CALL_TYPE_VOICE,
snReceiver, roomId, status,
callTypeManager.callStatus.exchangeToCallType()
)
}
onSuccess {
log(TAG, "ChatController 同步房间信息成功")
onSuccess?.invoke()
when (status) {
PUSH_MSG_HANG_UP, PUSH_MSG_DENY_ENTER -> {
updateExitRoomStatus()
}
}
}
onError {
log(TAG, "ChatController 同步房间信息失败:$it")
if (status == PUSH_MSG_HANG_UP) {
onSuccess?.invoke()
updateExitRoomStatus()
return@onError
}
onError?.invoke(it)
}
}
}
fun updateExitRoomStatus() {
log(TAG, "ChatController exitRoom")
roomId = 0
callTimer.stop()
stopCallingAudio()
AudioFocusUtil.getInstance().sendReleaseFocusIntent(AbsMogoApplication.getApp().applicationContext)
GMEApi.updateExitRoomStatus(this)
}
}

View File

@@ -0,0 +1,206 @@
package com.mogo.chat.model.control
import com.mogo.chat.R
import com.mogo.chat.aspect.DebugLog
import com.mogo.chat.base.BaseController
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.callcenter.CallTypeManager.Companion.callTypeManager
import com.mogo.chat.callcenter.IMType
import com.mogo.chat.callcenter.canMatchTimeout
import com.mogo.chat.constant.TAG
import com.mogo.chat.model.bean.MatchRequestParam
import com.mogo.chat.net.request
import com.mogo.chat.net.taskDelayAsync
import com.mogo.chat.provider.ServiceApi
import com.mogo.chat.util.*
import com.mogo.chat.util.audio.AudioFocusUtil
import com.mogo.commons.AbsMogoApplication
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.withContext
object MatchController : BaseController() {
private const val MAX_AMOUNT_OF_CANCEL_MATCHING = 5
private var cancelMatchCount = 0
private var timeOutJob: Job? = null
private var retryJob: Job? = null
private const val DEFAULT_MATCH_TIME_OUT_TIME = 30 * 1000L // 30 * 1000L
private var arrayOfVoiceSources = intArrayOf(R.raw.match1, R.raw.match2, R.raw.match3)
private var isMatching = false
private var timeOut: (() -> Unit)? = null
private var startMatchTime: Long = 0L
fun resetMatchStatus() {
isMatching = false
stopTimeOutRecord()
log(TAG, "matchCallBack====$startMatchTime")
val time: Long = (System.currentTimeMillis() - startMatchTime)
startMatchTime = 0L
trackNormalEvent(TRACK_MATCH_SUCCESS, mutableMapOf("matchtime" to time))
}
fun startMatch(
invokeFlag: String?,
onSuccess: () -> Unit,
onError: (Exception) -> Unit,
timeOut: () -> Unit
) {
MatchController.timeOut = timeOut
request<BaseResponse<Any>> {
loader {
val location = ServiceApi.locationClient()?.lastKnowLocation
val param = MatchRequestParam(
UserInfoHelper.userInfo.nickName!!,
UserInfoHelper.userInfo.headImgUrl!!,
UserInfoHelper.userInfo.carInfo ?: "",
location?.latitude ?: 0.0,
location?.longitude ?: 0.0,
(UserInfoHelper.userInfo.cardIdAge ?: "0").toInt(),
UserInfoHelper.userInfo.cardIdSex,
UserInfoHelper.userInfo.cityName
)
if (!invokeFlag.isNullOrEmpty()) {
param.cardIdSex = UserInfoHelper.userInfo.cardIdSex
param.cityName = UserInfoHelper.userInfo.cityName
}
chatServiceModel.startMatch(param)
}
onSuccess {
log(TAG, "开始匹配成功")
onSuccess.invoke()
startTimeOutRecord()
// 开始播放匹配音乐
playMatchingAudio()
startMatchTime = System.currentTimeMillis()
callTypeManager.callStatus = IMType.MATCHING
isMatching = true
}
onError {
log(TAG, "开始匹配失败--${it.message}")
isMatching = false
onError.invoke(it)
}
}
}
private var isRecordingTimeOut = false
private fun startTimeOutRecord() {
if (!isRecordingTimeOut) {
isRecordingTimeOut = true
log(TAG, "开始本地超时计时===")
timeOutJob = taskDelayAsync(DEFAULT_MATCH_TIME_OUT_TIME) {
log(TAG, "本地计时匹配超时===")
withContext(Dispatchers.Main) {
// 本地计时匹配超时
if (startMatchTime != 0L) {
val time: Long = (System.currentTimeMillis() - startMatchTime)
startMatchTime = 0L
trackNormalEvent(TRACK_MATCH_FAIL, mutableMapOf("matchtime" to time))
}
stopMatchingAudio()
if (callTypeManager.callStatus.canMatchTimeout()) {
timeOut?.invoke()
}
isMatching = false
isRecordingTimeOut = false
}
}
}
}
private var isPlayingMatchingAudio = false
private fun playMatchingAudio() {
if (!isPlayingMatchingAudio) {
isPlayingMatchingAudio = true
AudioFocusUtil.getInstance().requireDuck()
MediaController.startPlay(
AbsMogoApplication.getApp().applicationContext,
arrayOfVoiceSources.random(),
true
)
}
}
private fun stopMatchingAudio() {
if (isPlayingMatchingAudio) {
MediaController.release()
isPlayingMatchingAudio = false
AudioFocusUtil.getInstance().releaseDuck()
}
}
@DebugLog
fun stopTimeOutRecord() {
if (isRecordingTimeOut) {
log(TAG, "结束本地超时计时=====")
stopMatchingAudio()
timeOutJob?.cancel()
isRecordingTimeOut = false
}
}
/**
* 服务端返回匹配超时
*/
fun matchTimeOutFromNet() {
log(TAG, "服务端返回匹配超时===$isMatching")
if (isMatching) {
if (startMatchTime != 0L) {
val time: Long = (System.currentTimeMillis() - startMatchTime)
startMatchTime = 0L
trackNormalEvent(TRACK_MATCH_FAIL, mutableMapOf("matchtime" to time))
}
timeOutJob?.cancel()
stopMatchingAudio()
if (callTypeManager.callStatus.canMatchTimeout()) {
timeOut?.invoke()
}
timeOut = null
isMatching = false
}
}
fun cancelMatch(onSuccess: (() -> Unit)? = null) {
callTypeManager.callStatus = IMType.INIT_CALL
stopTimeOutRecord()
if (startMatchTime != 0L) {
val time = (System.currentTimeMillis() - startMatchTime)
trackNormalEvent(TRACK_MATCH_CANCEL, mutableMapOf("matchtime" to time))
startMatchTime = 0L
}
request<BaseResponse<Any>> {
loader {
chatServiceModel.cancelMatch()
}
onSuccess {
log(TAG, "取消匹配成功")
cancelMatchCount = 0
onSuccess?.invoke()
isMatching = false
}
onError {
log(TAG, "取消匹配失败--$cancelMatchCount--${it.message}")
isMatching = false
if (cancelMatchCount < MAX_AMOUNT_OF_CANCEL_MATCHING) {
retryJob = taskDelayAsync(1000) {
withContext(Dispatchers.Main) {
cancelMatchCount++
cancelMatch()
}
}
} else {
retryJob?.cancel()
retryJob = null
cancelMatchCount = 0
onSuccess?.invoke()
}
}
}
}
}

View File

@@ -0,0 +1,83 @@
package com.mogo.chat.model.control
import com.mogo.chat.base.BaseController
import com.mogo.chat.base.BaseResponse
import com.mogo.chat.common.gme.IGMEEventCallBack
import com.mogo.chat.constant.CALL_TYPE_VEHICLE_TEAM
import com.mogo.chat.constant.PUSH_MSG_DENY_ENTER
import com.mogo.chat.constant.PUSH_MSG_HANG_UP
import com.mogo.chat.constant.TAG
import com.mogo.chat.model.bean.CallRequestParam
import com.mogo.chat.net.request
import com.mogo.chat.provider.ServiceApi
import com.mogo.chat.util.UserInfoHelper
import com.mogo.chat.util.log
import com.mogo.chat.util.sp.getRoomId
import com.mogo.cloud.passport.MoGoAiCloudClientConfig
import com.mogo.commons.network.Utils
object VehicleTeamController : BaseController(), IGMEEventCallBack {
fun inviteJoinVehicleTeam( invitedSn: String, onSuccess: () -> Unit, onError: (Exception) -> Unit) {
getUserInfo({
request<BaseResponse<Any>> {
loader {
val location = ServiceApi.locationClient()?.lastKnowLocation
val param = CallRequestParam(
MoGoAiCloudClientConfig.getInstance().sn, invitedSn,
UserInfoHelper.userInfo.nickName!!,
UserInfoHelper.userInfo.headImgUrl!!,
UserInfoHelper.userInfo.carInfo ?: "",
location?.latitude ?: 0.0,
location?.longitude ?: 0.0,
CALL_TYPE_VEHICLE_TEAM)
chatServiceModel.inviteJoinVehicleTeam(param)
}
onSuccess {
onSuccess.invoke()
}
onError {
onError.invoke(it)
}
}
},{
log(TAG,"获取用户信息失败,请稍后重试")
onError.invoke(Exception("获取用户信息失败,请稍后重试"))
})
}
override fun gmeHangUp() {
requestVehicleTeamConnectStatus(UserInfoHelper.userInfo.sn, PUSH_MSG_HANG_UP,CALL_TYPE_VEHICLE_TEAM)
}
fun requestVehicleTeamConnectStatus(
snReceiver: String = "",
status: Int,
type:Int,
onSuccess: (() -> Unit)? = null,
onError: ((Exception) -> Unit)? = null) {
request<BaseResponse<Any>> {
loader {
chatServiceModel.requestConnectStatus(CALL_TYPE_VEHICLE_TEAM, snReceiver, getRoomId(), status,type)
}
onSuccess {
log(TAG, "同步房间信息成功")
onSuccess?.invoke()
when (status) {
PUSH_MSG_HANG_UP, PUSH_MSG_DENY_ENTER -> {
ChatController.updateExitRoomStatus()
}
}
}
onError {
log(TAG, "同步房间信息失败:$it")
if (status == PUSH_MSG_HANG_UP) {
onSuccess?.invoke()
ChatController.updateExitRoomStatus()
return@onError
}
onError?.invoke(it)
}
}
}
}