room_mic.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. package room
  2. import (
  3. "bet24.com/log"
  4. "bet24.com/servers/common"
  5. pb "bet24.com/servers/micros/audioroom/proto"
  6. "bet24.com/servers/micros/audioroom/transaction/database"
  7. task "bet24.com/servers/micros/task/proto"
  8. "bet24.com/servers/zego"
  9. "strconv"
  10. )
  11. const (
  12. mic_lock = -1 // 锁定
  13. mic_idle = 0 // 空闲
  14. mic_defaultCount = 5 // 默认上麦数量
  15. mic_timeOut = 10 // 麦位超时
  16. )
  17. // 是否麦位空闲
  18. func (this *Room) isMicIdle(index int) bool {
  19. if index < 0 || index >= len(this.mics) {
  20. log.Error("room_mic.IsMicIdle out of index roomId=%d index=%d", this.RoomId, index)
  21. return false
  22. }
  23. m := &this.mics[index]
  24. // 麦已锁
  25. if m.UserId == mic_lock {
  26. return false
  27. }
  28. // 有房间流
  29. if m.StreamId != "" {
  30. return false
  31. }
  32. // 麦已占(麦位锁定几秒钟)
  33. if m.UserId > mic_idle && m.TimeStamp+mic_timeOut <= common.GetTimeStamp() {
  34. return false
  35. }
  36. m.UserId = mic_idle
  37. m.TimeStamp = 0
  38. return true
  39. }
  40. // 判断是否已占麦位
  41. func (this *Room) isOnMic(userId int) bool {
  42. for _, v := range this.mics {
  43. if v.UserId == userId {
  44. return true
  45. }
  46. }
  47. return false
  48. }
  49. // 获取麦克风列表信息
  50. func (this *Room) GetMicListInfo() []pb.MicInfo {
  51. return this.mics
  52. }
  53. // 获取麦列表
  54. func (this *Room) GetMicList() []int {
  55. var list []int
  56. for k, v := range this.mics {
  57. // 占位不显示用户
  58. if v.StreamId == "" && v.UserId > mic_idle {
  59. // 超时清理
  60. if v.TimeStamp+mic_timeOut <= common.GetTimeStamp() {
  61. this.mics[k].UserId = mic_idle
  62. }
  63. list = append(list, mic_idle)
  64. continue
  65. }
  66. // 正常处理
  67. list = append(list, v.UserId)
  68. }
  69. return list
  70. }
  71. // 上麦
  72. func (this *Room) OnTheMic(userId, sn int) int {
  73. // 判断是否在黑名单
  74. if this.IsBlack(userId, pb.BlackType_Mic) {
  75. return 15
  76. }
  77. // 会员信息
  78. m := this.GetMemberInfo(userId)
  79. for i := 0; i < len(this.mics); i++ {
  80. if i != sn {
  81. continue
  82. }
  83. // 判断是否麦位空闲
  84. if !this.isMicIdle(i) {
  85. return 13
  86. }
  87. // 上麦模式(3种模式)
  88. // 0=房间内所有成员自由上麦
  89. if this.MicMode == pb.OnMic_All {
  90. // 上麦
  91. this.mics[i].UserId = userId
  92. this.mics[i].TimeStamp = common.GetTimeStamp()
  93. // 添加上麦日志
  94. go this.addOnMicLog(userId, userId, this.MicMode, m.RoleId)
  95. break
  96. }
  97. // 1=加入为成员才可以上麦
  98. if this.MicMode == pb.OnMic_Member {
  99. if m.UserId == 0 {
  100. return 16
  101. }
  102. }
  103. // 非管理员
  104. if m.RoleId != pb.Role_Assistant && m.RoleId != pb.Role_Administrator {
  105. // 2=仅限管理员邀请或者管理员才能上麦(包含创建者),调用邀请上麦接口 InviteOnMic
  106. if this.MicMode == pb.OnMic_Manager {
  107. return 17
  108. }
  109. // 3=申请才能上麦,调用申请上麦接口 ApplyOnMic
  110. if this.MicMode == pb.OnMic_Apply {
  111. return 18
  112. }
  113. }
  114. // 上麦
  115. this.mics[i].UserId = userId
  116. this.mics[i].TimeStamp = common.GetTimeStamp()
  117. // 添加上麦日志
  118. go this.addOnMicLog(userId, userId, this.MicMode, m.RoleId)
  119. break
  120. }
  121. // 清理重复占麦
  122. for i := 0; i < len(this.mics); i++ {
  123. if i == sn {
  124. continue
  125. }
  126. if this.mics[i].UserId != userId {
  127. continue
  128. }
  129. // 占麦清理,添加下麦日志
  130. if this.mics[i].StreamId != "" {
  131. go this.AddOffMicLog(userId, this.mics[i].StreamId)
  132. }
  133. this.mics[i] = pb.MicInfo{
  134. UserId: mic_idle,
  135. StreamId: "",
  136. TimeStamp: 0,
  137. }
  138. }
  139. return 1
  140. }
  141. // 上麦回调通知
  142. func (this *Room) OnTheMicNotify(userId int, streamId string) int {
  143. for i := 0; i < len(this.mics); i++ {
  144. if this.mics[i].UserId != userId {
  145. continue
  146. }
  147. // 清掉已占的麦位
  148. if this.mics[i].StreamId != "" && this.mics[i].StreamId != streamId {
  149. this.mics[i] = pb.MicInfo{
  150. UserId: mic_idle,
  151. StreamId: "",
  152. TimeStamp: 0,
  153. }
  154. continue
  155. }
  156. this.mics[i].StreamId = streamId
  157. this.mics[i].TimeStamp = common.GetTimeStamp()
  158. // 通知上麦日志
  159. go this.notifyOnMicLog(userId, i, streamId)
  160. }
  161. // 麦位通知
  162. go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{
  163. Reason: pb.Notify_Reason_Mic_Change,
  164. UserId: userId,
  165. })
  166. return 1
  167. }
  168. // 下麦回调通知
  169. func (this *Room) OffTheMicNotify(userId int, streamId string) int {
  170. for i := 0; i < len(this.mics); i++ {
  171. if this.mics[i].UserId != userId {
  172. continue
  173. }
  174. if this.mics[i].StreamId != streamId {
  175. log.Release("room.offTheMic userId=%d streamId=%s is valid %+v", userId, streamId, this.mics[i])
  176. continue
  177. }
  178. // 计算时长
  179. seconds := common.GetTimeStamp() - this.mics[i].TimeStamp
  180. this.mics[i] = pb.MicInfo{
  181. UserId: mic_idle,
  182. StreamId: "",
  183. TimeStamp: 0,
  184. }
  185. go func() {
  186. // 麦位通知
  187. this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{
  188. Reason: pb.Notify_Reason_Mic_Change,
  189. UserId: userId,
  190. SN: i,
  191. })
  192. // 下麦日志
  193. this.AddOffMicLog(userId, streamId)
  194. // 触发房间任务
  195. this.roomMgr.DoRoomTaskAction(userId, this.RoomId, pb.RoomTask_Action_OnMic, seconds)
  196. // 触发用户任务
  197. this.roomMgr.DoUserTaskAction(userId, this.RoomId, pb.UserTask_Action_OnMic, seconds, 0)
  198. // 触发大厅任务
  199. task.DoTaskAction(userId, task.TaskAction_upMicDuration, seconds, task.TaskScope{})
  200. }()
  201. return 1
  202. }
  203. return 11
  204. }
  205. // 加解锁麦(status -1=上锁 0=解锁)
  206. func (this *Room) SetMic(userId, sn int, status int) int {
  207. if status != mic_lock && status != mic_idle {
  208. return 11
  209. }
  210. for i := 0; i < len(this.mics); i++ {
  211. if i == sn {
  212. // 空闲时才允许上锁
  213. if status == mic_lock && this.mics[i].UserId > 0 {
  214. return 11
  215. }
  216. this.mics[i].UserId = status
  217. // 麦位通知
  218. go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{
  219. Reason: pb.Notify_Reason_Mic_Change,
  220. SN: i,
  221. })
  222. return 1
  223. }
  224. }
  225. return 12
  226. }
  227. // 邀请上麦(通知接收者直接调用sdk上麦)
  228. func (this *Room) InviteOnMic(userId, toUserId int) int {
  229. // 不能自己邀请自己和房主
  230. if userId == toUserId || this.UserId == toUserId {
  231. return 16
  232. }
  233. // 会员信息
  234. m := this.GetMemberInfo(userId)
  235. // 只有管理员才能发送邀请
  236. if m.RoleId != pb.Role_Administrator && m.RoleId != pb.Role_Assistant {
  237. return 16
  238. }
  239. // 同级别不能邀请
  240. toM := this.GetMemberInfo(toUserId)
  241. if toM.RoleId == m.RoleId {
  242. return 16
  243. }
  244. // 判断是否在黑名单
  245. if this.IsBlack(toUserId, pb.BlackType_Mic) {
  246. return 15
  247. }
  248. // 判断是否已占麦位
  249. if this.isOnMic(toUserId) {
  250. return 12
  251. }
  252. // 判断是否在线
  253. var isOnline bool
  254. for _, v := range this.onlineUsers {
  255. if v == toUserId {
  256. isOnline = true
  257. break
  258. }
  259. }
  260. // 非在线用户
  261. if !isOnline {
  262. return 17
  263. }
  264. for i := 0; i < len(this.mics); i++ {
  265. // 判断是否麦位空闲
  266. if !this.isMicIdle(i) {
  267. continue
  268. }
  269. // 上麦
  270. this.mics[i].UserId = toUserId
  271. this.mics[i].TimeStamp = common.GetTimeStamp()
  272. // 判断是否已申请
  273. if this.isMicApply(toUserId) {
  274. // 麦位申请删除
  275. this.delMicApply(toUserId)
  276. // 发送申请同意通知
  277. go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{
  278. Reason: pb.Notify_Reason_User_Mic_Apply_Agree,
  279. NotifyUserId: toUserId,
  280. UserId: userId,
  281. SN: i,
  282. })
  283. // 添加上麦日志
  284. go this.addOnMicLog(toUserId, userId, pb.OnMic_Apply, toM.RoleId)
  285. return 1
  286. }
  287. // 发送邀请通知
  288. go this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{
  289. Reason: pb.Notify_Reason_Mic_Invite,
  290. NotifyUserId: toUserId,
  291. UserId: userId,
  292. SN: i,
  293. })
  294. // 添加上麦日志
  295. go this.addOnMicLog(toUserId, userId, pb.OnMic_Manager, toM.RoleId)
  296. return 1
  297. }
  298. return 11
  299. }
  300. // 踢麦
  301. func (this *Room) KickMic(userId, toUserId int) int {
  302. for i := 0; i < len(this.mics); i++ {
  303. if this.mics[i].UserId != toUserId {
  304. continue
  305. }
  306. roomId := strconv.Itoa(this.RoomId)
  307. uid := strconv.Itoa(toUserId * -1)
  308. // sdk服务器 ==> 删除房间流
  309. code, message := zego.MuteUser(roomId, uid, this.mics[i].StreamId)
  310. log.Debug("room.kickMic(zego.MuteUser) i=%d userId=%s roomId=%s streamId=%s code=%d message=%s",
  311. i, uid, roomId, this.mics[i].StreamId, code, message)
  312. // 计算时长
  313. seconds := common.GetTimeStamp() - this.mics[i].TimeStamp
  314. // 清空麦位
  315. this.mics[i] = pb.MicInfo{
  316. UserId: 0,
  317. StreamId: "",
  318. TimeStamp: 0,
  319. }
  320. go func() {
  321. // 触发房间任务
  322. this.roomMgr.DoRoomTaskAction(toUserId, this.RoomId, pb.RoomTask_Action_OnMic, seconds)
  323. // 触发用户任务
  324. this.roomMgr.DoUserTaskAction(toUserId, this.RoomId, pb.UserTask_Action_OnMic, seconds, 0)
  325. // 踢麦通知
  326. this.notify(pb.Notify_Action_Refresh_Mic, pb.ReasonData{
  327. Reason: pb.Notify_Reason_Mic_Kick,
  328. UserId: toUserId,
  329. SN: i,
  330. })
  331. }()
  332. // 添加日志
  333. this.AddOperateLog(this.RoomId, userId, toUserId, pb.OperateType_KickMic)
  334. return 1
  335. }
  336. return 11
  337. }
  338. // 上麦申请列表
  339. func (this *Room) GetOnMicApplyList() []int {
  340. this.lock.RLock()
  341. defer this.lock.RUnlock()
  342. return this.micApplyList
  343. }
  344. // 申请队列信息
  345. func (this *Room) isMicApply(userId int) bool {
  346. // 判断是否已申请
  347. for _, uid := range this.micApplyList {
  348. if uid == userId {
  349. return true
  350. }
  351. }
  352. return false
  353. }
  354. // 申请上麦
  355. func (this *Room) ApplyOnMic(userId int) pb.RetMsg {
  356. var retMsg pb.RetMsg
  357. // 非申请模式
  358. if this.MicMode != pb.OnMic_Apply {
  359. retMsg.RetCode = 15
  360. retMsg.Message = "Non-application mode"
  361. return retMsg
  362. }
  363. // 是否黑名单
  364. if this.IsBlack(userId, pb.BlackType_Mic) {
  365. retMsg.RetCode = 11
  366. retMsg.Message = "blacklist users"
  367. return retMsg
  368. }
  369. // 判断是否已占麦位
  370. if this.isOnMic(userId) {
  371. retMsg.RetCode = 13
  372. retMsg.Message = "already on the mic"
  373. return retMsg
  374. }
  375. // 判断是否已申请
  376. if this.isMicApply(userId) {
  377. retMsg.RetCode = 12
  378. retMsg.Message = "Already in the application list"
  379. return retMsg
  380. }
  381. // 添加到申请列表
  382. this.micApplyList = append(this.micApplyList, userId)
  383. // 麦位申请数量变化通知
  384. go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{
  385. Reason: pb.Notify_Reason_User_Mic_Apply,
  386. MicApplyCount: len(this.micApplyList),
  387. })
  388. retMsg.RetCode = 1
  389. retMsg.Message = "successful application"
  390. return retMsg
  391. }
  392. // 取消申请上麦
  393. func (this *Room) CancelApplyOnMic(userId int) pb.RetMsg {
  394. var retMsg pb.RetMsg
  395. // 清理占麦
  396. for i := 0; i < len(this.mics); i++ {
  397. if this.mics[i].UserId != userId {
  398. continue
  399. }
  400. if this.mics[i].StreamId != "" {
  401. continue
  402. }
  403. this.mics[i].UserId = mic_idle
  404. this.mics[i].TimeStamp = 0
  405. break
  406. }
  407. // 删除申请处理
  408. this.delMicApply(userId)
  409. retMsg.RetCode = 1
  410. retMsg.Message = "Cancellation request successful"
  411. return retMsg
  412. }
  413. // 麦位申请取消或删除
  414. func (this *Room) delMicApply(toUserId int) {
  415. // 清理所有
  416. if toUserId == 0 {
  417. this.micApplyList = this.micApplyList[0:0]
  418. }
  419. // 处理申请
  420. for i := 0; i < len(this.micApplyList); i++ {
  421. if this.micApplyList[i] != toUserId {
  422. continue
  423. }
  424. this.micApplyList = append(this.micApplyList[:i], this.micApplyList[i+1:]...)
  425. break
  426. }
  427. // 麦位申请数量变化通知
  428. go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{
  429. Reason: pb.Notify_Reason_User_Mic_Apply_Cancel,
  430. MicApplyCount: len(this.micApplyList),
  431. })
  432. return
  433. }
  434. // 处理申请上麦(1=同意 2=拒绝)(通知接收者直接调用sdk上麦)
  435. func (this *Room) DealApplyOnMic(userId, toUserId, status int) pb.RetMsg {
  436. var retMsg pb.RetMsg
  437. // 判断申请状态
  438. if status != pb.MicApply_Status_Agree && status != pb.MicApply_Status_Reject {
  439. retMsg.RetCode = 11
  440. retMsg.Message = "illegal data"
  441. return retMsg
  442. }
  443. // 是否管理员
  444. if !this.isAdmin(userId) {
  445. retMsg.RetCode = 11
  446. retMsg.Message = "you are not an administrator"
  447. return retMsg
  448. }
  449. // 拒绝处理
  450. if status == pb.MicApply_Status_Reject {
  451. // 麦位申请拒绝
  452. this.delMicApply(toUserId)
  453. retMsg.RetCode = 1
  454. retMsg.Message = "refusal to succeed"
  455. return retMsg
  456. }
  457. // 判断是否有申请
  458. if !this.isMicApply(toUserId) {
  459. retMsg.RetCode = 1
  460. retMsg.Message = "Consent Request Sent"
  461. return retMsg
  462. }
  463. // 同意处理
  464. for i := 0; i < len(this.mics); i++ {
  465. // 判断是否麦位空闲
  466. if !this.isMicIdle(i) {
  467. continue
  468. }
  469. // 上麦
  470. this.mics[i].UserId = toUserId
  471. this.mics[i].TimeStamp = common.GetTimeStamp()
  472. // 麦位申请删除
  473. this.delMicApply(toUserId)
  474. // 发送通知
  475. go this.notify(pb.Notify_Action_Refresh_User, pb.ReasonData{
  476. Reason: pb.Notify_Reason_User_Mic_Apply_Agree,
  477. NotifyUserId: toUserId,
  478. UserId: userId,
  479. SN: i,
  480. })
  481. // 添加上麦日志
  482. go this.addOnMicLog(toUserId, userId, pb.OnMic_Apply, pb.Role_MAX)
  483. retMsg.RetCode = 1
  484. retMsg.Message = "Consent Request Sent"
  485. return retMsg
  486. }
  487. retMsg.RetCode = 12
  488. retMsg.Message = "Not enough free mic slots"
  489. return retMsg
  490. }
  491. // 添加上麦日志
  492. func (this *Room) addOnMicLog(userId, opUserId, micMode, roleId int) {
  493. // 无效值
  494. if roleId == pb.Role_MAX {
  495. roleId = this.GetMemberInfo(userId).RoleId
  496. }
  497. this.micLogList = append(this.micLogList, pb.MicLog{
  498. UserId: userId,
  499. RoleID: roleId,
  500. MicMode: micMode,
  501. OpUserId: opUserId,
  502. })
  503. return
  504. }
  505. // 通知上麦日志
  506. func (this *Room) notifyOnMicLog(userId, sn int, streamId string) {
  507. for k, v := range this.micLogList {
  508. if v.UserId != userId {
  509. continue
  510. }
  511. this.micLogList[k].StreamId = streamId
  512. this.micLogList[k].SN = sn
  513. this.micLogList[k].OnMicStamp = common.GetTimeStamp()
  514. break
  515. }
  516. return
  517. }
  518. // 添加下麦日志
  519. func (this *Room) AddOffMicLog(userId int, streamId string) {
  520. for i := 0; i < len(this.micLogList); i++ {
  521. v := this.micLogList[i]
  522. // 无效
  523. if v.StreamId == "" {
  524. continue
  525. }
  526. if userId > 0 && v.UserId != userId {
  527. continue
  528. }
  529. if streamId != "" && v.StreamId != streamId {
  530. continue
  531. }
  532. // 删除
  533. this.micLogList = append(this.micLogList[:i], this.micLogList[i+1:]...)
  534. ts := common.GetTimeStamp()
  535. seconds := ts - v.OnMicStamp
  536. // 数据库操作
  537. go database.AddMicLog(v.UserId, this.RoomId, v.RoleID, v.SN, v.MicMode, v.OnMicStamp, ts, seconds, v.OpUserId)
  538. // 移动索引
  539. i--
  540. }
  541. return
  542. }