提交
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
//
|
||||
// MediaSettingViewModel.swift
|
||||
// TUIRoomKit
|
||||
//
|
||||
// Created by janejntang on 2023/1/16.
|
||||
// Copyright © 2023 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RTCRoomEngine
|
||||
#if canImport(TXLiteAVSDK_TRTC)
|
||||
import TXLiteAVSDK_TRTC
|
||||
#elseif canImport(TXLiteAVSDK_Professional)
|
||||
import TXLiteAVSDK_Professional
|
||||
#endif
|
||||
|
||||
protocol MediaSettingViewEventResponder: AnyObject {
|
||||
func showResolutionAlert()
|
||||
func showFrameRateAlert()
|
||||
func showQualityView()
|
||||
func updateStackView(item: ListCellItemData)
|
||||
func makeToast(text: String)
|
||||
}
|
||||
|
||||
class MediaSettingViewModel {
|
||||
private(set) var videoItems: [ListCellItemData] = []
|
||||
private(set) var audioItems: [ListCellItemData] = []
|
||||
private(set) var otherItems: [ListCellItemData] = []
|
||||
weak var viewResponder: MediaSettingViewEventResponder? = nil
|
||||
var engineManager: EngineManager {
|
||||
EngineManager.shared
|
||||
}
|
||||
var store: RoomStore {
|
||||
engineManager.store
|
||||
}
|
||||
var videoSetting: VideoModel {
|
||||
engineManager.store.videoSetting
|
||||
}
|
||||
var audioSetting: AudioModel {
|
||||
engineManager.store.audioSetting
|
||||
}
|
||||
let resolutionNameItems: [String] = [.smoothResolutionText, .standardResolutionText, .highResolutionText, .superResolutionText]
|
||||
private let resolutionItems: [TUIVideoQuality] = [.quality360P, .quality540P, .quality720P, .quality1080P]
|
||||
private let bitrateArray = [550, 850, 1_200, 2_000]
|
||||
let topItems: [String] = [.videoText, .audioText, .otherText]
|
||||
let frameRateArray = ["15", "20"]
|
||||
|
||||
init() {
|
||||
createVideoItem()
|
||||
createAudioItem()
|
||||
createOtherItem()
|
||||
}
|
||||
|
||||
private func createVideoItem() {
|
||||
let resolutionItem = ListCellItemData()
|
||||
resolutionItem.titleText = .resolutionText
|
||||
resolutionItem.hasOverAllAction = true
|
||||
resolutionItem.type = .resolutionType
|
||||
resolutionItem.hasDownLineView = true
|
||||
resolutionItem.hasRightButton = true
|
||||
let buttonData = ButtonItemData()
|
||||
if let resolutionName = getResolutionName(videoQuality: videoSetting.videoQuality) {
|
||||
buttonData.normalTitle = resolutionName
|
||||
}
|
||||
buttonData.orientation = .right
|
||||
buttonData.normalIcon = "room_down_arrow1"
|
||||
buttonData.resourceBundle = tuiRoomKitBundle()
|
||||
buttonData.titleFont = UIFont.systemFont(ofSize: 16, weight: .regular)
|
||||
buttonData.titleColor = UIColor(0xD1D9EC)
|
||||
buttonData.size = CGSize(width: 80, height: 30)
|
||||
buttonData.isEnabled = false
|
||||
resolutionItem.buttonData = buttonData
|
||||
resolutionItem.action = { [weak self] sender in
|
||||
guard let self = self else { return }
|
||||
self.resolutionAction()
|
||||
}
|
||||
videoItems.append(resolutionItem)
|
||||
|
||||
let frameRateItem = ListCellItemData()
|
||||
frameRateItem.titleText = .frameRateText
|
||||
frameRateItem.hasOverAllAction = true
|
||||
frameRateItem.type = .frameRateType
|
||||
frameRateItem.hasRightButton = true
|
||||
let frameRateButtonData = ButtonItemData()
|
||||
frameRateButtonData.orientation = .right
|
||||
frameRateButtonData.normalIcon = "room_down_arrow1"
|
||||
frameRateButtonData.normalTitle = String(videoSetting.videoFps)
|
||||
frameRateButtonData.resourceBundle = tuiRoomKitBundle()
|
||||
frameRateButtonData.titleFont = UIFont.systemFont(ofSize: 16, weight: .regular)
|
||||
frameRateButtonData.titleColor = UIColor(0xD1D9EC)
|
||||
frameRateButtonData.size = CGSize(width: 80, height: 30)
|
||||
frameRateButtonData.isEnabled = false
|
||||
frameRateItem.buttonData = frameRateButtonData
|
||||
frameRateItem.action = { [weak self] sender in
|
||||
guard let self = self else { return }
|
||||
self.frameRateAction()
|
||||
}
|
||||
videoItems.append(frameRateItem)
|
||||
}
|
||||
|
||||
private func createAudioItem() {
|
||||
let captureVolumeItem = ListCellItemData()
|
||||
captureVolumeItem.titleText = .captureVolumeText
|
||||
captureVolumeItem.hasSlider = true
|
||||
captureVolumeItem.hasSliderLabel = true
|
||||
captureVolumeItem.minimumValue = 0
|
||||
captureVolumeItem.maximumValue = 100
|
||||
captureVolumeItem.sliderStep = 1
|
||||
captureVolumeItem.sliderDefault = Float(audioSetting.captureVolume)
|
||||
captureVolumeItem.hasDownLineView = true
|
||||
captureVolumeItem.action = { [weak self] sender in
|
||||
guard let self = self, let view = sender as? UISlider else { return }
|
||||
self.captureVolumeAction(sender: view)
|
||||
}
|
||||
audioItems.append(captureVolumeItem)
|
||||
|
||||
let playingVolumeItem = ListCellItemData()
|
||||
playingVolumeItem.titleText = .playVolumeText
|
||||
playingVolumeItem.hasSlider = true
|
||||
playingVolumeItem.hasSliderLabel = true
|
||||
playingVolumeItem.minimumValue = 0
|
||||
playingVolumeItem.maximumValue = 100
|
||||
playingVolumeItem.sliderStep = 1
|
||||
playingVolumeItem.sliderDefault = Float(audioSetting.playVolume)
|
||||
playingVolumeItem.hasDownLineView = true
|
||||
playingVolumeItem.action = { [weak self] sender in
|
||||
guard let self = self, let view = sender as? UISlider else { return }
|
||||
self.playingVolumeAction(sender: view)
|
||||
}
|
||||
audioItems.append(playingVolumeItem)
|
||||
|
||||
let volumePromptItem = ListCellItemData()
|
||||
volumePromptItem.titleText = .volumePromptText
|
||||
volumePromptItem.hasSwitch = true
|
||||
volumePromptItem.isSwitchOn = audioSetting.volumePrompt
|
||||
volumePromptItem.action = { [weak self] sender in
|
||||
guard let self = self, let view = sender as? UISwitch else { return }
|
||||
self.volumePromptAction(sender: view)
|
||||
}
|
||||
audioItems.append(volumePromptItem)
|
||||
}
|
||||
|
||||
private func resolutionAction() {
|
||||
viewResponder?.showResolutionAlert()
|
||||
}
|
||||
|
||||
private func createOtherItem() {
|
||||
let qualityItem = ListCellItemData()
|
||||
qualityItem.titleText = .qualityInspectionText
|
||||
qualityItem.hasOverAllAction = true
|
||||
qualityItem.hasRightButton = true
|
||||
let buttonData = ButtonItemData()
|
||||
buttonData.orientation = .right
|
||||
buttonData.normalIcon = "room_right_arrow1"
|
||||
buttonData.resourceBundle = tuiRoomKitBundle()
|
||||
buttonData.titleFont = UIFont.systemFont(ofSize: 16, weight: .regular)
|
||||
buttonData.titleColor = UIColor(0xD1D9EC)
|
||||
buttonData.size = CGSize(width: 80, height: 30)
|
||||
buttonData.isEnabled = false
|
||||
qualityItem.buttonData = buttonData
|
||||
qualityItem.action = { [weak self] sender in
|
||||
guard let self = self else { return }
|
||||
self.showQualityAction()
|
||||
}
|
||||
otherItems.append(qualityItem)
|
||||
|
||||
let floatChatItem = ListCellItemData()
|
||||
floatChatItem.titleText = .floatChatText
|
||||
floatChatItem.hasSwitch = true
|
||||
floatChatItem.isSwitchOn = store.shouldShowFloatChatView
|
||||
floatChatItem.action = { [weak self] sender in
|
||||
guard let self = self, let view = sender as? UISwitch else { return }
|
||||
self.floatChatShowAction(shouldShow: view.isOn)
|
||||
}
|
||||
otherItems.append(floatChatItem)
|
||||
}
|
||||
|
||||
private func showQualityAction() {
|
||||
viewResponder?.showQualityView()
|
||||
}
|
||||
|
||||
private func floatChatShowAction(shouldShow: Bool) {
|
||||
store.updateFloatChatShowState(shouldShow: shouldShow)
|
||||
}
|
||||
|
||||
private func frameRateAction() {
|
||||
viewResponder?.showFrameRateAlert()
|
||||
}
|
||||
|
||||
private func captureVolumeAction(sender: UISlider) {
|
||||
engineManager.setAudioCaptureVolume(Int(sender.value))
|
||||
}
|
||||
|
||||
private func playingVolumeAction(sender: UISlider) {
|
||||
engineManager.setAudioPlayoutVolume(Int(sender.value))
|
||||
}
|
||||
|
||||
private func volumePromptAction(sender: UISwitch) {
|
||||
engineManager.enableAudioVolumeEvaluation(isVolumePrompt: sender.isOn)
|
||||
}
|
||||
|
||||
func changeResolutionAction(index: Int) {
|
||||
guard let videoItem = videoItems.first(where: { $0.type == .resolutionType }) else { return }
|
||||
guard let quality = resolutionItems[safe: index] else { return }
|
||||
guard let resolutionName = getResolutionName(videoQuality: quality) else { return }
|
||||
videoItem.buttonData?.normalTitle = resolutionName
|
||||
viewResponder?.updateStackView(item: videoItem)
|
||||
engineManager.setVideoEncoder(videoQuality: quality, bitrate: getBitrate(videoQuality: quality))
|
||||
}
|
||||
|
||||
func changeFrameRateAction(index: Int) {
|
||||
guard let videoItem = videoItems.first(where: { $0.type == .frameRateType }) else { return }
|
||||
guard let frameRate = frameRateArray[safe: index] else { return }
|
||||
videoItem.buttonData?.normalTitle = frameRate
|
||||
viewResponder?.updateStackView(item: videoItem)
|
||||
engineManager.setVideoEncoder(fps: Int(frameRate))
|
||||
}
|
||||
|
||||
func getCurrentResolutionIndex() -> Int {
|
||||
guard let index = resolutionItems.firstIndex(where: { $0 == videoSetting.videoQuality }) else { return 0 }
|
||||
return index
|
||||
}
|
||||
|
||||
func getCurrentFrameRateIndex() -> Int {
|
||||
let frameRateString = String(videoSetting.videoFps)
|
||||
guard let index = frameRateArray.firstIndex(where: { $0 == frameRateString }) else { return 0 }
|
||||
return index
|
||||
}
|
||||
|
||||
private func getResolutionName(videoQuality: TUIVideoQuality) -> String? {
|
||||
guard let index = resolutionItems.firstIndex(of: videoQuality) else { return nil }
|
||||
guard let resolutionName = resolutionNameItems[safe: index] else { return nil }
|
||||
return resolutionName
|
||||
}
|
||||
|
||||
private func getBitrate(videoQuality: TUIVideoQuality) -> Int? {
|
||||
guard let index = resolutionItems.firstIndex(of: videoQuality) else { return nil }
|
||||
guard let bitrate = bitrateArray[safe: index] else { return nil }
|
||||
return bitrate
|
||||
}
|
||||
|
||||
deinit {
|
||||
debugPrint("deinit \(self)")
|
||||
}
|
||||
}
|
||||
|
||||
private extension String {
|
||||
static var videoText: String {
|
||||
localized("Video Settings")
|
||||
}
|
||||
static var audioText: String {
|
||||
localized("Audio Settings")
|
||||
}
|
||||
static var otherText: String {
|
||||
localized("Other Settings")
|
||||
}
|
||||
static var versionLowToastText: String {
|
||||
localized("Your system version is below 12.0. Please update.")
|
||||
}
|
||||
static var resolutionText: String {
|
||||
localized("Resolution")
|
||||
}
|
||||
static var frameRateText: String {
|
||||
localized("Frame Rate")
|
||||
}
|
||||
static var bitrateText: String {
|
||||
localized("Bitrate")
|
||||
}
|
||||
static var localMirrorText: String {
|
||||
localized("Local Mirror")
|
||||
}
|
||||
static var captureVolumeText: String {
|
||||
localized("Capture Volume")
|
||||
}
|
||||
static var playVolumeText: String {
|
||||
localized("Playback Volume")
|
||||
}
|
||||
static var volumePromptText: String {
|
||||
localized("Volume Reminder")
|
||||
}
|
||||
static var audioRecordingText: String {
|
||||
localized("Audio Recording")
|
||||
}
|
||||
static var smoothResolutionText: String {
|
||||
localized("Smooth")
|
||||
}
|
||||
static var standardResolutionText: String {
|
||||
localized("Standard Definition")
|
||||
}
|
||||
static var highResolutionText: String {
|
||||
localized("High Definition")
|
||||
}
|
||||
static var superResolutionText: String {
|
||||
localized("Full High Definition")
|
||||
}
|
||||
static var qualityInspectionText: String {
|
||||
localized("Network Quality Monitoring")
|
||||
}
|
||||
static var floatChatText: String {
|
||||
localized("Floating Chat")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user