需要添加直播接口

This commit is contained in:
cbb
2026-01-12 17:52:15 +08:00
parent 83fec2617c
commit 13af9eb303
281 changed files with 313157 additions and 104 deletions

View File

@@ -0,0 +1,43 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class AudioEffectStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = AudioEffectStoreObserver()
public func audioEffectStoreChanged(
_ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
AudioEffectStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \AudioEffectState.audioChangerType))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("audioChangerType", String(value.rawValue))
}).store(in: &cancellables)
AudioEffectStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \AudioEffectState.audioReverbType))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("audioReverbType", String(value.rawValue))
}).store(in: &cancellables)
AudioEffectStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \AudioEffectState.isEarMonitorOpened))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("isEarMonitorOpened", String(value))
}).store(in: &cancellables)
AudioEffectStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \AudioEffectState.earMonitorVolume))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("earMonitorVolume", String(value))
}).store(in: &cancellables)
}
}

View File

@@ -0,0 +1,55 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import Foundation
import RTCRoomEngine
public class BarrageStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = BarrageStoreObserver()
public func barrageStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
BarrageStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \BarrageState.messageList))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] messageList in
guard let self = self else { return }
let dict = messageList.map { self.convertBarrageToDic(barrage: $0) }
if let jsonList = JsonUtil.toJson(dict) {
callback("messageList", jsonList)
}
}).store(in: &cancellables)
// TODO:
// BarrageStore.create(liveID: liveID)
// .state.subscribe(StatePublisherSelector(keyPath: \BarrageState.allowSendMessage))
// .receive(on: DispatchQueue.main)
// .sink(receiveValue: { message in
// callback("allowSendMessage", String(message))
// }).store(in: &cancellables)
}
private func convertBarrageToDic(barrage: Barrage) -> [String: Any] {
var dict: [String: Any] = [
"liveID": barrage.liveID,
"sender": TypeConvert.convertLiveUserInfoToDic(liveUserInfo: barrage.sender),
"sequence": barrage.sequence,
"timestampInSecond": barrage.timestampInSecond,
"messageType": convertMessageType(barrage.messageType),
"textContent": barrage.textContent,
"extensionInfo": barrage.extensionInfo,
"businessID": barrage.businessID,
"data": barrage.data,
]
return dict
}
private func convertMessageType(_ type: BarrageType) -> String {
if type == BarrageType.custom {
return "CUSTOM"
}
return "TEXT"
}
}

View File

@@ -0,0 +1,34 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class BaseBeautyStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = BaseBeautyStoreObserver()
public func beautyStoreChanged(_ callback: @escaping (_ name: String, _ data: String) -> Void) {
cancellables.removeAll()
BaseBeautyStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \BaseBeautyState.smoothLevel))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("smoothLevel", String(value))
}).store(in: &cancellables)
BaseBeautyStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \BaseBeautyState.whitenessLevel))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("whitenessLevel", String(value))
}).store(in: &cancellables)
BaseBeautyStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \BaseBeautyState.ruddyLevel))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("ruddyLevel", String(value))
}).store(in: &cancellables)
}
}

View File

