import SRTC
import SwiftUI
@MainActor
final class RoomViewModel: ObservableObject, ChannelDelegate {
@Published var localTrack: LocalCameraTrack?
@Published var remoteTrack: Track?
private let srtc = SRTC()
private var channel: Channel?
private var micTrack: LocalMicTrack?
func join(with token: String) async throws {
srtc.logLevel = .debug
let channel = try await srtc.joinChannel(
token: token,
options: JoinOptions(autoSubscribeAudio: true)
)
channel.delegates.add(delegate: self)
self.channel = channel
let micTrack = srtc.createLocalMicTrack(preset: .music)
try await micTrack.startCapture()
try await channel.publishLocalTrack(micTrack)
self.micTrack = micTrack
let cameraTrack = srtc.createLocalCameraTrack(preset: .h720p)
try await cameraTrack.startCapture()
try await channel.publishLocalTrack(cameraTrack)
self.localTrack = cameraTrack
}
func leave() async {
// SDK 内部自动停止采集、取消发布,业务层只需清除引用
await srtc.leaveChannel()
channel = nil
micTrack = nil
localTrack = nil
remoteTrack = nil
}
func channel(_ channel: Channel, user: UserInfo, didAddTrack track: TrackInfo) {
guard track.kind == .video else { return }
Task {
try? await channel.subscribeRemoteVideoTrack(uid: user.uid, trackId: track.id)
let subscribedTrack = channel.getRemoteTrack(uid: user.uid, trackId: track.id)
await MainActor.run {
self.remoteTrack = subscribedTrack
}
}
}
}
struct RoomView: View {
@StateObject private var vm = RoomViewModel()
let token: String
var body: some View {
VStack(spacing: 12) {
if let localTrack = vm.localTrack {
SRTCVideoView(track: localTrack)
.frame(height: 220)
}
if let remoteTrack = vm.remoteTrack {
SRTCVideoView(track: remoteTrack)
.frame(height: 220)
}
HStack {
Button("加入频道") {
Task { try? await vm.join(with: token) }
}
Button("离开频道") {
Task { await vm.leave() }
}
}
}
.padding()
}
}