package room import ( "bet24.com/log" "bet24.com/servers/common" pb "bet24.com/servers/micros/audioroom/proto" "bet24.com/servers/micros/audioroom/transaction/database" task "bet24.com/servers/micros/task/proto" "bet24.com/servers/zego" "strconv" ) const ( mic_lock = -1 // 锁定 mic_idle = 0 // 空闲 mic_defaultCount = 5 // 默认上麦数量 mic_timeOut = 10 // 麦位超时 ) // 是否麦位空闲 func (this *Room) isMicIdle(index int) bool { if index < 0 || index >= len(this.mics) { log.Error("room_mic.IsMicIdle out of index roomId=%d index=%d", this.RoomId, index) return false } m := &this.mics[index] // 麦已锁 if m.UserId == mic_lock { return false } // 有房间流 if m.StreamId != "" { return false } // 麦已占(麦位锁定几秒钟) if m.UserId > mic_idle && m.TimeStamp+mic_timeOut <= common.GetTimeStamp() { return false } m.UserId = mic_idle m.TimeStamp = 0 return true } // 判断是否已占麦位 func (this *Room) isOnMic(userId int) bool { for _, v := range this.mics { if v.UserId == userId { return true } } return false } // 获取麦克风列表信息 func (this *Room) GetMicListInfo() []pb.MicInfo { return this.mics } // 获取麦列表 func (this *Room) GetMicList() []int { var list []int for k, v := range this.mics { // 占位不显示用户 if v.StreamId == "" && v.UserId > mic_idle { // 超时清理 if v.TimeStamp+mic_timeOut <= common.GetTimeStamp() { this.mics[k].UserId = mic_idle } list = append(list, mic_idle) continue } // 正常处理 list = append(list, v.UserId) } return list } // 上麦 func (this *Room) OnTheMic(userId, sn int) int { // 判断是否在黑名单 if this.IsBlack(userId, pb.BlackType_Mic) { return 15 } // 会员信息 m := this.GetMemberInfo(userId) for i := 0; i < len(this.mics); i++ { if i != sn { continue } // 判断是否麦位空闲 if !this.isMicIdle(i) { return 13 } // 上麦模式(3种模式) // 0=房间内所有成员自由上麦 if this.MicMode == pb.OnMic_All { // 上麦 this.mics[i].UserId = userId this.mics[i].TimeStamp = common.GetTimeStamp() // 添加上麦日志 go this.addOnMicLog(userId, userId, this.MicMode, m.RoleId) break } // 1=加入为成员才可以上麦 if this.MicMode == pb.OnMic_Member { if m.UserId == 0 { return 16 } } // 非管理员 if m.RoleId != pb.Role_Assistant && m.RoleId != pb.Role_Administrator { // 2=仅限管理员邀请或者管理员才能上麦(包含创建者),调用邀请上麦接口 InviteOnMic if this.MicMode == pb.OnMic_Manager { return 17 } // 3=申请才能上麦,调用申请上麦接口 ApplyOnMic if this.MicMode == pb.OnMic_Apply { return 18 } } // 上麦 this.mics[i].UserId = userId this.mics[i].TimeStamp = common.GetTimeStamp() // 添加上麦日志 go this.addOnMicLog(userId, userId, this.MicMode, m.RoleId) break } // 清理重复占麦 for i := 0; i < len(this.mics); i++ { if i == sn { continue } if this.mics[i].UserId != userId { continue } // 占麦清理,添加下麦日志 if this.mics[i].StreamId != "" { go this.AddOffMicLog(userId, this.mics[i].StreamId) } this.mics[i] = pb.MicInfo{ UserId: mic_idle, StreamId: "", TimeStamp: 0, } } return 1 } // 上麦回调通知 func (this *Room) OnTheMicNotify(userId int, streamId string) int { for i := 0; i < len(this.mics); i++ { if this.mics[i].UserId != userId { continue } // 清掉已占的麦位 if this.mics[i].StreamId != "" && this.mics[i].StreamId != streamId { this.mics[i] = pb.MicInfo{ UserId: mic_idle, StreamId: "", TimeStamp: 0, } continue } this.mics[i].StreamId = streamId this.mics[i].TimeStamp = common.GetTimeStamp() // 通知上麦日志 go this.notifyOnMicLog(userId, i, streamId) } // 麦位通知 go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{ Reason: pb.Notify_Reason_Mic_Change, UserId: userId, }) return 1 } // 下麦回调通知 func (this *Room) OffTheMicNotify(userId int, streamId string) int { for i := 0; i < len(this.mics); i++ { if this.mics[i].UserId != userId { continue } if this.mics[i].StreamId != streamId { log.Release("room.offTheMic userId=%d streamId=%s is valid %+v", userId, streamId, this.mics[i]) continue } // 计算时长 seconds := common.GetTimeStamp() - this.mics[i].TimeStamp this.mics[i] = pb.MicInfo{ UserId: mic_idle, StreamId: "", TimeStamp: 0, } go func() { // 麦位通知 this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{ Reason: pb.Notify_Reason_Mic_Change, UserId: userId, SN: i, }) // 下麦日志 this.AddOffMicLog(userId, streamId) // 触发房间任务 this.roomMgr.DoRoomTaskAction(userId, this.RoomId, pb.RoomTask_Action_OnMic, seconds) // 触发用户任务 this.roomMgr.DoUserTaskAction(userId, this.RoomId, pb.UserTask_Action_OnMic, seconds, 0) // 触发大厅任务 task.DoTaskAction(userId, task.TaskAction_upMicDuration, seconds, task.TaskScope{}) }() return 1 } return 11 } // 加解锁麦(status -1=上锁 0=解锁) func (this *Room) SetMic(userId, sn int, status int) int { if status != mic_lock && status != mic_idle { return 11 } for i := 0; i < len(this.mics); i++ { if i == sn { // 空闲时才允许上锁 if status == mic_lock && this.mics[i].UserId > 0 { return 11 } this.mics[i].UserId = status // 麦位通知 go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{ Reason: pb.Notify_Reason_Mic_Change, SN: i, }) return 1 } } return 12 } // 邀请上麦(通知接收者直接调用sdk上麦) func (this *Room) InviteOnMic(userId, toUserId int) int { // 不能自己邀请自己和房主 if userId == toUserId || this.UserId == toUserId { return 16 } // 会员信息 m := this.GetMemberInfo(userId) // 只有管理员才能发送邀请 if m.RoleId != pb.Role_Administrator && m.RoleId != pb.Role_Assistant { return 16 } // 同级别不能邀请 toM := this.GetMemberInfo(toUserId) if toM.RoleId == m.RoleId { return 16 } // 判断是否在黑名单 if this.IsBlack(toUserId, pb.BlackType_Mic) { return 15 } // 判断是否已占麦位 if this.isOnMic(toUserId) { return 12 } // 判断是否在线 var isOnline bool for _, v := range this.onlineUsers { if v == toUserId { isOnline = true break } } // 非在线用户 if !isOnline { return 17 } for i := 0; i < len(this.mics); i++ { // 判断是否麦位空闲 if !this.isMicIdle(i) { continue } // 上麦 this.mics[i].UserId = toUserId this.mics[i].TimeStamp = common.GetTimeStamp() // 判断是否已申请 if this.isMicApply(toUserId) { // 麦位申请删除 this.delMicApply(toUserId) // 发送申请同意通知 go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Mic_Apply_Agree, NotifyUserId: toUserId, UserId: userId, SN: i, }) // 添加上麦日志 go this.addOnMicLog(toUserId, userId, pb.OnMic_Apply, toM.RoleId) return 1 } // 发送邀请通知 go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{ Reason: pb.Notify_Reason_Mic_Invite, NotifyUserId: toUserId, UserId: userId, SN: i, }) // 添加上麦日志 go this.addOnMicLog(toUserId, userId, pb.OnMic_Manager, toM.RoleId) return 1 } return 11 } // 踢麦 func (this *Room) KickMic(userId, toUserId int) int { for i := 0; i < len(this.mics); i++ { if this.mics[i].UserId != toUserId { continue } roomId := strconv.Itoa(this.RoomId) uid := strconv.Itoa(toUserId * -1) // sdk服务器 ==> 删除房间流 code, message := zego.MuteUser(roomId, uid, this.mics[i].StreamId) log.Debug("room.kickMic(zego.MuteUser) i=%d userId=%s roomId=%s streamId=%s code=%d message=%s", i, uid, roomId, this.mics[i].StreamId, code, message) // 计算时长 seconds := common.GetTimeStamp() - this.mics[i].TimeStamp // 清空麦位 this.mics[i] = pb.MicInfo{ UserId: 0, StreamId: "", TimeStamp: 0, } go func() { // 触发房间任务 this.roomMgr.DoRoomTaskAction(toUserId, this.RoomId, pb.RoomTask_Action_OnMic, seconds) // 触发用户任务 this.roomMgr.DoUserTaskAction(toUserId, this.RoomId, pb.UserTask_Action_OnMic, seconds, 0) // 踢麦通知 this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{ Reason: pb.Notify_Reason_Mic_Kick, UserId: toUserId, SN: i, }) }() // 添加日志 this.AddOperateLog(this.RoomId, userId, toUserId, pb.OperateType_KickMic) return 1 } return 11 } // 上麦申请列表 func (this *Room) GetOnMicApplyList() []int { this.lock.RLock() defer this.lock.RUnlock() return this.micApplyList } // 申请队列信息 func (this *Room) isMicApply(userId int) bool { // 判断是否已申请 for _, uid := range this.micApplyList { if uid == userId { return true } } return false } // 申请上麦 func (this *Room) ApplyOnMic(userId int) pb.RetMsg { var retMsg pb.RetMsg // 非申请模式 if this.MicMode != pb.OnMic_Apply { retMsg.RetCode = 15 retMsg.Message = "Non-application mode" return retMsg } // 是否黑名单 if this.IsBlack(userId, pb.BlackType_Mic) { retMsg.RetCode = 11 retMsg.Message = "blacklist users" return retMsg } // 判断是否已占麦位 if this.isOnMic(userId) { retMsg.RetCode = 13 retMsg.Message = "already on the mic" return retMsg } // 判断是否已申请 if this.isMicApply(userId) { retMsg.RetCode = 12 retMsg.Message = "Already in the application list" return retMsg } // 添加到申请列表 this.micApplyList = append(this.micApplyList, userId) // 麦位申请数量变化通知 go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Mic_Apply, MicApplyCount: len(this.micApplyList), }) retMsg.RetCode = 1 retMsg.Message = "successful application" return retMsg } // 取消申请上麦 func (this *Room) CancelApplyOnMic(userId int) pb.RetMsg { var retMsg pb.RetMsg // 清理占麦 for i := 0; i < len(this.mics); i++ { if this.mics[i].UserId != userId { continue } if this.mics[i].StreamId != "" { continue } this.mics[i].UserId = mic_idle this.mics[i].TimeStamp = 0 break } // 删除申请处理 this.delMicApply(userId) retMsg.RetCode = 1 retMsg.Message = "Cancellation request successful" return retMsg } // 麦位申请取消或删除 func (this *Room) delMicApply(toUserId int) { // 清理所有 if toUserId == 0 { this.micApplyList = this.micApplyList[0:0] } // 处理申请 for i := 0; i < len(this.micApplyList); i++ { if this.micApplyList[i] != toUserId { continue } this.micApplyList = append(this.micApplyList[:i], this.micApplyList[i+1:]...) break } // 麦位申请数量变化通知 go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Mic_Apply_Cancel, MicApplyCount: len(this.micApplyList), }) return } // 处理申请上麦(1=同意 2=拒绝)(通知接收者直接调用sdk上麦) func (this *Room) DealApplyOnMic(userId, toUserId, status int) pb.RetMsg { var retMsg pb.RetMsg // 判断申请状态 if status != pb.MicApply_Status_Agree && status != pb.MicApply_Status_Reject { retMsg.RetCode = 11 retMsg.Message = "illegal data" return retMsg } // 是否管理员 if !this.isAdmin(userId) { retMsg.RetCode = 11 retMsg.Message = "you are not an administrator" return retMsg } // 拒绝处理 if status == pb.MicApply_Status_Reject { // 麦位申请拒绝 this.delMicApply(toUserId) retMsg.RetCode = 1 retMsg.Message = "refusal to succeed" return retMsg } // 判断是否有申请 if !this.isMicApply(toUserId) { retMsg.RetCode = 1 retMsg.Message = "Consent Request Sent" return retMsg } // 同意处理 for i := 0; i < len(this.mics); i++ { // 判断是否麦位空闲 if !this.isMicIdle(i) { continue } // 上麦 this.mics[i].UserId = toUserId this.mics[i].TimeStamp = common.GetTimeStamp() // 麦位申请删除 this.delMicApply(toUserId) // 发送通知 go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{ Reason: pb.Notify_Reason_User_Mic_Apply_Agree, NotifyUserId: toUserId, UserId: userId, SN: i, }) // 添加上麦日志 go this.addOnMicLog(toUserId, userId, pb.OnMic_Apply, pb.Role_MAX) retMsg.RetCode = 1 retMsg.Message = "Consent Request Sent" return retMsg } retMsg.RetCode = 12 retMsg.Message = "Not enough free mic slots" return retMsg } // 添加上麦日志 func (this *Room) addOnMicLog(userId, opUserId, micMode, roleId int) { // 无效值 if roleId == pb.Role_MAX { roleId = this.GetMemberInfo(userId).RoleId } this.micLogList = append(this.micLogList, pb.MicLog{ UserId: userId, RoleID: roleId, MicMode: micMode, OpUserId: opUserId, }) return } // 通知上麦日志 func (this *Room) notifyOnMicLog(userId, sn int, streamId string) { for k, v := range this.micLogList { if v.UserId != userId { continue } this.micLogList[k].StreamId = streamId this.micLogList[k].SN = sn this.micLogList[k].OnMicStamp = common.GetTimeStamp() break } return } // 添加下麦日志 func (this *Room) AddOffMicLog(userId int, streamId string) { for i := 0; i < len(this.micLogList); i++ { v := this.micLogList[i] // 无效 if v.StreamId == "" { continue } if userId > 0 && v.UserId != userId { continue } if streamId != "" && v.StreamId != streamId { continue } // 删除 this.micLogList = append(this.micLogList[:i], this.micLogList[i+1:]...) ts := common.GetTimeStamp() seconds := ts - v.OnMicStamp // 数据库操作 go database.AddMicLog(v.UserId, this.RoomId, v.RoleID, v.SN, v.MicMode, v.OnMicStamp, ts, seconds, v.OpUserId) // 移动索引 i-- } return }