@@ -0,0 +1,166 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class BattleStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var battleEventCancellables = Set<AnyCancellable>()
public static let shared = BattleStoreObserver()
public func battleStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
BattleStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \BattleState.currentBattleInfo))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] currentBattleInfo in
guard let self = self else { return }
if let battleInfo = currentBattleInfo {
if let json = JsonUtil.toJson(
self.convertBattleInfoToDic(battleInfo: battleInfo))
{
callback("currentBattleInfo", json)
}
}
}).store(in: &cancellables)
BattleStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \BattleState.battleUsers))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] battleUsers in
guard let self = self else { return }
let userList = battleUsers.map {
TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0)
}
if let json = JsonUtil.toJson(userList) {
callback("battleUsers", json)
}
}).store(in: &cancellables)
BattleStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \BattleState.battleScore))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] battleScore in
guard let self = self else { return }
if let json = JsonUtil.toJson(battleScore) {
callback("battleScore", json)
}
}).store(in: &cancellables)
}
private func convertBattleInfoToDic(battleInfo: BattleInfo) -> [String: Any] {
return [
"battleID": battleInfo.battleID,
"config": convertBattleConfigToDic(config: battleInfo.config),
"startTime": battleInfo.startTime,
"endTime": battleInfo.endTime,
]
}
private func convertBattleConfigToDic(config: BattleConfig) -> [String: Any] {
return [
"duration": config.duration,
"needResponse": config.needResponse,
"extensionInfo": config.extensionInfo,
]
}
public func setupBattleEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
battleEventCancellables.removeAll()
BattleStore.create(liveID: liveID).battleEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onBattleStarted(let battleInfo, let inviter, let invitees):
let dict: [String: Any] = [
"battleInfo": self.convertBattleInfoToDic(battleInfo: battleInfo),
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitees": invitees.map {
TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0)
},
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleStarted", json)
}
case .onBattleEnded(let battleInfo, let reason):
let reasonStr = reason == .allMemberExit ? "ALL_MEMBER_EXIT" : "TIME_OVER"
let dict: [String: Any] = [
"battleInfo": self.convertBattleInfoToDic(battleInfo: battleInfo),
"reason": reasonStr,
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleEnded", json)
}
case .onUserJoinBattle(let battleID, let battleUser):
let dict: [String: Any] = [
"battleID": battleID,
"battleUser": TypeConvert.convertSeatUserInfoToDic(
seatUserInfo: battleUser),
]
if let json = JsonUtil.toJson(dict) {
callback("onUserJoinBattle", json)
}
case .onUserExitBattle(let battleID, let battleUser):
let dict: [String: Any] = [
"battleID": battleID,
"battleUser": TypeConvert.convertSeatUserInfoToDic(
seatUserInfo: battleUser),
]
if let json = JsonUtil.toJson(dict) {
callback("onUserExitBattle", json)
}
case .onBattleRequestReceived(let battleID, let inviter, let invitee):
let dict: [String: Any] = [
"battleID": battleID,
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleRequestReceived", json)
}
case .onBattleRequestCancelled(let battleID, let inviter, let invitee):
let dict: [String: Any] = [
"battleID": battleID,
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleRequestCancelled", json)
}
case .onBattleRequestTimeout(let battleID, let inviter, let invitee):
let dict: [String: Any] = [
"battleID": battleID,
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleRequestTimeout", json)
}
case .onBattleRequestAccept(let battleID, let inviter, let invitee):
let dict: [String: Any] = [
"battleID": battleID,
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleRequestAccept", json)
}
case .onBattleRequestReject(let battleID, let inviter, let invitee):
let dict: [String: Any] = [
"battleID": battleID,
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onBattleRequestReject", json)
}
}
}.store(in: &battleEventCancellables)
}
}

View File

