Runt
2025-06-27 e21b1c797955a231f2bcf71818e0259fbb6aeba1
LiveProject/activity/stream/LiveActivity.swift
@@ -5,9 +5,10 @@
//  Created by 倪路朋 on 6/25/25.
//
import Foundation
import UIKit
import AVFoundation
import SwiftUI
import WrappingHStack
import MetalKit
struct LiveActivity: View {
    @State private var pixelBuffer: CVPixelBuffer?
@@ -16,18 +17,24 @@
    @State private var showDeviceDialog = false
    
    @State private var streamRate = Float(9/16.0);
    @State private var fpsState = 30;
    @State private var mainSize: CGSize = .init(width: 100, height: 100)
    
    @State private var devices = [DeviceInfo(name: "相机", type: .CAMERA(), deviceId: "相机"),
                                  DeviceInfo(name: "话筒", type: .MICROPHONE(),deviceId: "话筒"),
                                  DeviceInfo(name: "系统", type: .SYSTEM(),deviceId : "系统")]
    @State private var displaySize : CGSize = .zero;
    @State private var devices = [DeviceInfo(name: "相机", type: .CAMERA, deviceId: UUID().uuidString,icon: IconCamera()),
                                  DeviceInfo(name: "话筒", type: .MICROPHONE,deviceId: UUID().uuidString,icon: IconMic()),
                                  DeviceInfo(name: "系统", type: .SYSTEM,deviceId : UUID().uuidString,icon: IconPortrait())]
    private let mViewModel = LiveViewModel()
    
    var body: some View {
        ZStack{
            Color.clear
                .ignoresSafeArea() // 填满全屏
            VStack{
                VideoRendererView(renderer: MetalRenderer()).background(Color.black).frame(width: mainSize.width,height:mainSize.height)
                VideoRendererView(renderer:mViewModel.renderer).background(Color.black).frame(width: mainSize.width,height:mainSize.height)
                Spacer()
            }.border(Color.blue)
            VStack{
@@ -42,10 +49,14 @@
                GeometryReader { geometry in
                    Color.clear
                        .onAppear {
                            updateWindowSize(width: Int(geometry.size.width), height: Int(geometry.size.height))
                            displaySize = geometry.size;
                            updateWindowSize()
                            print("displaySize:\(displaySize)")
                        }
                        .onChange(of: geometry.size) { newSize in
                            updateWindowSize(width: Int(newSize.width), height: Int(newSize.height))
                            displaySize = newSize;
                            updateWindowSize()
                            print("displaySize:\(displaySize)")
                        }
                })
            .border(Color.red)
@@ -57,35 +68,35 @@
            }
    }
    
    func updateWindowSize(width:Int,height:Int){
        var rate : Float = Float(width)/Float(height);
    func updateWindowSize(){
        var rate : Float = Float(displaySize.width)/Float(displaySize.height);
        if(rate != streamRate) {
            var mainWidth = 0;
            var mainHeight = 0;
            var mainWidth = 0.0;
            var mainHeight = 0.0;
            if(rate < streamRate){
                mainWidth = width;
                mainWidth = displaySize.width;
                if(9.0/16 == streamRate){
                    mainHeight = (mainWidth / 9 * 16);
                    mainHeight = (mainWidth / 9.0 * 16);
                }else{
                    mainHeight = (mainWidth / 16 * 9);
                    mainHeight = (mainWidth / 16.0 * 9);
                }
            }else{
                mainHeight = height;
                mainHeight = displaySize.height;
                if(9.0 / 16 == streamRate){
                    mainWidth = (mainHeight / 16 * 9);
                    mainWidth = (mainHeight / 16.0 * 9);
                }else{
                    mainWidth = (mainHeight / 9 * 16);
                    mainWidth = (mainHeight / 9.0 * 16);
                }
            }
            if(mainSize.width != CGFloat(mainWidth) || mainSize.height != CGFloat(mainHeight)){
                mainSize = .init(width: mainWidth, height: mainHeight);
            }
        }else{
            if(mainSize.width != CGFloat(width) || mainSize.height != CGFloat(height)){
                mainSize = .init(width: width, height: height);
            if(mainSize.width != displaySize.width || mainSize.height != displaySize.height){
                mainSize = .init(width: displaySize.width, height: displaySize.height);
            }
        }
        //Log.w(TAG , "onSizeChanged: ${mainWindowSize.value}" , )
        print("updateWindow:\(mainSize)")
    }
    
    func DialogDevices() -> some View{
@@ -102,12 +113,16 @@
                VStack(spacing: 20) {
                    Spacer().frame(height:40)
                    FlowLayout(devices){ device in
                        MButton(text:device.name){
                        MButton(icon: device.icon,text: device.name){
                            mViewModel.newWindowAction(device: device){ status in
                                withAnimation{
                                    showDeviceDialog = false;
                                }
                            }
                            print("\(device.name) click")
                        }
                    }
                    .padding()
                    .animation(.default, value: devices)
                }
                .frame(maxWidth: .infinity)
                .padding()
@@ -116,6 +131,7 @@
                .transition(.move(edge: .bottom))
            }
            .zIndex(1)
            .animation(.default, value: devices)
        }
    }
    
@@ -123,12 +139,16 @@
        VStack{
        
            HStack(){
                MButton(icon: IconPortrait()){
                //横竖屏控制
                MButton(icon:streamRate == (9/16.0) ? IconPortrait() : IconLandscape() ){
                    streamRate = streamRate == (9/16.0) ? (16/9.0) : (9/16.0)
                    updateWindowSize()
                }
                MButton(text: "30帧"){
                // fps 控制
                MButton(text: "\(fpsState)帧"){
                    fpsState = fpsState == 30 ? 60 : 30;
                }
                //添加推流地址
                MButton(valid: .INVALID,text: "+"){
                    
                }