Merge branch 'Integration' into stylus3

# Conflicts:
#	VoidLink/ViewControllers/StreamFrameViewController.m
This commit is contained in:
True Zhuanjia committed 2026-02-02 11:56:47 +08:00
commit 6f264441ab
2 files changed
+27 -40

No files matched your search

+9 -7
View File
@@ -9,8 +9,8 @@
import Foundation import Foundation
import QuartzCore import QuartzCore
/// SafeTimer: 高精度、可暂停/重启、可彻底清理 @objc(SafeTimer)
final class SafeTimer { final class SafeTimer: NSObject {
private var timer: DispatchSourceTimer? private var timer: DispatchSourceTimer?
private let timerQueue: DispatchQueue // 私有串行队列 private let timerQueue: DispatchQueue // 私有串行队列
private let userHandler: () -> Void private let userHandler: () -> Void
@@ -20,7 +20,7 @@ final class SafeTimer {
private var shouldRunHandler: Bool = false // 控制逻辑上的暂停/恢复 private var shouldRunHandler: Bool = false // 控制逻辑上的暂停/恢复
private var isCleaned: Bool = false // 是否已经 clean private var isCleaned: Bool = false // 是否已经 clean
init(interval: TimeInterval = 1.0, @objc init(interval: TimeInterval = 1.0,
delay: TimeInterval = 0, delay: TimeInterval = 0,
queueLabel: String = "com.example.safetimer", queueLabel: String = "com.example.safetimer",
handler: @escaping () -> Void) { handler: @escaping () -> Void) {
@@ -29,6 +29,8 @@ final class SafeTimer {
self.delay = delay self.delay = delay
self.userHandler = handler self.userHandler = handler
self.timerQueue = DispatchQueue(label: queueLabel) self.timerQueue = DispatchQueue(label: queueLabel)
super.init()
let t = DispatchSource.makeTimerSource(queue: timerQueue) let t = DispatchSource.makeTimerSource(queue: timerQueue)
t.schedule(deadline: .now() + delay, repeating: interval) t.schedule(deadline: .now() + delay, repeating: interval)
@@ -48,7 +50,7 @@ final class SafeTimer {
} }
/// 开始逻辑上的计时 /// 开始逻辑上的计时
func start() { @objc func start() {
timerQueue.async { [weak self] in timerQueue.async { [weak self] in
guard let self = self, !self.isCleaned else { return } guard let self = self, !self.isCleaned else { return }
self.shouldRunHandler = true self.shouldRunHandler = true
@@ -56,7 +58,7 @@ final class SafeTimer {
} }
/// 暂停逻辑上的计时 /// 暂停逻辑上的计时
func pause() { @objc func pause() {
timerQueue.async { [weak self] in timerQueue.async { [weak self] in
guard let self = self, !self.isCleaned else { return } guard let self = self, !self.isCleaned else { return }
self.shouldRunHandler = false self.shouldRunHandler = false
@@ -64,7 +66,7 @@ final class SafeTimer {
} }
/// 重置下一次触发时间,并开始执行 handler /// 重置下一次触发时间,并开始执行 handler
func restart() { @objc func restart() {
timerQueue.async { [weak self] in timerQueue.async { [weak self] in
guard let self = self, let t = self.timer, !self.isCleaned else { return } guard let self = self, let t = self.timer, !self.isCleaned else { return }
t.schedule(deadline: .now() + self.delay, repeating: self.interval) t.schedule(deadline: .now() + self.delay, repeating: self.interval)
@@ -73,7 +75,7 @@ final class SafeTimer {
} }
/// 彻底清理 timer,返回后保证 handler 不再执行 /// 彻底清理 timer,返回后保证 handler 不再执行
func clean() { @objc func clean() {
if isCleaned { return } if isCleaned { return }
// 同步在 timerQueue 执行,保证已排队事件全部处理完(或跳过) // 同步在 timerQueue 执行,保证已排队事件全部处理完(或跳过)
timerQueue.sync { timerQueue.sync {
@@ -80,7 +80,7 @@
dispatch_block_t _delayedRemoveExtScreen; dispatch_block_t _delayedRemoveExtScreen;
VideoDecoderRenderer *_videoRenderer; VideoDecoderRenderer *_videoRenderer;
BOOL _isRestoringFromPiP; BOOL _isRestoringFromPiP;
CADisplayLink *_displayLink; SafeTimer* safeTimer;
#if !TARGET_OS_TV #if !TARGET_OS_TV
CustomEdgeSlideGestureRecognizer *_slideToSettingsRecognizer; CustomEdgeSlideGestureRecognizer *_slideToSettingsRecognizer;
@@ -439,11 +439,12 @@
[self.view bringSubviewToFront:self.imguiView.mtkView]; [self.view bringSubviewToFront:self.imguiView.mtkView];
} }
[self stopDisplayLink]; // [self pauseTimer];
if(_settings.sendDummyEvent){ if(_settings.sendDummyEvent){
[self setupDisplayLink]; if(!safeTimer) [self setupTimer];
[self startDisplayLink]; if(!viewJustLoaded) [safeTimer start];
} }
else [safeTimer pause];
_motionHandler = [MotionHandler sharedWithProfile: nil]; _motionHandler = [MotionHandler sharedWithProfile: nil];
_motionHandler.gyroBiasX = _settings.gyroBiasX.doubleValue; _motionHandler.gyroBiasX = _settings.gyroBiasX.doubleValue;
@@ -461,12 +462,11 @@
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
if(_settings.sendDummyEvent) [self startDisplayLink]; // if(_settings.sendDummyEvent) [self startTimer];
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[self stopDisplayLink];
} }
- (void)viewDidAppear:(BOOL)animated - (void)viewDidAppear:(BOOL)animated
@@ -541,7 +541,8 @@
selector:@selector(keyboardWillHide) selector:@selector(keyboardWillHide)
name:UIKeyboardWillHideNotification name:UIKeyboardWillHideNotification
object:nil]; object:nil];
[safeTimer start];
#endif #endif
} }
@@ -841,6 +842,9 @@
for(UIView* view in self.view.subviews){ for(UIView* view in self.view.subviews){
[view removeFromSuperview]; [view removeFromSuperview];
} }
[safeTimer pause];
[safeTimer clean];
} }
} }
@@ -1698,36 +1702,17 @@
} }
- (void)dealloc { - (void)dealloc {
[self stopDisplayLink];
NSLog(@"dealloc StreamFrameViewController %f", CACurrentMediaTime()); NSLog(@"dealloc StreamFrameViewController %f", CACurrentMediaTime());
} }
- (void)setupDisplayLink { - (void)setupTimer {
if (_displayLink != nil) return;
TemporarySettings* tempSettings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here. TemporarySettings* tempSettings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here.
if (@available(iOS 15.0, tvOS 15.0, *)) { safeTimer = [[SafeTimer alloc] initWithInterval:1.0/tempSettings.framerate.intValue delay:0 queueLabel:@"streamview.timer" handler:^{
[_displayLink setPreferredFrameRateRange:CAFrameRateRangeMake(tempSettings.framerate.intValue,tempSettings.framerate.intValue, tempSettings.framerate.intValue)]; dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
} LiSendKeyboardEvent(0xFF, KEY_ACTION_UP, 0);
else { // LiSendTouchEvent(LI_TOUCH_EVENT_UP, 200, 1, 1, 0, 0, 0, 0);
_displayLink.preferredFramesPerSecond = tempSettings.framerate.intValue; });
} }];
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)startDisplayLink {
_displayLink.paused = NO;
}
- (void)stopDisplayLink {
[_displayLink invalidate];
_displayLink = nil;
}
- (void)displayLinkTick:(CADisplayLink *)link {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
LiSendKeyboardEvent(0xFF, KEY_ACTION_UP, 0);
});
} }
@end @end