@@ -0,0 +1,145 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class CoGuestStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var hostEventCancellables = Set<AnyCancellable>()
private var guestEventCancellables = Set<AnyCancellable>()
public static let shared = CoGuestStoreObserver()
public func coGuestStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
CoGuestStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \CoGuestState.connected))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { arr in
let dict = arr.map { TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0) }
if let json = JsonUtil.toJson(dict) {
callback("connected", json)
}
}).store(in: &cancellables)
let arrayKeys: [(String, KeyPath<CoGuestState, [LiveUserInfo]>)] = [
("invitees", \CoGuestState.invitees),
("applicants", \CoGuestState.applicants),
("candidates", \CoGuestState.candidates),
]
for (key, kp) in arrayKeys {
CoGuestStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: kp))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { arr in
let dict = arr.map { TypeConvert.convertLiveUserInfoToDic(liveUserInfo: $0) }
if let json = JsonUtil.toJson(dict) {
callback(key, json)
}
}).store(in: &cancellables)
}
}
public func setupHostEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
hostEventCancellables.removeAll()
CoGuestStore.create(liveID: liveID).hostEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onGuestApplicationReceived(let guestUser):
let dict: [String: Any] = [
"guestUser" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: guestUser)
]
if let json = JsonUtil.toJson(dict) {
callback("onGuestApplicationReceived", json)
}
case .onGuestApplicationCancelled(let guestUser):
let dict: [String: Any] = [
"guestUser" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: guestUser)
]
if let json = JsonUtil.toJson(dict) {
callback("onGuestApplicationCancelled", json)
}
case .onGuestApplicationProcessedByOtherHost(let guestUser, let hostUser):
var dict: [String: Any] = [:]
dict["guestUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: guestUser)
dict["hostUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: hostUser)
if let json = JsonUtil.toJson(dict) {
callback("onGuestApplicationProcessedByOtherHost", json)
}
case .onHostInvitationResponded(let isAccept, let guestUser):
var dict: [String: Any] = [:]
dict["isAccept"] = isAccept
dict["guestUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: guestUser)
if let json = JsonUtil.toJson(dict) {
callback("onHostInvitationResponded", json)
}
case .onHostInvitationNoResponse(let guestUser, let reason):
var dict: [String: Any] = [:]
dict["guestUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: guestUser)
dict["reason"] = convertNoResponseReason(reason)
if let json = JsonUtil.toJson(dict) {
callback("onHostInvitationNoResponse", json)
}
}
}.store(in: &hostEventCancellables)
}
private func convertNoResponseReason(_ reason: NoResponseReason) -> String {
if reason == NoResponseReason.alreadySeated {
return "ALREADY_SEATED"
}
return "TIMEOUT"
}
public func setupGuestEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
guestEventCancellables.removeAll()
CoGuestStore.create(liveID: liveID).guestEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onHostInvitationReceived(let hostUser):
let dict: [String: Any] = [
"hostUser" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: hostUser)
]
if let json = JsonUtil.toJson(dict) {
callback("onHostInvitationReceived", json)
}
case .onHostInvitationCancelled(let hostUser):
let dict: [String: Any] = [
"hostUser" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: hostUser)
]
if let json = JsonUtil.toJson(dict) {
callback("onHostInvitationCancelled", json)
}
case .onGuestApplicationResponded(let isAccept, let hostUser):
var dict: [String: Any] = [:]
dict["isAccept"] = isAccept
dict["hostUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: hostUser)
if let json = JsonUtil.toJson(dict) {
callback("onGuestApplicationResponded", json)
}
case .onGuestApplicationNoResponse(let reason):
var dict: [String: Any] = [:]
dict["reason"] = convertNoResponseReason(reason)
if let json = JsonUtil.toJson(dict) {
callback("onGuestApplicationNoResponse", json)
}
case .onKickedOffSeat(let seatIndex, let hostUser):
var dict: [String: Any] = [:]
dict["seatIndex"] = seatIndex
dict["hostUser"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: hostUser)
if let json = JsonUtil.toJson(dict) {
callback("onKickedOffSeat", json)
}
}
}.store(in: &guestEventCancellables)
}
}

View File

