MultiStreamsSorter.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. //
  2. // MultiStreamsSorter.swift
  3. // TUIRoomKit
  4. //
  5. // Created by CY zhao on 2024/12/18.
  6. //
  7. import Foundation
  8. class MultiStreamsSorter {
  9. private let currentUserId: String
  10. private var roomOwnerId: String = ""
  11. init(currentUserId: String) {
  12. self.currentUserId = currentUserId
  13. }
  14. func sortStreams(_ videoItems: [UserInfo]) -> [UserInfo] {
  15. guard needSorting(videoItems) else { return videoItems }
  16. var sortedItems = videoItems
  17. if let ownerIndex = sortedItems.firstIndex(where: { $0.userRole == .roomOwner }) {
  18. let owner = sortedItems.remove(at: ownerIndex)
  19. roomOwnerId = owner.userId
  20. sortedItems.insert(owner, at: 0)
  21. }
  22. if currentUserId != roomOwnerId,
  23. let currentUserIndex = sortedItems.firstIndex(where: { $0.userId == currentUserId }) {
  24. let currentUser = sortedItems.remove(at: currentUserIndex)
  25. sortedItems.insert(currentUser, at: 1)
  26. }
  27. let sortedOthers = sortedItems
  28. .dropFirst(currentUserId == roomOwnerId ? 1 : 2)
  29. .sorted { first, second in
  30. let firstStatus = StreamStatus(hasAudio: first.hasAudioStream,
  31. hasVideo: first.hasVideoStream)
  32. let secondStatus = StreamStatus(hasAudio: second.hasAudioStream,
  33. hasVideo: second.hasVideoStream)
  34. return firstStatus.priority < secondStatus.priority
  35. }
  36. return Array(sortedItems.prefix(currentUserId == roomOwnerId ? 1 : 2)) + sortedOthers
  37. }
  38. private func needSorting(_ videoItems: [UserInfo]) -> Bool {
  39. guard videoItems.count > 1 else { return false }
  40. if let firstUser = videoItems.first,
  41. firstUser.userRole != .roomOwner,
  42. videoItems.contains(where: { $0.userRole == .roomOwner}) {
  43. return true
  44. }
  45. if currentUserId != roomOwnerId {
  46. let currentUserExpectedPosition = 1
  47. if videoItems.count > currentUserExpectedPosition,
  48. videoItems[currentUserExpectedPosition].userId != currentUserId,
  49. videoItems.contains(where: { $0.userId == currentUserId }) {
  50. return true
  51. }
  52. }
  53. let startIndex = currentUserId == roomOwnerId ? 1 : 2
  54. guard videoItems.count > startIndex + 1 else { return false }
  55. let otherStreams = Array(videoItems[startIndex...])
  56. for i in 0..<(otherStreams.count - 1) {
  57. let current = otherStreams[i]
  58. let next = otherStreams[i + 1]
  59. let currentStreamState = StreamStatus(hasAudio: current.hasAudioStream, hasVideo: current.hasVideoStream)
  60. let nexdtStreamState = StreamStatus(hasAudio: next.hasAudioStream, hasVideo: next.hasVideoStream)
  61. if currentStreamState.priority > nexdtStreamState.priority {
  62. return true
  63. }
  64. }
  65. return false
  66. }
  67. }
  68. enum StreamStatus {
  69. case videoAndAudio
  70. case videoOnly
  71. case audioOnly
  72. case none
  73. init(hasAudio: Bool, hasVideo: Bool) {
  74. switch(hasAudio, hasVideo) {
  75. case(true, true): self = .videoAndAudio
  76. case(false, true): self = .videoOnly
  77. case(true, false): self = .audioOnly
  78. case(false, false): self = .none
  79. }
  80. }
  81. var priority: Int {
  82. switch self {
  83. case .videoAndAudio: return 0
  84. case .videoOnly: return 1
  85. case .audioOnly: return 2
  86. case .none: return 3
  87. }
  88. }
  89. }