fix: build

This commit is contained in:
Acaki
2025-07-12 02:00:33 +08:00
parent df2b67ac99
commit d69688678d
36 changed files with 565 additions and 836 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[submodule "moonlight-common/moonlight-common-c"] [submodule "moonlight-common/moonlight-common-c"]
path = moonlight-common/moonlight-common-c path = moonlight-common/moonlight-common-c
url=https://github.com/TrueZhuangJia/voidlink-c.git url=https://github.com/Acaki/voidlink-c
[submodule "X1Kit"] [submodule "X1Kit"]
path = X1Kit path = X1Kit
url = https://github.com/cgutman/X1Kit.git url = https://github.com/cgutman/X1Kit.git
+78
View File
@@ -0,0 +1,78 @@
// dear imgui: Renderer Backend for Metal
// This needs to be used along with a Platform Backend (e.g. OSX)
// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
// ObjC API
//-----------------------------------------------------------------------------
#ifdef __OBJC__
@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
id<MTLCommandBuffer> commandBuffer,
id<MTLRenderCommandEncoder> commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
#endif
//-----------------------------------------------------------------------------
// C++ API
//-----------------------------------------------------------------------------
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
#ifdef IMGUI_IMPL_METAL_CPP
#include <Metal/Metal.hpp>
#ifndef __OBJC__
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
MTL::CommandBuffer* commandBuffer,
MTL::RenderCommandEncoder* commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
#endif
#endif
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE
View File
-40
View File
@@ -1,40 +0,0 @@
//
// TemporarySettings.h
// Moonlight
//
// Created by Cameron Gutman on 12/1/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "Settings+CoreDataClass.h"
@interface TemporarySettings : NSObject
@property (nonatomic, retain) Settings * parent;
@property (nonatomic, retain) NSNumber * bitrate;
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * audioConfig;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@property (nonatomic) enum {
CODEC_PREF_AUTO,
CODEC_PREF_H264,
CODEC_PREF_HEVC,
CODEC_PREF_AV1,
} preferredCodec;
@property (nonatomic) BOOL useFramePacing;
@property (nonatomic) BOOL multiController;
@property (nonatomic) BOOL swapABXYButtons;
@property (nonatomic) BOOL playAudioOnPC;
@property (nonatomic) BOOL optimizeGames;
@property (nonatomic) BOOL enableHdr;
@property (nonatomic) BOOL btMouseSupport;
@property (nonatomic) BOOL absoluteTouchMode;
@property (nonatomic) BOOL statsOverlay;
- (id) initFromSettings:(Settings*)settings;
@end
-37
View File
@@ -1,37 +0,0 @@
//
// StreamView.h
// Moonlight
//
// Created by Cameron Gutman on 10/19/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import "ControllerSupport.h"
#import "OnScreenControls.h"
#import "Moonlight-Swift.h"
#import "StreamConfiguration.h"
@protocol UserInteractionDelegate <NSObject>
- (void) userInteractionBegan;
- (void) userInteractionEnded;
@end
#if TARGET_OS_TV
@interface StreamView : UIView <X1KitMouseDelegate, UITextFieldDelegate>
#else
@interface StreamView : UIView <X1KitMouseDelegate, UITextFieldDelegate, UIPointerInteractionDelegate>
#endif
- (void) setupStreamView:(ControllerSupport*)controllerSupport
interactionDelegate:(id<UserInteractionDelegate>)interactionDelegate
config:(StreamConfiguration*)streamConfig;
- (void) showOnScreenControls;
- (OnScreenControlsLevel) getCurrentOscState;
#if !TARGET_OS_TV
- (void) updateCursorLocation:(CGPoint)location isMouse:(BOOL)isMouse;
#endif
@end
@@ -1128,7 +1128,6 @@ BOOL isCustomResolution(CGSize res) {
NSInteger touchMode = [self.touchModeSelector selectedSegmentIndex]; NSInteger touchMode = [self.touchModeSelector selectedSegmentIndex];
NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex]; NSInteger statsOverlayLevel = [self.statsOverlaySelector selectedSegmentIndex];
BOOL statsOverlayEnabled = statsOverlayLevel != 0; BOOL statsOverlayEnabled = statsOverlayLevel != 0;
BOOL statsOverlay = [self.statsOverlaySelector selectedSegmentIndex] == 1;
BOOL enableGraphs = [self.enableGraphsSelector selectedSegmentIndex] == 1; BOOL enableGraphs = [self.enableGraphsSelector selectedSegmentIndex] == 1;
BOOL enableHdr = [self.hdrSelector selectedSegmentIndex] == 1; BOOL enableHdr = [self.hdrSelector selectedSegmentIndex] == 1;
BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1; BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1;
@@ -1172,7 +1171,6 @@ BOOL isCustomResolution(CGSize res) {
resolutionSelected:resolutionSelected resolutionSelected:resolutionSelected
externalDisplayMode:externalDisplayMode externalDisplayMode:externalDisplayMode
localMousePointerMode:localMousePointerMode]; localMousePointerMode:localMousePointerMode];
statsOverlay:statsOverlay
enableGraphs:enableGraphs enableGraphs:enableGraphs
graphOpacity:_graphOpacity graphOpacity:_graphOpacity
renderingBackend:renderingBackend]; renderingBackend:renderingBackend];
@@ -1,714 +0,0 @@
//
// StreamFrameViewController.m
// Moonlight
//
// Created by Diego Waxemberg on 1/18/14.
// Copyright (c) 2015 Moonlight Stream. All rights reserved.
//
#import "StreamFrameViewController.h"
#import "MainFrameViewController.h"
#import "VideoDecoderRenderer.h"
#import "StreamManager.h"
#import "ControllerSupport.h"
#import "DataManager.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <Limelight.h>
#if TARGET_OS_TV
#import <AVFoundation/AVDisplayCriteria.h>
#import <AVKit/AVDisplayManager.h>
#import <AVKit/UIWindow.h>
#endif
@interface AVDisplayCriteria()
@property(readonly) int videoDynamicRange;
@property(readonly, nonatomic) float refreshRate;
- (id)initWithRefreshRate:(float)arg1 videoDynamicRange:(int)arg2;
@end
@implementation StreamFrameViewController {
ControllerSupport *_controllerSupport;
StreamManager *_streamMan;
TemporarySettings *_settings;
NSTimer *_inactivityTimer;
NSTimer *_statsUpdateTimer;
UITapGestureRecognizer *_menuTapGestureRecognizer;
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
UITapGestureRecognizer *_playPauseTapGestureRecognizer;
UITextView *_overlayView;
UILabel *_stageLabel;
UILabel *_tipLabel;
UIActivityIndicatorView *_spinner;
StreamView *_streamView;
UIScrollView *_scrollView;
BOOL _userIsInteracting;
CGSize _keyboardSize;
#if !TARGET_OS_TV
UIScreenEdgePanGestureRecognizer *_exitSwipeRecognizer;
#endif
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
#if !TARGET_OS_TV
[[self revealViewController] setPrimaryViewController:self];
#endif
}
#if TARGET_OS_TV
- (void)controllerPauseButtonPressed:(id)sender { }
- (void)controllerPauseButtonDoublePressed:(id)sender {
Log(LOG_I, @"Menu double-pressed -- backing out of stream");
[self returnToMainFrame];
}
- (void)controllerPlayPauseButtonPressed:(id)sender {
Log(LOG_I, @"Play/Pause button pressed -- backing out of stream");
[self returnToMainFrame];
}
#endif
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES animated:YES];
[UIApplication sharedApplication].idleTimerDisabled = YES;
_settings = [[[DataManager alloc] init] getSettings];
_stageLabel = [[UILabel alloc] init];
[_stageLabel setUserInteractionEnabled:NO];
[_stageLabel setText:[NSString stringWithFormat:@"Starting %@...", self.streamConfig.appName]];
[_stageLabel sizeToFit];
_stageLabel.textAlignment = NSTextAlignmentCenter;
_stageLabel.textColor = [UIColor whiteColor];
_stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
_spinner = [[UIActivityIndicatorView alloc] init];
[_spinner setUserInteractionEnabled:NO];
#if TARGET_OS_TV
[_spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
#else
[_spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
#endif
[_spinner sizeToFit];
[_spinner startAnimating];
_spinner.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2 - _stageLabel.frame.size.height - _spinner.frame.size.height);
_controllerSupport = [[ControllerSupport alloc] initWithConfig:self.streamConfig delegate:self];
_inactivityTimer = nil;
_streamView = [[StreamView alloc] initWithFrame:self.view.frame];
[_streamView setupStreamView:_controllerSupport interactionDelegate:self config:self.streamConfig];
#if TARGET_OS_TV
if (!_menuTapGestureRecognizer || !_menuDoubleTapGestureRecognizer || !_playPauseTapGestureRecognizer) {
_menuTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPauseButtonPressed:)];
_menuTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
_playPauseTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPlayPauseButtonPressed:)];
_playPauseTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypePlayPause)];
_menuDoubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(controllerPauseButtonDoublePressed:)];
_menuDoubleTapGestureRecognizer.numberOfTapsRequired = 2;
[_menuTapGestureRecognizer requireGestureRecognizerToFail:_menuDoubleTapGestureRecognizer];
_menuDoubleTapGestureRecognizer.allowedPressTypes = @[@(UIPressTypeMenu)];
}
[self.view addGestureRecognizer:_menuTapGestureRecognizer];
[self.view addGestureRecognizer:_menuDoubleTapGestureRecognizer];
[self.view addGestureRecognizer:_playPauseTapGestureRecognizer];
#else
_exitSwipeRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)];
_exitSwipeRecognizer.edges = UIRectEdgeLeft;
_exitSwipeRecognizer.delaysTouchesBegan = NO;
_exitSwipeRecognizer.delaysTouchesEnded = NO;
[self.view addGestureRecognizer:_exitSwipeRecognizer];
#endif
_tipLabel = [[UILabel alloc] init];
[_tipLabel setUserInteractionEnabled:NO];
#if TARGET_OS_TV
[_tipLabel setText:@"Tip: Tap the Play/Pause button on the Apple TV Remote to disconnect from your PC"];
#else
[_tipLabel setText:@"Tip: Swipe from the left edge to disconnect from your PC"];
#endif
[_tipLabel sizeToFit];
_tipLabel.textColor = [UIColor whiteColor];
_tipLabel.textAlignment = NSTextAlignmentCenter;
_tipLabel.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height * 0.9);
_streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig
renderView:_streamView
connectionCallbacks:self];
NSOperationQueue* opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:_streamMan];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(applicationDidBecomeActive:)
name: UIApplicationDidBecomeActiveNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(applicationDidEnterBackground:)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
#if 0
// FIXME: This doesn't work reliably on iPad for some reason. Showing and hiding the keyboard
// several times in a row will not correctly restore the state of the UIScrollView.
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardWillShow:)
name: UIKeyboardWillShowNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(keyboardWillHide:)
name: UIKeyboardWillHideNotification
object: nil];
#endif
// Only enable scroll and zoom in absolute touch mode
if (_settings.absoluteTouchMode) {
_scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
#if !TARGET_OS_TV
[_scrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
#endif
[_scrollView setShowsHorizontalScrollIndicator:NO];
[_scrollView setShowsVerticalScrollIndicator:NO];
[_scrollView setDelegate:self];
[_scrollView setMaximumZoomScale:10.0f];
// Add StreamView inside a UIScrollView for absolute mode
[_scrollView addSubview:_streamView];
[self.view addSubview:_scrollView];
}
else {
// Add StreamView directly in relative mode
[self.view addSubview:_streamView];
}
[self.view addSubview:_stageLabel];
[self.view addSubview:_spinner];
[self.view addSubview:_tipLabel];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _streamView;
}
- (void)willMoveToParentViewController:(UIViewController *)parent {
// Only cleanup when we're being destroyed
if (parent == nil) {
[_controllerSupport cleanup];
[UIApplication sharedApplication].idleTimerDisabled = NO;
[_streamMan stopStream];
if (_inactivityTimer != nil) {
[_inactivityTimer invalidate];
_inactivityTimer = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
}
#if 0
- (void)keyboardWillShow:(NSNotification *)notification {
_keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = self->_scrollView.frame;
frame.size.height -= self->_keyboardSize.height;
self->_scrollView.frame = frame;
}];
}
-(void)keyboardWillHide:(NSNotification *)notification {
// NOTE: UIKeyboardFrameEndUserInfoKey returns a different keyboard size
// than UIKeyboardFrameBeginUserInfoKey, so it's unsuitable for use here
// to undo the changes made by keyboardWillShow.
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = self->_scrollView.frame;
frame.size.height += self->_keyboardSize.height;
self->_scrollView.frame = frame;
}];
}
#endif
- (void)updateStatsOverlay {
NSString* overlayText = [self->_streamMan getStatsOverlayText];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateOverlayText:overlayText];
});
}
- (void)updateOverlayText:(NSString*)text {
if (_overlayView == nil) {
_overlayView = [[UITextView alloc] init];
#if !TARGET_OS_TV
[_overlayView setEditable:NO];
#endif
[_overlayView setUserInteractionEnabled:NO];
[_overlayView setSelectable:NO];
[_overlayView setScrollEnabled:NO];
// HACK: If not using stats overlay, center the text
if (_statsUpdateTimer == nil) {
[_overlayView setTextAlignment:NSTextAlignmentCenter];
}
[_overlayView setTextColor:[UIColor lightGrayColor]];
[_overlayView setBackgroundColor:[UIColor blackColor]];
#if TARGET_OS_TV
[_overlayView setFont:[UIFont systemFontOfSize:24]];
#else
[_overlayView setFont:[UIFont systemFontOfSize:12]];
#endif
[_overlayView setAlpha:0.5];
[self.view addSubview:_overlayView];
}
if (text != nil) {
// We set our bounds to the maximum width in order to work around a bug where
// sizeToFit interacts badly with the UITextView's line breaks, causing the
// width to get smaller and smaller each time as more line breaks are inserted.
[_overlayView setBounds:CGRectMake(self.view.frame.origin.x,
_overlayView.frame.origin.y,
self.view.frame.size.width,
_overlayView.frame.size.height)];
[_overlayView setText:text];
[_overlayView sizeToFit];
[_overlayView setCenter:CGPointMake(self.view.frame.size.width / 2, _overlayView.frame.size.height / 2)];
[_overlayView setHidden:NO];
}
else {
[_overlayView setHidden:YES];
}
}
- (void) returnToMainFrame {
// Reset display mode back to default
[self updatePreferredDisplayMode:NO];
[_statsUpdateTimer invalidate];
_statsUpdateTimer = nil;
[self.navigationController popToRootViewControllerAnimated:YES];
}
// This will fire if the user opens control center or gets a low battery message
- (void)applicationWillResignActive:(NSNotification *)notification {
if (_inactivityTimer != nil) {
[_inactivityTimer invalidate];
}
#if !TARGET_OS_TV
// Terminate the stream if the app is inactive for 60 seconds
Log(LOG_I, @"Starting inactivity termination timer");
_inactivityTimer = [NSTimer scheduledTimerWithTimeInterval:60
target:self
selector:@selector(inactiveTimerExpired:)
userInfo:nil
repeats:NO];
#endif
}
- (void)inactiveTimerExpired:(NSTimer*)timer {
Log(LOG_I, @"Terminating stream after inactivity");
[self returnToMainFrame];
_inactivityTimer = nil;
}
- (void)applicationDidBecomeActive:(NSNotification *)notification {
// Stop the background timer, since we're foregrounded again
if (_inactivityTimer != nil) {
Log(LOG_I, @"Stopping inactivity timer after becoming active again");
[_inactivityTimer invalidate];
_inactivityTimer = nil;
}
}
// This fires when the home button is pressed
- (void)applicationDidEnterBackground:(UIApplication *)application {
Log(LOG_I, @"Terminating stream immediately for backgrounding");
if (_inactivityTimer != nil) {
[_inactivityTimer invalidate];
_inactivityTimer = nil;
}
[self returnToMainFrame];
}
- (void)edgeSwiped {
Log(LOG_I, @"User swiped to end stream");
[self returnToMainFrame];
}
- (void) connectionStarted {
Log(LOG_I, @"Connection started");
dispatch_async(dispatch_get_main_queue(), ^{
// Leave the spinner spinning until it's obscured by
// the first frame of video.
self->_stageLabel.hidden = YES;
self->_tipLabel.hidden = YES;
[self->_streamView showOnScreenControls];
[self->_controllerSupport connectionEstablished];
if (self->_settings.statsOverlay) {
self->_statsUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:@selector(updateStatsOverlay)
userInfo:nil
repeats:YES];
}
});
}
- (void)connectionTerminated:(int)errorCode {
Log(LOG_I, @"Connection terminated: %d", errorCode);
unsigned int portFlags = LiGetPortFlagsFromTerminationErrorCode(errorCode);
unsigned int portTestResults = LiTestClientConnectivity(CONN_TEST_SERVER, 443, portFlags);
dispatch_async(dispatch_get_main_queue(), ^{
// Allow the display to go to sleep now
[UIApplication sharedApplication].idleTimerDisabled = NO;
NSString* title;
NSString* message;
if (portTestResults != ML_TEST_RESULT_INCONCLUSIVE && portTestResults != 0) {
title = @"Connection Error";
message = @"Your device's network connection is blocking Moonlight. Streaming may not work while connected to this network.";
}
else {
switch (errorCode) {
case ML_ERROR_GRACEFUL_TERMINATION:
[self returnToMainFrame];
return;
case ML_ERROR_NO_VIDEO_TRAFFIC:
title = @"Connection Error";
message = @"No video received from host.";
if (portFlags != 0) {
char failingPorts[256];
LiStringifyPortFlags(portFlags, "\n", failingPorts, sizeof(failingPorts));
message = [message stringByAppendingString:[NSString stringWithFormat:@"\n\nCheck your firewall and port forwarding rules for port(s):\n%s", failingPorts]];
}
break;
case ML_ERROR_NO_VIDEO_FRAME:
title = @"Connection Error";
message = @"Your network connection isn't performing well. Reduce your video bitrate setting or try a faster connection.";
break;
case ML_ERROR_UNEXPECTED_EARLY_TERMINATION:
case ML_ERROR_PROTECTED_CONTENT:
title = @"Connection Error";
message = @"Something went wrong on your host PC when starting the stream.\n\nMake sure you don't have any DRM-protected content open on your host PC. You can also try restarting your host PC.\n\nIf the issue persists, try reinstalling your GPU drivers and GeForce Experience.";
break;
case ML_ERROR_FRAME_CONVERSION:
title = @"Connection Error";
message = @"The host PC reported a fatal video encoding error.\n\nTry disabling HDR mode, changing the streaming resolution, or changing your host PC's display resolution.";
break;
default:
{
NSString* errorString;
if (abs(errorCode) > 1000) {
// We'll assume large errors are hex values
errorString = [NSString stringWithFormat:@"%08X", (uint32_t)errorCode];
}
else {
// Smaller values will just be printed as decimal (probably errno.h values)
errorString = [NSString stringWithFormat:@"%d", errorCode];
}
title = @"Connection Terminated";
message = [NSString stringWithFormat: @"The connection was terminated\n\nError code: %@", errorString];
break;
}
}
}
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
[Utils addHelpOptionToDialog:conTermAlert];
[conTermAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
[self returnToMainFrame];
}]];
[self presentViewController:conTermAlert animated:YES completion:nil];
});
[_streamMan stopStream];
}
- (void) stageStarting:(const char*)stageName {
Log(LOG_I, @"Starting %s", stageName);
dispatch_async(dispatch_get_main_queue(), ^{
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
[self->_stageLabel setText:titleCase];
[self->_stageLabel sizeToFit];
self->_stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self->_stageLabel.center.y);
});
}
- (void) stageComplete:(const char*)stageName {
}
- (void) stageFailed:(const char*)stageName withError:(int)errorCode portTestFlags:(int)portTestFlags {
Log(LOG_I, @"Stage %s failed: %d", stageName, errorCode);
unsigned int portTestResults = LiTestClientConnectivity(CONN_TEST_SERVER, 443, portTestFlags);
dispatch_async(dispatch_get_main_queue(), ^{
// Allow the display to go to sleep now
[UIApplication sharedApplication].idleTimerDisabled = NO;
NSString* message = [NSString stringWithFormat:@"%s failed with error %d", stageName, errorCode];
if (portTestFlags != 0) {
char failingPorts[256];
LiStringifyPortFlags(portTestFlags, "\n", failingPorts, sizeof(failingPorts));
message = [message stringByAppendingString:[NSString stringWithFormat:@"\n\nCheck your firewall and port forwarding rules for port(s):\n%s", failingPorts]];
}
if (portTestResults != ML_TEST_RESULT_INCONCLUSIVE && portTestResults != 0) {
message = [message stringByAppendingString:@"\n\nYour device's network connection is blocking Moonlight. Streaming may not work while connected to this network."];
}
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
message:message
preferredStyle:UIAlertControllerStyleAlert];
[Utils addHelpOptionToDialog:alert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
[self returnToMainFrame];
}]];
[self presentViewController:alert animated:YES completion:nil];
});
[_streamMan stopStream];
}
- (void) launchFailed:(NSString*)message {
Log(LOG_I, @"Launch failed: %@", message);
dispatch_async(dispatch_get_main_queue(), ^{
// Allow the display to go to sleep now
[UIApplication sharedApplication].idleTimerDisabled = NO;
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Error"
message:message
preferredStyle:UIAlertControllerStyleAlert];
[Utils addHelpOptionToDialog:alert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
[self returnToMainFrame];
}]];
[self presentViewController:alert animated:YES completion:nil];
});
}
- (void)rumble:(unsigned short)controllerNumber lowFreqMotor:(unsigned short)lowFreqMotor highFreqMotor:(unsigned short)highFreqMotor {
Log(LOG_I, @"Rumble on gamepad %d: %04x %04x", controllerNumber, lowFreqMotor, highFreqMotor);
[_controllerSupport rumble:controllerNumber lowFreqMotor:lowFreqMotor highFreqMotor:highFreqMotor];
}
- (void) rumbleTriggers:(uint16_t)controllerNumber leftTrigger:(uint16_t)leftTrigger rightTrigger:(uint16_t)rightTrigger {
Log(LOG_I, @"Trigger rumble on gamepad %d: %04x %04x", controllerNumber, leftTrigger, rightTrigger);
[_controllerSupport rumbleTriggers:controllerNumber leftTrigger:leftTrigger rightTrigger:rightTrigger];
}
- (void) setMotionEventState:(uint16_t)controllerNumber motionType:(uint8_t)motionType reportRateHz:(uint16_t)reportRateHz {
Log(LOG_I, @"Set motion state on gamepad %d: %02x %u Hz", controllerNumber, motionType, reportRateHz);
[_controllerSupport setMotionEventState:controllerNumber motionType:motionType reportRateHz:reportRateHz];
}
- (void) setControllerLed:(uint16_t)controllerNumber r:(uint8_t)r g:(uint8_t)g b:(uint8_t)b {
Log(LOG_I, @"Set controller LED on gamepad %d: l%02x%02x%02x", controllerNumber, r, g, b);
[_controllerSupport setControllerLed:controllerNumber r:r g:g b:b];
}
- (void)connectionStatusUpdate:(int)status {
Log(LOG_W, @"Connection status update: %d", status);
// The stats overlay takes precedence over these warnings
if (_statsUpdateTimer != nil) {
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
switch (status) {
case CONN_STATUS_OKAY:
[self updateOverlayText:nil];
break;
case CONN_STATUS_POOR:
if (self->_streamConfig.bitRate > 5000) {
[self updateOverlayText:@"Slow connection to PC\nReduce your bitrate"];
}
else {
[self updateOverlayText:@"Poor connection to PC"];
}
break;
}
});
}
- (void) updatePreferredDisplayMode:(BOOL)streamActive {
#if TARGET_OS_TV
if (@available(tvOS 11.2, *)) {
UIWindow* window = [[[UIApplication sharedApplication] delegate] window];
AVDisplayManager* displayManager = [window avDisplayManager];
// This logic comes from Kodi and MrMC
if (streamActive) {
int dynamicRange;
if (LiGetCurrentHostDisplayHdrMode()) {
dynamicRange = 2; // HDR10
}
else {
dynamicRange = 0; // SDR
}
AVDisplayCriteria* displayCriteria = [[AVDisplayCriteria alloc] initWithRefreshRate:[_settings.framerate floatValue]
videoDynamicRange:dynamicRange];
displayManager.preferredDisplayCriteria = displayCriteria;
}
else {
// Switch back to the default display mode
displayManager.preferredDisplayCriteria = nil;
}
}
#endif
}
- (void) setHdrMode:(bool)enabled {
Log(LOG_I, @"HDR is now: %s", enabled ? "active" : "inactive");
dispatch_async(dispatch_get_main_queue(), ^{
[self updatePreferredDisplayMode:YES];
});
}
- (void) videoContentShown {
[_spinner stopAnimating];
[self.view setBackgroundColor:[UIColor blackColor]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)gamepadPresenceChanged {
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
#endif
}
- (void)mousePresenceChanged {
#if !TARGET_OS_TV
if (@available(iOS 14.0, *)) {
[self setNeedsUpdateOfPrefersPointerLocked];
}
#endif
}
- (void) streamExitRequested {
Log(LOG_I, @"Gamepad combo requested stream exit");
[self returnToMainFrame];
}
- (void)userInteractionBegan {
// Disable hiding home bar when user is interacting.
// iOS will force it to be shown anyway, but it will
// also discard our edges deferring system gestures unless
// we willingly give up home bar hiding preference.
_userIsInteracting = YES;
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
#endif
}
- (void)userInteractionEnded {
// Enable home bar hiding again if conditions allow
_userIsInteracting = NO;
#if !TARGET_OS_TV
if (@available(iOS 11.0, *)) {
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}
#endif
}
#if !TARGET_OS_TV
// Require a confirmation when streaming to activate a system gesture
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
return UIRectEdgeAll;
}
- (BOOL)prefersHomeIndicatorAutoHidden {
if ([_controllerSupport getConnectedGamepadCount] > 0 &&
[_streamView getCurrentOscState] == OnScreenControlsLevelOff &&
_userIsInteracting == NO) {
// Autohide the home bar when a gamepad is connected
// and the on-screen controls are disabled. We can't
// do this all the time because any touch on the display
// will cause the home indicator to reappear, and our
// preferredScreenEdgesDeferringSystemGestures will also
// be suppressed (leading to possible errant exits of the
// stream).
return YES;
}
return NO;
}
- (BOOL)shouldAutorotate {
return YES;
}
- (BOOL)prefersPointerLocked {
// Pointer lock breaks the UIKit mouse APIs, which is a problem because
// GCMouse is horribly broken on iOS 14.0 for certain mice. Only lock
// the cursor if there is a GCMouse present.
return [GCMouse mice].count > 0;
}
#endif
@end
+148
View File
@@ -37,6 +37,25 @@
84E1CDFA2C4FE83400547904 /* SwiftLocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDF92C4FE83400547904 /* SwiftLocalizationHelper.swift */; }; 84E1CDFA2C4FE83400547904 /* SwiftLocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDF92C4FE83400547904 /* SwiftLocalizationHelper.swift */; };
84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */; }; 84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */; };
84FD0B542C3134A6006B5BE5 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */; }; 84FD0B542C3134A6006B5BE5 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */; };
97E20DBF2E21637B000D5DCA /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DBE2E21637B000D5DCA /* SceneDelegate.m */; };
97E20DCF2E21647A000D5DCA /* Shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCD2E21647A000D5DCA /* Shaders.metal */; };
97E20DD02E21647A000D5DCA /* MetalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCC2E21647A000D5DCA /* MetalViewController.m */; };
97E20DD12E21647A000D5DCA /* MetalView.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DCA2E21647A000D5DCA /* MetalView.m */; };
97E20DD22E21647A000D5DCA /* MetalVideoRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */; };
97E20DDF2E2164A9000D5DCA /* Frame.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD92E2164A9000D5DCA /* Frame.m */; };
97E20DE02E2164A9000D5DCA /* FrameQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DDB2E2164A9000D5DCA /* FrameQueue.m */; };
97E20DE12E2164A9000D5DCA /* FloatBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD72E2164A9000D5DCA /* FloatBuffer.m */; };
97E20DE22E2164A9000D5DCA /* PaddedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */; };
97E20DE32E2164A9000D5DCA /* BandwidthTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */; };
97E20DE72E216510000D5DCA /* ImGuiRenderer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */; };
97E20DEA2E216532000D5DCA /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DE92E216532000D5DCA /* SceneDelegate.m */; };
97E20DEE2E2165A5000D5DCA /* ImGuiPlots.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */; };
97E21BB52E2186A3000D5DCA /* imgui_impl_metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */; };
97E21BBF2E21882D000D5DCA /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */; };
97E21BC02E21882D000D5DCA /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */; };
97E21BC12E21882D000D5DCA /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */; };
97E21BC22E21882D000D5DCA /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BB92E21882D000D5DCA /* imgui.cpp */; };
97E21BC32E21882D000D5DCA /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */; };
98181BE92791277400E43572 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BE82791275D00E43572 /* libSDL2.a */; }; 98181BE92791277400E43572 /* libSDL2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BE82791275D00E43572 /* libSDL2.a */; };
98181BED2791281100E43572 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BEC2791281100E43572 /* CoreMotion.framework */; }; 98181BED2791281100E43572 /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98181BEC2791281100E43572 /* CoreMotion.framework */; };
9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9819CC13254F107A008A7C8E /* RelativeTouchHandler.m */; }; 9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 9819CC13254F107A008A7C8E /* RelativeTouchHandler.m */; };
@@ -185,6 +204,43 @@
84FD0B4F2C313343006B5BE5 /* LocalizationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalizationHelper.h; sourceTree = "<group>"; }; 84FD0B4F2C313343006B5BE5 /* LocalizationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalizationHelper.h; sourceTree = "<group>"; };
84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalizationHelper.m; sourceTree = "<group>"; }; 84FD0B502C31338D006B5BE5 /* LocalizationHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalizationHelper.m; sourceTree = "<group>"; };
84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; }; 84FD0B532C3134A6006B5BE5 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
97E20DBD2E21637B000D5DCA /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
97E20DBE2E21637B000D5DCA /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
97E20DC62E21647A000D5DCA /* MetalConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalConfig.h; sourceTree = "<group>"; };
97E20DC72E21647A000D5DCA /* MetalVideoRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalVideoRenderer.h; sourceTree = "<group>"; };
97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalVideoRenderer.m; sourceTree = "<group>"; };
97E20DC92E21647A000D5DCA /* MetalView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalView.h; sourceTree = "<group>"; };
97E20DCA2E21647A000D5DCA /* MetalView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalView.m; sourceTree = "<group>"; };
97E20DCB2E21647A000D5DCA /* MetalViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MetalViewController.h; sourceTree = "<group>"; };
97E20DCC2E21647A000D5DCA /* MetalViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MetalViewController.m; sourceTree = "<group>"; };
97E20DCD2E21647A000D5DCA /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; };
97E20DD42E2164A9000D5DCA /* BandwidthTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BandwidthTracker.h; sourceTree = "<group>"; };
97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BandwidthTracker.m; sourceTree = "<group>"; };
97E20DD62E2164A9000D5DCA /* FloatBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FloatBuffer.h; sourceTree = "<group>"; };
97E20DD72E2164A9000D5DCA /* FloatBuffer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FloatBuffer.m; sourceTree = "<group>"; };
97E20DD82E2164A9000D5DCA /* Frame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Frame.h; sourceTree = "<group>"; };
97E20DD92E2164A9000D5DCA /* Frame.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Frame.m; sourceTree = "<group>"; };
97E20DDA2E2164A9000D5DCA /* FrameQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameQueue.h; sourceTree = "<group>"; };
97E20DDB2E2164A9000D5DCA /* FrameQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FrameQueue.m; sourceTree = "<group>"; };
97E20DDC2E2164A9000D5DCA /* PaddedLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PaddedLabel.h; sourceTree = "<group>"; };
97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PaddedLabel.m; sourceTree = "<group>"; };
97E20DDE2E2164A9000D5DCA /* Plot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Plot.h; sourceTree = "<group>"; };
97E20DE52E2164EE000D5DCA /* ImGuiRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImGuiRenderer.h; sourceTree = "<group>"; };
97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImGuiRenderer.mm; sourceTree = "<group>"; };
97E20DE82E216532000D5DCA /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = "<group>"; };
97E20DE92E216532000D5DCA /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = "<group>"; };
97E20DEC2E2165A0000D5DCA /* ImGuiPlots.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImGuiPlots.h; sourceTree = "<group>"; };
97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ImGuiPlots.mm; sourceTree = "<group>"; };
97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = imgui_impl_metal.mm; sourceTree = "<group>"; };
97E21BB72E21882D000D5DCA /* imconfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = third_party/imgui/imconfig.h; sourceTree = SOURCE_ROOT; };
97E21BB82E21882D000D5DCA /* imgui.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = third_party/imgui/imgui.h; sourceTree = SOURCE_ROOT; };
97E21BB92E21882D000D5DCA /* imgui.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = third_party/imgui/imgui.cpp; sourceTree = SOURCE_ROOT; };
97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = third_party/imgui/imgui_demo.cpp; sourceTree = SOURCE_ROOT; };
97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = third_party/imgui/imgui_draw.cpp; sourceTree = SOURCE_ROOT; };
97E21BBC2E21882D000D5DCA /* imgui_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = third_party/imgui/imgui_internal.h; sourceTree = SOURCE_ROOT; };
97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = third_party/imgui/imgui_tables.cpp; sourceTree = SOURCE_ROOT; };
97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = third_party/imgui/imgui_widgets.cpp; sourceTree = SOURCE_ROOT; };
97E21BC42E21883A000D5DCA /* imgui_impl_metal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = imgui_impl_metal.h; sourceTree = "<group>"; };
9803CCAB254F9EAF00EE185E /* ConnectionCallbacks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConnectionCallbacks.h; sourceTree = "<group>"; }; 9803CCAB254F9EAF00EE185E /* ConnectionCallbacks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConnectionCallbacks.h; sourceTree = "<group>"; };
98181BE82791275D00E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/iOS/libSDL2.a; sourceTree = "<group>"; }; 98181BE82791275D00E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/iOS/libSDL2.a; sourceTree = "<group>"; };
98181BEA2791278300E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/tvOS/libSDL2.a; sourceTree = "<group>"; }; 98181BEA2791278300E43572 /* libSDL2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libSDL2.a; path = libs/SDL2/lib/tvOS/libSDL2.a; sourceTree = "<group>"; };
@@ -403,6 +459,47 @@
path = Localization; path = Localization;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
97E20DCE2E21647A000D5DCA /* Metal */ = {
isa = PBXGroup;
children = (
97E20DC62E21647A000D5DCA /* MetalConfig.h */,
97E20DC72E21647A000D5DCA /* MetalVideoRenderer.h */,
97E20DC82E21647A000D5DCA /* MetalVideoRenderer.m */,
97E20DC92E21647A000D5DCA /* MetalView.h */,
97E20DCA2E21647A000D5DCA /* MetalView.m */,
97E20DCB2E21647A000D5DCA /* MetalViewController.h */,
97E20DCC2E21647A000D5DCA /* MetalViewController.m */,
97E20DCD2E21647A000D5DCA /* Shaders.metal */,
);
path = Metal;
sourceTree = "<group>";
};
97E20DEB2E21654B000D5DCA /* Stats */ = {
isa = PBXGroup;
children = (
97E20DED2E2165A5000D5DCA /* ImGuiPlots.mm */,
97E20DEC2E2165A0000D5DCA /* ImGuiPlots.h */,
);
path = Stats;
sourceTree = "<group>";
};
97E21BB42E2186A3000D5DCA /* ImGui */ = {
isa = PBXGroup;
children = (
97E21BC42E21883A000D5DCA /* imgui_impl_metal.h */,
97E21BB72E21882D000D5DCA /* imconfig.h */,
97E21BB82E21882D000D5DCA /* imgui.h */,
97E21BB92E21882D000D5DCA /* imgui.cpp */,
97E21BBA2E21882D000D5DCA /* imgui_demo.cpp */,
97E21BBB2E21882D000D5DCA /* imgui_draw.cpp */,
97E21BBC2E21882D000D5DCA /* imgui_internal.h */,
97E21BBD2E21882D000D5DCA /* imgui_tables.cpp */,
97E21BBE2E21882D000D5DCA /* imgui_widgets.cpp */,
97E21BB32E2186A3000D5DCA /* imgui_impl_metal.mm */,
);
path = ImGui;
sourceTree = "<group>";
};
9896219423D15C2900211983 /* X1Kit */ = { 9896219423D15C2900211983 /* X1Kit */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -435,6 +532,7 @@
FB290CE519B2C406004C83CF = { FB290CE519B2C406004C83CF = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97E21BB42E2186A3000D5DCA /* ImGui */,
9896219423D15C2900211983 /* X1Kit */, 9896219423D15C2900211983 /* X1Kit */,
98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */, 98AB2E7F1CAD46830089BB98 /* moonlight-common.xcodeproj */,
FB290CF919B2C406004C83CF /* VoidLink */, FB290CF919B2C406004C83CF /* VoidLink */,
@@ -482,6 +580,12 @@
FB290CF919B2C406004C83CF /* VoidLink */ = { FB290CF919B2C406004C83CF /* VoidLink */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97E20DEB2E21654B000D5DCA /* Stats */,
97E20DE82E216532000D5DCA /* SceneDelegate.h */,
97E20DE92E216532000D5DCA /* SceneDelegate.m */,
97E20DCE2E21647A000D5DCA /* Metal */,
97E20DBD2E21637B000D5DCA /* SceneDelegate.h */,
97E20DBE2E21637B000D5DCA /* SceneDelegate.m */,
84D8EB932C5146AD00FC10A9 /* VoidLink-Bridging-Header.h */, 84D8EB932C5146AD00FC10A9 /* VoidLink-Bridging-Header.h */,
84FD0B492C312C0B006B5BE5 /* Localization */, 84FD0B492C312C0B006B5BE5 /* Localization */,
8454AC682C31907F00F0A302 /* iPad.storyboard */, 8454AC682C31907F00F0A302 /* iPad.storyboard */,
@@ -516,6 +620,8 @@
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */, FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */,
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */, FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */,
843E93BD2C41528700B1651F /* OrientationHelper.swift */, 843E93BD2C41528700B1651F /* OrientationHelper.swift */,
97E20DE62E216510000D5DCA /* ImGuiRenderer.mm */,
97E20DE52E2164EE000D5DCA /* ImGuiRenderer.h */,
); );
path = VoidLink; path = VoidLink;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -616,6 +722,17 @@
FB89461E19F646E200339C8A /* Utility */ = { FB89461E19F646E200339C8A /* Utility */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97E20DD42E2164A9000D5DCA /* BandwidthTracker.h */,
97E20DD52E2164A9000D5DCA /* BandwidthTracker.m */,
97E20DD62E2164A9000D5DCA /* FloatBuffer.h */,
97E20DD72E2164A9000D5DCA /* FloatBuffer.m */,
97E20DD82E2164A9000D5DCA /* Frame.h */,
97E20DD92E2164A9000D5DCA /* Frame.m */,
97E20DDA2E2164A9000D5DCA /* FrameQueue.h */,
97E20DDB2E2164A9000D5DCA /* FrameQueue.m */,
97E20DDC2E2164A9000D5DCA /* PaddedLabel.h */,
97E20DDD2E2164A9000D5DCA /* PaddedLabel.m */,
97E20DDE2E2164A9000D5DCA /* Plot.h */,
FB89462119F646E200339C8A /* Utils.h */, FB89462119F646E200339C8A /* Utils.h */,
FB89462219F646E200339C8A /* Utils.m */, FB89462219F646E200339C8A /* Utils.m */,
FBD1C8E01A8AD69E00C6703C /* Logger.h */, FBD1C8E01A8AD69E00C6703C /* Logger.h */,
@@ -859,8 +976,14 @@
9819CC22254F180F008A7C8E /* AbsoluteTouchHandler.m in Sources */, 9819CC22254F180F008A7C8E /* AbsoluteTouchHandler.m in Sources */,
9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */, 9819CC14254F107A008A7C8E /* RelativeTouchHandler.m in Sources */,
FB1A674D2131E65900507771 /* KeyboardSupport.m in Sources */, FB1A674D2131E65900507771 /* KeyboardSupport.m in Sources */,
97E20DDF2E2164A9000D5DCA /* Frame.m in Sources */,
97E20DE02E2164A9000D5DCA /* FrameQueue.m in Sources */,
97E20DE12E2164A9000D5DCA /* FloatBuffer.m in Sources */,
97E20DE22E2164A9000D5DCA /* PaddedLabel.m in Sources */,
97E20DE32E2164A9000D5DCA /* BandwidthTracker.m in Sources */,
84591A512BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m in Sources */, 84591A512BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m in Sources */,
843CC7F62C1E7A1700BBC475 /* NativeTouchHandler.m in Sources */, 843CC7F62C1E7A1700BBC475 /* NativeTouchHandler.m in Sources */,
97E20DEE2E2165A5000D5DCA /* ImGuiPlots.mm in Sources */,
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */, FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */, FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */, FB9AFD401A7E127D00872C98 /* AppListResponse.m in Sources */,
@@ -870,6 +993,11 @@
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */, FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
843E93BE2C41528700B1651F /* OrientationHelper.swift in Sources */, 843E93BE2C41528700B1651F /* OrientationHelper.swift in Sources */,
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */, FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
97E21BBF2E21882D000D5DCA /* imgui_tables.cpp in Sources */,
97E21BC02E21882D000D5DCA /* imgui_demo.cpp in Sources */,
97E21BC12E21882D000D5DCA /* imgui_widgets.cpp in Sources */,
97E21BC22E21882D000D5DCA /* imgui.cpp in Sources */,
97E21BC32E21882D000D5DCA /* imgui_draw.cpp in Sources */,
84E1CDEC2C4F67D300547904 /* CommandManager.swift in Sources */, 84E1CDEC2C4F67D300547904 /* CommandManager.swift in Sources */,
847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */, 847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */,
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */, FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
@@ -882,7 +1010,9 @@
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */, FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */, FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */, 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */,
97E21BB52E2186A3000D5DCA /* imgui_impl_metal.mm in Sources */,
84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */, 84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */,
97E20DEA2E216532000D5DCA /* SceneDelegate.m in Sources */,
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */, FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */,
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */, FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */, 843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */,
@@ -905,8 +1035,13 @@
84E1CDEF2C4F688E00547904 /* ToolboxViewController.swift in Sources */, 84E1CDEF2C4F688E00547904 /* ToolboxViewController.swift in Sources */,
844CD0EB2C7F8500004861A7 /* PureNativeTouchHandler.m in Sources */, 844CD0EB2C7F8500004861A7 /* PureNativeTouchHandler.m in Sources */,
84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */, 84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */,
97E20DCF2E21647A000D5DCA /* Shaders.metal in Sources */,
97E20DD02E21647A000D5DCA /* MetalViewController.m in Sources */,
97E20DD12E21647A000D5DCA /* MetalView.m in Sources */,
97E20DD22E21647A000D5DCA /* MetalVideoRenderer.m in Sources */,
84351B2C2C29AD6100A77989 /* OSCProfilesTableViewController.m in Sources */, 84351B2C2C29AD6100A77989 /* OSCProfilesTableViewController.m in Sources */,
98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */, 98D585701C0ED0E800F6CC00 /* TemporarySettings.m in Sources */,
97E20DBF2E21637B000D5DCA /* SceneDelegate.m in Sources */,
FB89462819F646E200339C8A /* CryptoManager.m in Sources */, FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */, DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */,
FB89462E19F646E200339C8A /* PairManager.m in Sources */, FB89462E19F646E200339C8A /* PairManager.m in Sources */,
@@ -921,6 +1056,7 @@
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */, FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */, FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */, FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
97E20DE72E216510000D5DCA /* ImGuiRenderer.mm in Sources */,
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */, FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */, FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
84351B2B2C29AD6100A77989 /* LayoutOnScreenControlsViewController.m in Sources */, 84351B2B2C29AD6100A77989 /* LayoutOnScreenControlsViewController.m in Sources */,
@@ -1112,6 +1248,7 @@
"$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells", "$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells",
"$(PROJECT_DIR)/Limelight/Input", "$(PROJECT_DIR)/Limelight/Input",
"$(PROJECT_DIR)/Limelight/Localization", "$(PROJECT_DIR)/Limelight/Localization",
"$(PROJECT_DIR)/third_party/imgui",
"$(PROJECT_DIR)/Limelight/Database", "$(PROJECT_DIR)/Limelight/Database",
); );
INFOPLIST_FILE = "VoidLink/Limelight-Info.plist"; INFOPLIST_FILE = "VoidLink/Limelight-Info.plist";
@@ -1122,6 +1259,11 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-32",
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-64",
);
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/libs/opus/lib/iOS", "$(PROJECT_DIR)/libs/opus/lib/iOS",
@@ -1171,6 +1313,7 @@
"$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells", "$(PROJECT_DIR)/Limelight/ViewControllers/CustomOSCViewControl/Cells",
"$(PROJECT_DIR)/Limelight/Input", "$(PROJECT_DIR)/Limelight/Input",
"$(PROJECT_DIR)/Limelight/Localization", "$(PROJECT_DIR)/Limelight/Localization",
"$(PROJECT_DIR)/third_party/imgui",
"$(PROJECT_DIR)/Limelight/Database", "$(PROJECT_DIR)/Limelight/Database",
); );
INFOPLIST_FILE = "VoidLink/Limelight-Info.plist"; INFOPLIST_FILE = "VoidLink/Limelight-Info.plist";
@@ -1181,6 +1324,11 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-32",
"$(PROJECT_DIR)/third_party/imgui/examples/libs/glfw/lib-vc2010-64",
);
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ( "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/libs/opus/lib/iOS", "$(PROJECT_DIR)/libs/opus/lib/iOS",
+5 -2
View File
@@ -78,14 +78,17 @@ typedef NS_ENUM(NSInteger, SettingsMenuMode) {
useFramePacing:(BOOL)useFramePacing useFramePacing:(BOOL)useFramePacing
enableHdr:(BOOL)enableHdr enableHdr:(BOOL)enableHdr
btMouseSupport:(BOOL)btMouseSupport btMouseSupport:(BOOL)btMouseSupport
// absoluteTouchMode:(BOOL)absoluteTouchMode
touchMode:(NSInteger)touchMode touchMode:(NSInteger)touchMode
statsOverlayLevel:(NSInteger)statsOverlayLevel statsOverlayLevel:(NSInteger)statsOverlayLevel
statsOverlayEnabled:(BOOL)statsOverlayEnabled statsOverlayEnabled:(BOOL)statsOverlayEnabled
unlockDisplayOrientation:(BOOL)unlockDisplayOrientation unlockDisplayOrientation:(BOOL)unlockDisplayOrientation
resolutionSelected:(NSInteger)resolutionSelected resolutionSelected:(NSInteger)resolutionSelected
externalDisplayMode:(NSInteger)externalDisplayMode externalDisplayMode:(NSInteger)externalDisplayMode
localMousePointerMode:(NSInteger)localMousePointerMode; localMousePointerMode:(NSInteger)localMousePointerMode
frameQueueSize:(NSInteger)frameQueueSize
enableGraphs:(BOOL)enableGraphs
graphOpacity:(NSInteger)graphOpacity
renderingBackend:(NSInteger)renderingBackend;
- (NSArray*) getHosts; - (NSArray*) getHosts;
- (void) updateHost:(TemporaryHost*)host; - (void) updateHost:(TemporaryHost*)host;
+4 -9
View File
@@ -82,20 +82,16 @@
preferredCodec:(uint32_t)preferredCodec preferredCodec:(uint32_t)preferredCodec
enableYUV444:(BOOL)enableYUV444 enableYUV444:(BOOL)enableYUV444
useFramePacing:(BOOL)useFramePacing useFramePacing:(BOOL)useFramePacing
frameQueueSize:(NSInteger)frameQueueSize
enableHdr:(BOOL)enableHdr enableHdr:(BOOL)enableHdr
btMouseSupport:(BOOL)btMouseSupport btMouseSupport:(BOOL)btMouseSupport
// absoluteTouchMode:(BOOL)absoluteTouchMode
touchMode:(NSInteger)touchMode touchMode:(NSInteger)touchMode
statsOverlayLevel:(NSInteger)statsOverlayLevel statsOverlayLevel:(NSInteger)statsOverlayLevel
statsOverlayEnabled:(BOOL)statsOverlayEnabled statsOverlayEnabled:(BOOL)statsOverlayEnabled
unlockDisplayOrientation:(BOOL)unlockDisplayOrientation unlockDisplayOrientation:(BOOL)unlockDisplayOrientation
resolutionSelected:(NSInteger)resolutionSelected resolutionSelected:(NSInteger)resolutionSelected
externalDisplayMode:(NSInteger)externalDisplayMode externalDisplayMode:(NSInteger)externalDisplayMode
localMousePointerMode:(NSInteger)localMousePointerMode{ localMousePointerMode:(NSInteger)localMousePointerMode
frameQueueSize:(NSInteger)frameQueueSize
absoluteTouchMode:(BOOL)absoluteTouchMode
statsOverlay:(BOOL)statsOverlay
enableGraphs:(BOOL)enableGraphs enableGraphs:(BOOL)enableGraphs
graphOpacity:(NSInteger)graphOpacity graphOpacity:(NSInteger)graphOpacity
renderingBackend:(NSInteger)renderingBackend renderingBackend:(NSInteger)renderingBackend
@@ -128,7 +124,6 @@
settingsToSave.playAudioOnPC = audioOnPC; settingsToSave.playAudioOnPC = audioOnPC;
settingsToSave.preferredCodec = preferredCodec; settingsToSave.preferredCodec = preferredCodec;
settingsToSave.enableYUV444 = enableYUV444; settingsToSave.enableYUV444 = enableYUV444;
settingsToSave.frameQueueSize = [NSNumber numberWithInteger:frameQueueSize];
settingsToSave.enableHdr = enableHdr; settingsToSave.enableHdr = enableHdr;
settingsToSave.btMouseSupport = btMouseSupport; settingsToSave.btMouseSupport = btMouseSupport;
// settingsToSave.absoluteTouchMode = absoluteTouchMode; // settingsToSave.absoluteTouchMode = absoluteTouchMode;
@@ -139,8 +134,8 @@
settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected]; settingsToSave.resolutionSelected = [NSNumber numberWithInteger:resolutionSelected];
settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode]; settingsToSave.externalDisplayMode = [NSNumber numberWithInteger:externalDisplayMode];
settingsToSave.localMousePointerMode = [NSNumber numberWithInteger:localMousePointerMode]; settingsToSave.localMousePointerMode = [NSNumber numberWithInteger:localMousePointerMode];
settingsToSave.absoluteTouchMode = absoluteTouchMode;
settingsToSave.statsOverlay = statsOverlay; settingsToSave.frameQueueSize = [NSNumber numberWithInteger:frameQueueSize];
settingsToSave.enableGraphs = enableGraphs; settingsToSave.enableGraphs = enableGraphs;
settingsToSave.graphOpacity = [NSNumber numberWithInteger:graphOpacity]; settingsToSave.graphOpacity = [NSNumber numberWithInteger:graphOpacity];
settingsToSave.renderingBackend = [NSNumber numberWithInteger:renderingBackend]; settingsToSave.renderingBackend = [NSNumber numberWithInteger:renderingBackend];
+4
View File
@@ -62,6 +62,10 @@
@property (nonatomic) BOOL liftStreamViewForKeyboard; @property (nonatomic) BOOL liftStreamViewForKeyboard;
@property (nonatomic) BOOL showKeyboardToolbar; @property (nonatomic) BOOL showKeyboardToolbar;
@property (nonatomic) BOOL unlockDisplayOrientation; @property (nonatomic) BOOL unlockDisplayOrientation;
@property (nonatomic) BOOL enableGraphs;
@property (nonatomic, retain) NSNumber * frameQueueSize;
@property (nonatomic, retain) NSNumber * graphOpacity;
@property (nonatomic, retain) NSNumber * renderingBackend;
- (id) initFromSettings:(Settings*)settings; - (id) initFromSettings:(Settings*)settings;
+45
View File
@@ -0,0 +1,45 @@
//
// ImGuiRenderer 2.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#import <UIKit/UIKit.h>
#import "FloatBuffer.h"
#import "Plot.h"
typedef void (^MetricsHandler)(int plotId, CFTimeInterval value);
@interface ImGuiRenderer : UIViewController
@end
@interface ImGuiRenderer () <MTKViewDelegate>
@property (nonatomic) CGRect bounds;
@property (nonatomic, readonly) MTKView * _Nonnull mtkView;
@property (nonatomic, strong) id <MTLDevice> _Nonnull device;
@property (nonatomic, strong) id <MTLCommandQueue> _Nonnull commandQueue;
@property (nonatomic) struct PlotDef * _Nonnull plots;
@property (nonatomic) FloatBuffer * _Nonnull frametimes;
@property (nonatomic) BOOL enableGraphs;
@property (nonatomic) float graphOpacity;
@property (nonatomic) BOOL imguiRunning;
@property (nonatomic) MetricsHandler _Nonnull metricsHandler;
-(nonnull instancetype) initWithFrame:(CGRect)bounds
streamFps:(int)streamFps
enableGraphs:(BOOL)enableGraphs
graphOpacity:(int)graphOpacity;
-(void) start;
-(void) show;
-(void) hide;
-(void) stop;
-(void) observeFloat:(int)plotId value:(CFTimeInterval)value;
-(void) observeFloatReturnMetrics:(int)plotId value:(CFTimeInterval)value plotMetrics:(PlotMetrics * _Nullable)plotMetrics;
@end
@@ -1,3 +1,12 @@
//
// ImGuiRenderer.m
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVFoundation.h>
#import <Metal/Metal.h> #import <Metal/Metal.h>
#import "ImGuiRenderer.h" #import "ImGuiRenderer.h"
@@ -54,8 +54,9 @@
<attribute name="showKeyboardToolbar" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/> <attribute name="showKeyboardToolbar" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="slideToSettingsDistance" optional="YES" attributeType="Float" defaultValueString="0.25" usesScalarValueType="NO" syncable="YES"/> <attribute name="slideToSettingsDistance" optional="YES" attributeType="Float" defaultValueString="0.25" usesScalarValueType="NO" syncable="YES"/>
<attribute name="slideToSettingsScreenEdge" optional="YES" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="NO" syncable="YES"/> <attribute name="slideToSettingsScreenEdge" optional="YES" attributeType="Integer 32" defaultValueString="2" usesScalarValueType="NO" syncable="YES"/>
<attribute name="statsOverlayEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="statsOverlayLevel" optional="YES" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="renderingBackend" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/> <attribute name="renderingBackend" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
<attribute name="statsOverlay" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="swapABXYButtons" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/> <attribute name="swapABXYButtons" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
<attribute name="touchMode" optional="YES" attributeType="Integer 16" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/> <attribute name="touchMode" optional="YES" attributeType="Integer 16" defaultValueString="1" usesScalarValueType="NO" syncable="YES"/>
<attribute name="touchMoveEventInterval" optional="YES" attributeType="Integer 16" defaultValueString="320" usesScalarValueType="NO" syncable="YES"/> <attribute name="touchMoveEventInterval" optional="YES" attributeType="Integer 16" defaultValueString="320" usesScalarValueType="NO" syncable="YES"/>
@@ -1,3 +1,12 @@
//
// MetalConfig.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
// When enabled, rendering occurs on the main application thread. // When enabled, rendering occurs on the main application thread.
// This can make responding to UI events during redraw simpler // This can make responding to UI events during redraw simpler
// to manage because UI calls usually need to occur on the main thread. // to manage because UI calls usually need to occur on the main thread.
@@ -1,3 +1,12 @@
//
// MetalVideoRenderer.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <QuartzCore/CAMetalLayer.h> #import <QuartzCore/CAMetalLayer.h>
#import <QuartzCore/QuartzCore.h> #import <QuartzCore/QuartzCore.h>
#import "ConnectionCallbacks.h" #import "ConnectionCallbacks.h"
@@ -1,3 +1,12 @@
//
// MetalVideoRenderer.m
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import "MetalVideoRenderer.h" #import "MetalVideoRenderer.h"
#import <CoreVideo/CoreVideo.h> #import <CoreVideo/CoreVideo.h>
#import <Metal/Metal.h> #import <Metal/Metal.h>
@@ -1,3 +1,12 @@
//
// MetalView.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <Metal/Metal.h> #import <Metal/Metal.h>
#import <QuartzCore/CAMetalDisplayLink.h> #import <QuartzCore/CAMetalDisplayLink.h>
#import <QuartzCore/CAMetalLayer.h> #import <QuartzCore/CAMetalLayer.h>
@@ -1,3 +1,12 @@
//
// MetalView.m
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
// This is based on the following Apple example: // This is based on the following Apple example:
// https://developer.apple.com/documentation/metal/achieving-smooth-frame-rates-with-a-metal-display-link?language=objc // https://developer.apple.com/documentation/metal/achieving-smooth-frame-rates-with-a-metal-display-link?language=objc
// https://developer.apple.com/wwdc23/10123/ // https://developer.apple.com/wwdc23/10123/
@@ -1,3 +1,12 @@
//
// MetalViewController.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <Metal/Metal.h> #import <Metal/Metal.h>
#import "FrameQueue.h" #import "FrameQueue.h"
#import "ImGuiRenderer.h" #import "ImGuiRenderer.h"
@@ -1,3 +1,12 @@
//
// MetalViewController.m
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
/* /*
See the LICENSE.txt file for this sample’s licensing information. See the LICENSE.txt file for this sample’s licensing information.
@@ -1,3 +1,12 @@
//
// Vertex.swift
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#include <metal_stdlib> #include <metal_stdlib>
#include <simd/simd.h> #include <simd/simd.h>
+12
View File
@@ -0,0 +1,12 @@
#import <UIKit/UIKit.h>
@interface SceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow * window;
+ (void)setExternalDisplayRenderView:(UIView *)renderView;
+ (void)clearExternalDisplayRenderView;
- (void)updatePreferredDisplayMode:(BOOL)streamActive withRenderView:(UIView *)renderView;
@end
+91
View File
@@ -0,0 +1,91 @@
#import "SceneDelegate.h"
#import "StreamFrameViewController.h"
@implementation SceneDelegate
static UIView *_sharedStreamVideoRenderView = nil;
static UIWindow *_externalSceneWindow = nil;
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
if (![scene isKindOfClass:[UIWindowScene class]]) {
return;
}
UIWindowScene *windowScene = (UIWindowScene *)scene;
if ([session.role isEqualToString:UIWindowSceneSessionRoleApplication]) {
self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
NSString *storyboardName;
if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
storyboardName = @"iPad";
} else {
storyboardName = @"iPhone";
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
UIViewController *initialViewController = [storyboard instantiateInitialViewController];
self.window.rootViewController = initialViewController;
[self.window makeKeyAndVisible];
Log(LOG_I, @"SceneDelegate: Main app scene connected.");
} else if ([session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
Log(LOG_I, @"SceneDelegate: External display scene connecting for screen: %@", ((UIWindowScene *)scene).screen.description);
UIWindowScene *windowScene = (UIWindowScene *)scene;
_externalSceneWindow = [[UIWindow alloc] initWithWindowScene:windowScene];
UIViewController *externalVC = [[UIViewController alloc] init];
externalVC.view.backgroundColor = [UIColor blackColor]; // Set a default background
_externalSceneWindow.rootViewController = externalVC;
if (_sharedStreamVideoRenderView) {
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds;
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
Log(LOG_I, @"SceneDelegate: External display scene connected.");
}
}
}
// Method for StreamFrameViewController to provide its render view
+ (void)setExternalDisplayRenderView:(UIView *)renderView {
_sharedStreamVideoRenderView = renderView;
if (_externalSceneWindow && _externalSceneWindow.rootViewController && _sharedStreamVideoRenderView) {
dispatch_async(dispatch_get_main_queue(), ^{
// Ensure it's removed from any previous parent (should have been done by StreamFrameVC)
[_sharedStreamVideoRenderView removeFromSuperview];
_sharedStreamVideoRenderView.frame = _externalSceneWindow.bounds; // Set frame for external window
[_externalSceneWindow.rootViewController.view addSubview:_sharedStreamVideoRenderView];
_externalSceneWindow.hidden = NO;
Log(LOG_I, @"SceneDelegate: Added render view to external window's root view.");
});
} else {
Log(LOG_E, @"SceneDelegate: External display window or root view controller not available.");
}
}
+ (void)clearExternalDisplayRenderView {
if (_sharedStreamVideoRenderView) {
dispatch_async(dispatch_get_main_queue(), ^{
[_sharedStreamVideoRenderView removeFromSuperview];
Log(LOG_I, @"SceneDelegate: Removed render view from external display.");
});
}
_sharedStreamVideoRenderView = nil;
}
- (void)sceneDidDisconnect:(UIScene *)scene {
Log(LOG_I, @"SceneDelegate: Scene disconnected: %@, role: %@", scene.title, scene.session.role);
if ([scene.session.role isEqualToString:UIWindowSceneSessionRoleExternalDisplay]) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
if (_externalSceneWindow == windowScene.windows.firstObject) { // Compare with the window from the disconnecting scene
[SceneDelegate clearExternalDisplayRenderView]; // Clears the shared view
_externalSceneWindow = nil;
Log(LOG_I, @"SceneDelegate: External display scene fully disconnected and cleaned up.");
} else {
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not the one holding our _externalSceneWindow.");
}
} else {
Log(LOG_W, @"SceneDelegate: Disconnecting scene is not a UIWindowScene.");
}
}
}
@end
@@ -1,3 +1,12 @@
//
// ImGuiPlots.h
// VoidLink
//
// Created by Mason Chen on 2025/7/11.
// Copyright © 2025 Moonlight Game Streaming Project. All rights reserved.
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <VideoToolbox/VideoToolbox.h> #import <VideoToolbox/VideoToolbox.h>
+1 -1
View File
@@ -18,6 +18,6 @@
- (void) stopStream; - (void) stopStream;
- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel; - (NSString*) getStatsOverlayText;
@end @end
+3 -12
View File
@@ -152,11 +152,9 @@
return TRUE; return TRUE;
} }
- (NSString*) getStatsOverlayText: (uint16_t) overlayLevel { - (NSString*) getStatsOverlayText {
video_stats_t stats; video_stats_t stats;
// NSLog(@"overlayLevel: %d", overlayLevel);
if (!_connection) { if (!_connection) {
return nil; return nil;
} }
@@ -168,16 +166,15 @@
uint32_t rtt, variance; uint32_t rtt, variance;
NSString* latencyString; NSString* latencyString;
if (LiGetEstimatedRttInfo(&rtt, &variance)) { if (LiGetEstimatedRttInfo(&rtt, &variance)) {
latencyString = [LocalizationHelper localizedStringForKey:@"%u ms (variance: %u ms)", rtt, variance]; latencyString = [NSString stringWithFormat:@"%u ms (variance: %u ms)", rtt, variance];
} }
else { else {
latencyString = @"N/A"; latencyString = @"N/A";
} }
NSString* hostProcessingString; NSString* hostProcessingString;
// overlayLevel 2: detailed
if (stats.framesWithHostProcessingLatency != 0) { if (stats.framesWithHostProcessingLatency != 0) {
hostProcessingString = [LocalizationHelper localizedStringForKey:@"\nHost processing latency min/max/avg: %.1f/%.1f/%.1f ms", hostProcessingString = [NSString stringWithFormat:@"Host processing latency min/max/avg: %.1f/%.1f/%.1f ms\n",
stats.minHostProcessingLatency / 10.f, stats.minHostProcessingLatency / 10.f,
stats.maxHostProcessingLatency / 10.f, stats.maxHostProcessingLatency / 10.f,
(float)stats.totalHostProcessingLatency / stats.framesWithHostProcessingLatency / 10.f]; (float)stats.totalHostProcessingLatency / stats.framesWithHostProcessingLatency / 10.f];
@@ -188,7 +185,6 @@
} }
float interval = stats.endTime - stats.startTime; float interval = stats.endTime - stats.startTime;
if(overlayLevel == 2) return [LocalizationHelper localizedStringForKey:@"Video stream: %dx%d %.2f FPS (Codec: %@)\nNetwork dropped frames: %.2f%%\nAverage network latency: %@%@",
float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f; float scalePlotMetrics = stats.frameDropMetrics.nsamples > 0 ? ((float)stats.frameDropMetrics.nsamples / stats.totalFrames) : 1.0f;
float fps = (stats.totalFrames - stats.networkDroppedFrames - (stats.frameDropMetrics.total / scalePlotMetrics)) / interval; float fps = (stats.totalFrames - stats.networkDroppedFrames - (stats.frameDropMetrics.total / scalePlotMetrics)) / interval;
@@ -212,11 +208,6 @@
(stats.networkDroppedFrames / stats.totalFrames) * 100.0, (stats.networkDroppedFrames / stats.totalFrames) * 100.0,
stats.frameDropMetrics.nsamples > 0 ? (stats.frameDropMetrics.total / stats.frameDropMetrics.nsamples) * 100.0 : 0.0f, stats.frameDropMetrics.nsamples > 0 ? (stats.frameDropMetrics.total / stats.frameDropMetrics.nsamples) * 100.0 : 0.0f,
latencyString, latencyString,
hostProcessingString];
else return [LocalizationHelper localizedStringForKey:@"FPS: %5.2f Network dropped frames: %.2f%% Network latency: %@",
stats.totalFrames / interval,
stats.networkDroppedFrames / interval,
latencyString];
stats.decodeMetrics.min, stats.decodeMetrics.max, stats.decodeMetrics.avg]; stats.decodeMetrics.min, stats.decodeMetrics.max, stats.decodeMetrics.avg];
} }
@@ -106,6 +106,14 @@
@property (strong, nonatomic) IBOutlet UIStackView *audioConfigStack; @property (strong, nonatomic) IBOutlet UIStackView *audioConfigStack;
@property (strong, nonatomic) IBOutlet UISegmentedControl *audioConfigSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *audioConfigSelector;
@property (strong, nonatomic) IBOutlet UILabel *frameQueueSizeLabel;
@property (strong, nonatomic) IBOutlet UISlider *frameQueueSizeSlider;
@property (strong, nonatomic) IBOutlet UILabel *enableGraphsLabel;
@property (strong, nonatomic) IBOutlet UISwitch *enableGraphsSwitch;
@property (strong, nonatomic) IBOutlet UIStepper *graphOpacityStepper;
@property (strong, nonatomic) IBOutlet UISegmentedControl *renderingBackendSelector;
#pragma clang diagnostic push #pragma clang diagnostic push
@@ -37,6 +37,8 @@
CGFloat _currentRefreshRate; CGFloat _currentRefreshRate;
MenuSectionView *touchControlSection; MenuSectionView *touchControlSection;
NSMutableSet* hiddenStacks; NSMutableSet* hiddenStacks;
NSInteger _frameQueueSize;
NSInteger _graphOpacity;
} }
@dynamic overrideUserInterfaceStyle; @dynamic overrideUserInterfaceStyle;
@@ -147,7 +149,7 @@ static const int bitrateTable[] = {
500000, 500000,
}; };
const int RESOLUTION_TABLE_SIZE = 6; const int RESOLUTION_TABLE_SIZE = 7;
const int RESOLUTION_TABLE_CUSTOM_INDEX = RESOLUTION_TABLE_SIZE - 1; const int RESOLUTION_TABLE_CUSTOM_INDEX = RESOLUTION_TABLE_SIZE - 1;
CGSize resolutionTable[RESOLUTION_TABLE_SIZE]; CGSize resolutionTable[RESOLUTION_TABLE_SIZE];
@@ -1149,6 +1151,8 @@ BOOL isCustomResolution(CGSize res) {
// Ensure we pick a bitrate that falls exactly onto a slider notch // Ensure we pick a bitrate that falls exactly onto a slider notch
_bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]]; _bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]];
_frameQueueSize = [currentSettings.frameQueueSize intValue];
_graphOpacity = [currentSettings.graphOpacity intValue];
// Get the size of the screen with and without safe area insets // Get the size of the screen with and without safe area insets
UIWindow *window = UIApplication.sharedApplication.windows.firstObject; UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
@@ -1162,10 +1166,11 @@ BOOL isCustomResolution(CGSize res) {
resolutionTable[0] = CGSizeMake(1280, 720); resolutionTable[0] = CGSizeMake(1280, 720);
resolutionTable[1] = CGSizeMake(1920, 1080); resolutionTable[1] = CGSizeMake(1920, 1080);
resolutionTable[2] = CGSizeMake(3840, 2160); resolutionTable[2] = CGSizeMake(2560, 1440);
resolutionTable[3] = CGSizeMake(safeAreaWidth, fullScreenHeight); resolutionTable[3] = CGSizeMake(3840, 2160);
resolutionTable[4] = CGSizeMake(fullScreenWidth, fullScreenHeight); resolutionTable[4] = CGSizeMake(safeAreaWidth, fullScreenHeight);
resolutionTable[5] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value resolutionTable[5] = CGSizeMake(fullScreenWidth, fullScreenHeight);
resolutionTable[6] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value
[self updateResolutionTable]; [self updateResolutionTable];
// Don't populate the custom entry unless we have a custom resolution // Don't populate the custom entry unless we have a custom resolution
@@ -1183,9 +1188,12 @@ BOOL isCustomResolution(CGSize res) {
case 60: case 60:
framerate = 1; framerate = 1;
break; break;
case 120: case 90:
framerate = 2; framerate = 2;
break; break;
case 120:
framerate = 3;
break;
} }
NSInteger resolution = currentSettings.resolutionSelected.integerValue; NSInteger resolution = currentSettings.resolutionSelected.integerValue;
@@ -1246,6 +1254,10 @@ BOOL isCustomResolution(CGSize res) {
[self.yuv444Switch setOn:currentSettings.enableYUV444]; [self.yuv444Switch setOn:currentSettings.enableYUV444];
[self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue]; [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue];
NSInteger renderingBackend = [currentSettings.renderingBackend integerValue];
[self.renderingBackendSelector setSelectedSegmentIndex:renderingBackend];
[self.citrixX1MouseSwitch setOn:currentSettings.btMouseSupport]; [self.citrixX1MouseSwitch setOn:currentSettings.btMouseSupport];
[self.optimizeGamesSwitch setOn: currentSettings.optimizeGames]; [self.optimizeGamesSwitch setOn: currentSettings.optimizeGames];
[self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0]; [self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0];
@@ -1274,6 +1286,21 @@ BOOL isCustomResolution(CGSize res) {
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged]; [self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
[self updateBitrateText]; [self updateBitrateText];
[self updateResolutionDisplayLabel]; [self updateResolutionDisplayLabel];
[self.frameQueueSizeSlider setMinimumValue:1];
[self.frameQueueSizeSlider setMaximumValue:5];
[self.frameQueueSizeSlider setValue:_frameQueueSize];
[self.frameQueueSizeSlider addTarget:self action:@selector(frameQueueSizeSliderMoved) forControlEvents:UIControlEventValueChanged];
[self updateFrameQueueSizeText];
[self.enableGraphsSwitch addTarget:self action:@selector(enableGraphsChanged) forControlEvents:UIControlEventValueChanged];
[self enableGraphsChanged];
[self.graphOpacityStepper setMinimumValue:0];
[self.graphOpacityStepper setMaximumValue:100];
[self.graphOpacityStepper setValue:_graphOpacity];
[self.graphOpacityStepper addTarget:self action:@selector(graphOpacityStepperMoved) forControlEvents:UIControlEventValueChanged];
[self updateGraphOpacityText];
if (@available(iOS 18.0, tvOS 18.0, *)) {}else{ if (@available(iOS 18.0, tvOS 18.0, *)) {}else{
[self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; [self.audioConfigSelector removeSegmentAtIndex:1 animated:false];
[self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; // segment 2 goes away when you remove index 2 [self.audioConfigSelector removeSegmentAtIndex:1 animated:false]; // segment 2 goes away when you remove index 2
@@ -1808,6 +1835,8 @@ BOOL isCustomResolution(CGSize res) {
case 1: case 1:
return 60; return 60;
case 2: case 2:
return 90;
case 3:
return 120; return 120;
default: default:
abort(); abort();
@@ -1926,12 +1955,37 @@ BOOL isCustomResolution(CGSize res) {
} }
} }
- (void) frameQueueSizeSliderMoved {
assert(self.frameQueueSizeSlider.value >= 0 && self.frameQueueSizeSlider.value <= 5);
_frameQueueSize = (int)self.frameQueueSizeSlider.value;
[self updateFrameQueueSizeText];
}
- (void) updateFrameQueueSizeText {
[self.frameQueueSizeLabel setText:[NSString stringWithFormat:@"Frames to buffer: %ld", _frameQueueSize ]];
}
- (void) enableGraphsChanged {
[self.graphOpacityStepper setEnabled:[self.enableGraphsSwitch isOn]];
}
- (void) graphOpacityStepperMoved {
assert(self.graphOpacityStepper.value >= 0 && self.graphOpacityStepper.value <= 100);
_graphOpacity = (int)self.graphOpacityStepper.value;
[self updateGraphOpacityText];
}
- (void) updateGraphOpacityText {
[self.enableGraphsLabel setText:[NSString stringWithFormat:@"Performance Graphs - Opacity: %ld%%", _graphOpacity ]];
}
- (void) saveSettings { - (void) saveSettings {
DataManager* dataMan = [[DataManager alloc] init]; DataManager* dataMan = [[DataManager alloc] init];
NSInteger framerate = [self getChosenFrameRate]; NSInteger framerate = [self getChosenFrameRate];
NSInteger height = [self getChosenStreamHeight]; NSInteger height = [self getChosenStreamHeight];
NSInteger width = [self getChosenStreamWidth]; NSInteger width = [self getChosenStreamWidth];
NSInteger audioConfig = [@[@2, @6, @8][[self.audioConfigSelector selectedSegmentIndex]] integerValue]; NSInteger audioConfig = [@[@2, @6, @8][[self.audioConfigSelector selectedSegmentIndex]] integerValue];
NSInteger renderingBackend = [self.renderingBackendSelector selectedSegmentIndex];
NSInteger onscreenControls = [self.onScreenWidgetSelector selectedSegmentIndex]; NSInteger onscreenControls = [self.onScreenWidgetSelector selectedSegmentIndex];
NSInteger keyboardToggleFingers = self.softKeyboardGestureSelector.selectedSegmentIndex == 3 ? 20 : self.softKeyboardGestureSelector.selectedSegmentIndex+3; NSInteger keyboardToggleFingers = self.softKeyboardGestureSelector.selectedSegmentIndex == 3 ? 20 : self.softKeyboardGestureSelector.selectedSegmentIndex+3;
NSInteger oscLayoutToolFingers = (uint16_t)self->oswLayoutFingers; NSInteger oscLayoutToolFingers = (uint16_t)self->oswLayoutFingers;
@@ -1964,6 +2018,7 @@ BOOL isCustomResolution(CGSize res) {
BOOL statsOverlayEnabled = statsOverlayLevel != 0; BOOL statsOverlayEnabled = statsOverlayLevel != 0;
BOOL enableHdr = self.hdrSwitch.isOn; BOOL enableHdr = self.hdrSwitch.isOn;
BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1; BOOL unlockDisplayOrientation = [self.unlockDisplayOrientationSelector selectedSegmentIndex] == 1;
BOOL enableGraphs = self.enableGraphsSwitch.isOn;
NSInteger resolutionSelected = [self.resolutionSelector selectedSegmentIndex]; NSInteger resolutionSelected = [self.resolutionSelector selectedSegmentIndex];
NSInteger externalDisplayMode = [self.externalDisplayModeSelector selectedSegmentIndex]; NSInteger externalDisplayMode = [self.externalDisplayModeSelector selectedSegmentIndex];
NSInteger localMousePointerMode = [self.localMousePointerModeSelector selectedSegmentIndex]; NSInteger localMousePointerMode = [self.localMousePointerModeSelector selectedSegmentIndex];
@@ -2002,7 +2057,11 @@ BOOL isCustomResolution(CGSize res) {
unlockDisplayOrientation:unlockDisplayOrientation unlockDisplayOrientation:unlockDisplayOrientation
resolutionSelected:resolutionSelected resolutionSelected:resolutionSelected
externalDisplayMode:externalDisplayMode externalDisplayMode:externalDisplayMode
localMousePointerMode:localMousePointerMode]; localMousePointerMode:localMousePointerMode
frameQueueSize:_frameQueueSize
enableGraphs:enableGraphs
graphOpacity:_graphOpacity
renderingBackend:renderingBackend];
} }
- (void)didReceiveMemoryWarning { - (void)didReceiveMemoryWarning {
@@ -50,7 +50,6 @@
UITapGestureRecognizer *_menuDoubleTapGestureRecognizer; UITapGestureRecognizer *_menuDoubleTapGestureRecognizer;
UITapGestureRecognizer *_playPauseTapGestureRecognizer; UITapGestureRecognizer *_playPauseTapGestureRecognizer;
UITextView *_overlayView; UITextView *_overlayView;
uint16_t overlayLevel;
UILabel *_stageLabel; UILabel *_stageLabel;
UILabel *_tipLabel; UILabel *_tipLabel;
UIActivityIndicatorView *_spinner; UIActivityIndicatorView *_spinner;
@@ -189,7 +188,6 @@
} }
_settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here. _settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here.
overlayLevel = _settings.statsOverlayLevel.intValue;
[self configOscLayoutTool]; [self configOscLayoutTool];
[self configSwipeGestures]; [self configSwipeGestures];
[self configZoomGestureAndAddStreamView]; [self configZoomGestureAndAddStreamView];
@@ -583,7 +581,7 @@
} }
else [self.view addSubview:_overlayView]; // don't know why but this is necessary for reactivating overlay. else [self.view addSubview:_overlayView]; // don't know why but this is necessary for reactivating overlay.
NSString* overlayText = [self->_streamMan getStatsOverlayText:overlayLevel]; NSString* overlayText = [self->_streamMan getStatsOverlayText];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self updateOverlayText:overlayText]; [self updateOverlayText:overlayText];
}); });
Submodule third_party/implot deleted from 3da8bd3429