@@ -0,0 +1,138 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class CoHostStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var coHostEventCancellables = Set<AnyCancellable>()
public static let shared = CoHostStoreObserver()
public func coHostStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
CoHostStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \CoHostState.coHostStatus))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
var coHostStatus = "DISCONNECTED"
if value == .connected {
coHostStatus = "CONNECTED"
}
if let json = JsonUtil.toJson(coHostStatus) {
callback("coHostStatus", json)
}
}).store(in: &cancellables)
CoHostStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \CoHostState.connected))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { arr in
let dict = arr.map { TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0) }
if let json = JsonUtil.toJson(dict) {
callback("connected", json)
}
}).store(in: &cancellables)
//TODO:
// CoHostStore.create(liveID: liveID)
// .state.subscribe(StatePublisherSelector(keyPath: \CoHostState.candidates))
// .receive(on: DispatchQueue.main)
// .sink(receiveValue: { arr in
// let dict = arr.map { TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0) }
// if let json = JsonUtil.toJson(dict) {
// callback("candidates", json)
// }
// }).store(in: &cancellables)
CoHostStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \CoHostState.invitees))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { arr in
let dict = arr.map { TypeConvert.convertSeatUserInfoToDic(seatUserInfo: $0) }
if let json = JsonUtil.toJson(dict) {
callback("invitees", json)
}
}).store(in: &cancellables)
CoHostStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \CoHostState.applicant))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] value in
guard let self = self else { return }
guard let value = value else { return }
let userInfo = TypeConvert.convertSeatUserInfoToDic(seatUserInfo: value)
if let json = JsonUtil.toJson(userInfo) {
callback("applicant", json)
}
}).store(in: &cancellables)
}
public func setupCoHostEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
coHostEventCancellables.removeAll()
CoHostStore.create(liveID: liveID).coHostEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onCoHostRequestReceived(let inviter, let extensionInfo):
var dict: [String: Any] = [
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"extensionInfo": extensionInfo,
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostRequestReceived", json)
}
case .onCoHostRequestCancelled(let inviter, let invitee):
var dict: [String: Any] = [
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
]
if let invitee = invitee {
dict["invitee"] = TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee)
}
if let json = JsonUtil.toJson(dict) {
callback("onCoHostRequestCancelled", json)
}
case .onCoHostRequestAccepted(let invitee):
var dict: [String: Any] = [
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee)
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostRequestAccepted", json)
}
case .onCoHostRequestRejected(let invitee):
var dict: [String: Any] = [
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee)
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostRequestRejected", json)
}
case .onCoHostRequestTimeout(let inviter, let invitee):
var dict: [String: Any] = [
"inviter": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: inviter),
"invitee": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: invitee),
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostRequestTimeout", json)
}
case .onCoHostUserJoined(let userInfo):
var dict: [String: Any] = [
"userInfo": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: userInfo)
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostUserJoined", json)
}
case .onCoHostUserLeft(let userInfo):
var dict: [String: Any] = [
"userInfo": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: userInfo)
]
if let json = JsonUtil.toJson(dict) {
callback("onCoHostUserLeft", json)
}
}
}.store(in: &coHostEventCancellables)
}
}

View File

@@ -0,0 +1,166 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class DeviceStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = DeviceStoreObserver()
public func deviceStoreChanged(_ callback: @escaping (_ name: String, _ data: String) -> Void) {
cancellables.removeAll()
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.microphoneStatus))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("microphoneStatus", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.microphoneLastError))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("microphoneLastError", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.captureVolume))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("captureVolume", String(value))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.currentMicVolume))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("currentMicVolume", String(value))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.outputVolume))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("outputVolume", String(value))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.cameraStatus))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("cameraStatus", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.cameraLastError))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("cameraLastError", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.isFrontCamera))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("isFrontCamera", String(value))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.localMirrorType))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] value in
guard let self = self else { return }
if let json = JsonUtil.toJson(convertLocalMirrorType(value)) {
callback("localMirrorType", json)
}
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.localVideoQuality))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] value in
guard let self = self else { return }
callback("localVideoQuality", convertVideoQuality(value))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.currentAudioRoute))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("currentAudioRoute", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.screenStatus))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
callback("screenStatus", String(value.rawValue))
}).store(in: &cancellables)
DeviceStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \DeviceState.networkInfo))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] value in
guard let self = self else { return }
if let json = JsonUtil.toJson(convertNetworkInfo(value)) {
callback("networkInfo", json)
}
}).store(in: &cancellables)
}
private func convertNetworkInfo(_ info: NetworkInfo) -> [String: Any] {
var map = [String: Any]()
map["userID"] = info.userID ?? ""
map["quality"] = convertNetworkQuality(info.quality)
map["upLoss"] = info.upLoss
map["downLoss"] = info.downLoss
map["delay"] = info.delay
return map
}
private func convertNetworkQuality(_ quality: NetworkQuality?) -> String {
guard let quality = quality else {
return "UNKNOWN"
}
switch quality {
case .excellent:
return "EXCELLENT"
case .good:
return "GOOD"
case .poor:
return "POOR"
case .veryBad:
return "VBAD"
case .bad:
return "BAD"
case .down:
return "DOWN"
default:
return "UNKNOWN"
}
}
private func convertVideoQuality(_ quality: VideoQuality) -> String {
switch quality {
case VideoQuality.quality540P:
return "540P"
case VideoQuality.quality720P:
return "720P"
case VideoQuality.quality1080P:
return "1080P"
default:
return "360P"
}
}
private func convertLocalMirrorType(_ type: MirrorType) -> String {
switch type {
case MirrorType.enable:
return "ENABLE"
case MirrorType.disable:
return "DISABLE"
default:
return "AUTO"
}
}
}

View File

@@ -0,0 +1,74 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class GiftStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var giftEventCancellables = Set<AnyCancellable>()
public static let shared = GiftStoreObserver()
public func giftStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
GiftStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \GiftState.usableGifts))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] usableGifts in
guard let self = self else { return }
let dict = usableGifts.map { self.convertGiftCategoryToDic(giftCategory: $0) }
if let jsonList = JsonUtil.toJson(dict) {
callback("usableGifts", jsonList)
}
}).store(in: &cancellables)
}
private func convertGiftCategoryToDic(giftCategory: GiftCategory) -> [String: Any] {
var gifts: [[String: Any]] = []
for info in giftCategory.giftList {
gifts.append(convertGiftToDic(gift: info))
}
return [
"categoryID": giftCategory.categoryID,
"name": giftCategory.name,
"desc": giftCategory.desc,
"extensionInfo": giftCategory.extensionInfo,
"giftList": gifts,
]
}
private func convertGiftToDic(gift: Gift) -> [String: Any] {
return [
"giftID": gift.giftID,
"name": gift.name,
"desc": gift.desc,
"iconURL": gift.iconURL,
"resourceURL": gift.resourceURL,
"level": gift.level,
"coins": gift.coins,
"extensionInfo": gift.extensionInfo,
]
}
public func setupGiftEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
giftEventCancellables.removeAll()
GiftStore.create(liveID: liveID).giftEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onReceiveGift(let liveID, let gift, let count, let sender):
var dict: [String: Any] = [:]
dict["liveID"] = liveID
dict["gift"] = self.convertGiftToDic(gift: gift)
dict["count"] = count
dict["sender"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: sender)
if let json = JsonUtil.toJson(dict) {
callback("onReceiveGift", json)
}
}
}.store(in: &giftEventCancellables)
}
}

View File

@@ -0,0 +1,41 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class LikeStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var likeEventCancellables = Set<AnyCancellable>()
public static let shared = LikeStoreObserver()
public func likeStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
LikeStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LikeState.totalLikeCount))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { totalLikeCount in
callback("totalLikeCount", String(totalLikeCount))
}).store(in: &cancellables)
}
public func setupLikeEvent(_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void) {
likeEventCancellables.removeAll()
LikeStore.create(liveID: liveID).likeEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onReceiveLikesMessage(liveID: let liveID, totalLikesReceived: let totalLikesReceived, sender: let sender):
var dict: [String: Any] = [:]
dict["liveID"] = liveID
dict["totalLikesReceived"] = totalLikesReceived
dict["sender"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: sender)
if let json = JsonUtil.toJson(dict) {
callback("onReceiveLikesMessage", json)
}
}
}.store(in: &likeEventCancellables)
}
}

View File

@@ -0,0 +1,71 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class LiveAudienceStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var audienceCancellables = Set<AnyCancellable>()
public static let shared = LiveAudienceStoreObserver()
public func liveAudienceStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
LiveAudienceStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveAudienceState.audienceList))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { audienceList in
let dict = audienceList.map {
TypeConvert.convertLiveUserInfoToDic(liveUserInfo: $0)
}
if let jsonList = JsonUtil.toJson(dict) {
callback("audienceList", jsonList)
}
})
.store(in: &cancellables)
LiveAudienceStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveAudienceState.audienceCount))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { count in
callback("audienceCount", String(count))
}).store(in: &cancellables)
}
public func setupAudienceEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
audienceCancellables.removeAll()
LiveAudienceStore.create(liveID: liveID).liveAudienceEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onAudienceJoined(let audience):
let dict: [String: Any] = [
"audience" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: audience)
]
if let json = JsonUtil.toJson(dict) {
callback("onAudienceJoined", json)
}
case .onAudienceMessageDisabled(let audience, let isDisable):
var dict: [String: Any] = [:]
dict["isDisable"] = isDisable
dict["audience"] = TypeConvert.convertLiveUserInfoToDic(liveUserInfo: audience)
if let json = JsonUtil.toJson(dict) {
callback("onAudienceMessageDisabled", json)
}
case .onAudienceLeft(let audience):
let dict: [String: Any] = [
"audience" : TypeConvert.convertLiveUserInfoToDic(liveUserInfo: audience)
]
if let json = JsonUtil.toJson(dict) {
callback("onAudienceLeft", json)
}
break
}
}.store(in: &audienceCancellables)
}
}

View File

@@ -0,0 +1,97 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import Foundation
import RTCRoomEngine
public class LiveListStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var liveListEventCancellables = Set<AnyCancellable>()
public static let shared = LiveListStoreObserver()
public func liveStoreChanged(_ callback: @escaping (_ name: String, _ data: String) -> Void) {
cancellables.removeAll()
LiveListStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \LiveListState.liveList))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] liveList in
guard let self = self else { return }
let dict = liveList.map { TypeConvert.convertLiveInfoToDic(liveInfo: $0) }
if let jsonList = JsonUtil.toJson(dict) {
callback("liveList", jsonList)
}
}).store(in: &cancellables)
LiveListStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \LiveListState.liveListCursor))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { liveListCursor in
if let json = JsonUtil.toJson(liveListCursor) {
callback("liveListCursor", json)
}
}).store(in: &cancellables)
LiveListStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \LiveListState.currentLive))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] liveInfo in
guard let self = self else { return }
let dict = TypeConvert.convertLiveInfoToDic(liveInfo: liveInfo)
if let json = JsonUtil.toJson(dict) {
callback("currentLive", json)
}
}).store(in: &cancellables)
}
public func setupLiveListEvent(_ callback: @escaping (_ name: String, _ data: String) -> Void) {
liveListEventCancellables.removeAll()
LiveListStore.shared.liveListEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onLiveEnded(let liveID, let reason, let message):
var dict: [String: Any] = [:]
dict["liveID"] = liveID
dict["reason"] = convertLiveEndedReason(reason)
dict["message"] = message
if let json = JsonUtil.toJson(dict) {
callback("onLiveEnded", json)
}
case .onKickedOutOfLive(let liveID, let reason, let message):
var dict: [String: Any] = [:]
dict["liveID"] = liveID
dict["reason"] = convertLiveKickedOutReason(reason)
dict["message"] = message
if let json = JsonUtil.toJson(dict) {
callback("onKickedOutOfLive", json)
}
}
}.store(in: &liveListEventCancellables)
}
private func convertLiveEndedReason(_ reason: LiveEndedReason) -> String {
if reason == LiveEndedReason.endedByServer {
return "ENDED_BY_SERVER"
}
return "ENDED_BY_HOST"
}
private func convertLiveKickedOutReason(_ reason: LiveKickedOutReason) -> String {
switch reason {
case .byLoggedOnOtherDevice:
return "BY_LOGGED_ON_OTHER_DEVICE"
case .byServer:
return "BY_SERVER"
case .forNetworkDisconnected:
return "FOR_NETWORK_DISCONNECTED"
case .forJoinRoomStatusInvalidDuringOffline:
return "FOR_JOIN_ROOM_STATUS_INVALID_DURING_OFFLINE"
case .forCountOfJoinedRoomsExceedLimit:
return "FOR_COUNT_OF_JOINED_ROOMS_EXCEED_LIMIT"
default:
return "BY_ADMIN"
}
}
}

View File

@@ -0,0 +1,104 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import Foundation
import RTCRoomEngine
public class LiveSeatStoreObserver {
private var cancellables = Set<AnyCancellable>()
private var liveSeatEventCancellables = Set<AnyCancellable>()
public static let shared = LiveSeatStoreObserver()
public func liveSeatStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
LiveSeatStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveSeatState.seatList))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] seatList in
guard let self = self else { return }
let dictArray = seatList.map { self.convertSeatInfoToDic(seatInfo: $0) }
if let jsonList = JsonUtil.toJson(dictArray) {
callback("seatList", jsonList)
}
}).store(in: &cancellables)
LiveSeatStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveSeatState.canvas))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] canvas in
guard let self = self else { return }
let dict = self.convertCanvasToDic(canvas: canvas)
if let json = JsonUtil.toJson(dict) {
callback("canvas", json)
}
}).store(in: &cancellables)
LiveSeatStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveSeatState.speakingUsers))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { speakingUsers in
if let jsonUsers = JsonUtil.toJson(speakingUsers) {
callback("speakingUsers", jsonUsers)
}
}).store(in: &cancellables)
}
private func convertSeatInfoToDic(seatInfo: SeatInfo) -> [String: Any] {
var dict: [String: Any] = [
"index": seatInfo.index,
"isLocked": seatInfo.isLocked,
"userInfo": TypeConvert.convertSeatUserInfoToDic(seatUserInfo: seatInfo.userInfo),
"region": convertRegionInfoToDic(region: seatInfo.region),
]
return dict
}
private func convertRegionInfoToDic(region: RegionInfo) -> [String: Any] {
return [
"x": region.x,
"y": region.y,
"w": region.w,
"h": region.h,
"zorder": region.zorder,
]
}
private func convertCanvasToDic(canvas: LiveCanvas) -> [String: Any] {
return [
"templateID": canvas.templateID,
"w": canvas.w,
"h": canvas.h,
]
}
public func setupLiveSeatEvent(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
liveSeatEventCancellables.removeAll()
LiveSeatStore.create(liveID: liveID).liveSeatEventPublisher
.receive(on: RunLoop.main)
.sink { [weak self] event in
guard let self = self else { return }
switch event {
case .onLocalCameraOpenedByAdmin(let policy):
callback("onLocalCameraOpenedByAdmin", convertDeviceControlPolicy(policy))
case .onLocalCameraClosedByAdmin:
callback("onLocalCameraClosedByAdmin", "")
case .onLocalMicrophoneOpenedByAdmin(let policy):
callback("onLocalMicrophoneOpenedByAdmin", convertDeviceControlPolicy(policy))
case .onLocalMicrophoneClosedByAdmin:
callback("onLocalMicrophoneClosedByAdmin", "")
}
}.store(in: &liveSeatEventCancellables)
}
private func convertDeviceControlPolicy(_ reason: DeviceControlPolicy) -> String {
if reason == DeviceControlPolicy.unlockOnly {
return "UNLOCK_ONLY"
}
return "FORCE_OPEN"
}
}

View File

@@ -0,0 +1,25 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class LiveSummaryStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = LiveSummaryStoreObserver()
public func liveSummaryStoreChanged(
_ liveID: String, _ callback: @escaping (_ name: String, _ data: String) -> Void
) {
cancellables.removeAll()
LiveSummaryStore.create(liveID: liveID)
.state.subscribe(StatePublisherSelector(keyPath: \LiveSummaryState.summaryData))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { data in
let dict = TypeConvert.convertLiveSummaryDataToDic(summaryData: data)
if let json = JsonUtil.toJson(dict) {
callback("summaryData", json)
}
}).store(in: &cancellables)
}
}

View File

@@ -0,0 +1,70 @@
import AtomicXCore
import Combine
import DCloudUTSFoundation
import RTCRoomEngine
public class LoginStoreObserver {
private var cancellables = Set<AnyCancellable>()
public static let shared = LoginStoreObserver()
public func loginStoreChanged(_ callback: @escaping (_ name: String, _ data: String) -> Void) {
cancellables.removeAll()
LoginStore.shared
.state.subscribe(StatePublisherSelector(keyPath: \LoginState.loginUserInfo))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] userInfo in
guard let self = self else { return }
guard let userInfo = userInfo else { return }
if let jsonString = JsonUtil.toJson(
self.converUserProfileToDic(userProfile: userInfo))
{
callback("loginUserInfo", jsonString)
}
}).store(in: &cancellables)
LoginStore.shared.state.subscribe(StatePublisherSelector(keyPath: \LoginState.loginStatus))
.receive(on: DispatchQueue.main)
.sink(receiveValue: { value in
var loginStatus = "UNLOGIN"
if value == .logined {
loginStatus = "LOGINED"
}
if let json = JsonUtil.toJson(loginStatus) {
callback("loginStatus", json)
}
}).store(in: &cancellables)
}
private func converUserProfileToDic(userProfile: UserProfile) -> [String: Any] {
return [
"userID": userProfile.userID,
"nickname": userProfile.nickname,
"avatarURL": userProfile.avatarURL,
"selfSignature": userProfile.selfSignature,
"gender": convertGender(gender: userProfile.gender),
"role": userProfile.role,
"level": userProfile.level,
"allowType": convertAllowType(type: userProfile.allowType),
// "customInfo": userProfile.customInfo, //TODO:
]
}
private func convertGender(gender: Gender?) -> String {
var genderStr = "UNKNOWN"
if( gender == .male) {
genderStr = "MALE"
} else if( gender == .female) {
genderStr = "FEMALE"
}
return genderStr
}
private func convertAllowType(type: AllowType?) -> String {
var allowType = "ALLOW_ANY"
if(type == .needConfirm) {
allowType = "NEED_CONFIRM"
} else if(type == .denyAny) {
allowType = "DENY_ANY"
}
return allowType
}
}

View File

@@ -0,0 +1,96 @@
import AtomicXCore
import RTCRoomEngine
struct TypeConvert {
static func convertLiveUserInfoToDic(liveUserInfo: LiveUserInfo) -> [String: String] {
var dict: [String: String] = [
"userID": liveUserInfo.userID ?? "",
"userName": liveUserInfo.userName ?? "",
"avatarURL": liveUserInfo.avatarURL ?? "",
]
return dict
}
static func convertUserRole(_ role: Role?) -> String {
switch role {
case .admin:
return "ADMIN"
case .generalUser:
return "GENERAL_USER"
default:
return "OWNER"
}
}
static func convertSeatUserInfoToDic(seatUserInfo: SeatUserInfo) -> [String: Any] {
var dict: [String: Any] = [
"userID": seatUserInfo.userID,
"userName": seatUserInfo.userName ?? "",
"avatarURL": seatUserInfo.avatarURL ?? "",
"role": convertUserRole(seatUserInfo.role),
"liveID": seatUserInfo.liveID,
"microphoneStatus": convertDeviceStatus(seatUserInfo.microphoneStatus),
"allowOpenMicrophone": seatUserInfo.allowOpenMicrophone,
"cameraStatus": convertDeviceStatus(seatUserInfo.cameraStatus),
"allowOpenCamera": seatUserInfo.allowOpenCamera,
]
return dict
}
static func convertDeviceStatus(_ status: DeviceStatus) -> String {
switch status {
case .on:
return "ON"
case .off:
return "OFF"
}
}
static func convertLiveInfoToDic(liveInfo: LiveInfo) -> [String: Any] {
var dict: [String: Any] = [
"liveID": liveInfo.liveID,
"liveName": liveInfo.liveName,
"notice": liveInfo.notice,
"isMessageDisable": liveInfo.isMessageDisable,
"isPublicVisible": liveInfo.isPublicVisible,
"isSeatEnabled": liveInfo.isSeatEnabled,
"keepOwnerOnSeat": liveInfo.keepOwnerOnSeat,
"maxSeatCount": liveInfo.maxSeatCount,
"seatMode": TypeConvert.convertTakeSeatMode(liveInfo.seatMode),
"seatLayoutTemplateID": liveInfo.seatLayoutTemplateID,
"coverURL": liveInfo.coverURL,
"backgroundURL": liveInfo.backgroundURL,
"activityStatus": liveInfo.activityStatus,
"liveOwner": TypeConvert.convertLiveUserInfoToDic(liveUserInfo: liveInfo.liveOwner),
"createTime" : liveInfo.createTime,
"categoryList": liveInfo.categoryList,
"totalViewerCount": liveInfo.totalViewerCount,
"isGiftEnabled": liveInfo.isGiftEnabled,
"metaData": liveInfo.metaData,
]
return dict
}
static func convertTakeSeatMode(_ mode: TakeSeatMode) -> String {
switch mode {
case .free:
return "FREE"
case .apply:
return "APPLY"
}
}
static func convertLiveSummaryDataToDic(summaryData: LiveSummaryData) -> [String: Any] {
var dict: [String: Any] = [
"totalDuration": summaryData.totalDuration,
"totalViewers": summaryData.totalViewers,
"totalGiftsSent": summaryData.totalGiftsSent,
"totalGiftUniqueSenders": summaryData.totalGiftUniqueSenders,
"totalGiftCoins": summaryData.totalGiftCoins,
"totalLikesReceived": summaryData.totalLikesReceived,
"totalMessageSent": summaryData.totalMessageSent,
]
return dict
}
}