From a31ad07ba550d5ecc53d391447100c0805b0aae1 Mon Sep 17 00:00:00 2001 From: Matt Russell <_matt@live.com.au> Date: Thu, 21 May 2020 00:13:31 +0800 Subject: [PATCH] added external screen support --- Limelight/Stream/VideoDecoderRenderer.m | 15 ++-- .../StreamFrameViewController.m | 90 +++++++++++++++++-- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index 8dcddabf..d140b298 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -22,8 +22,7 @@ @implementation VideoDecoderRenderer { CMVideoFormatDescriptionRef formatDesc; CADisplayLink* _displayLink; -} - +} - (void)reinitializeDisplayLayer { CALayer *oldLayer = displayLayer; @@ -31,7 +30,6 @@ - (void)reinitializeDisplayLayer displayLayer = [[AVSampleBufferDisplayLayer alloc] init]; displayLayer.bounds = _view.bounds; displayLayer.backgroundColor = [OSColor blackColor].CGColor; - displayLayer.position = CGPointMake(CGRectGetMidX(_view.bounds), CGRectGetMidY(_view.bounds)); displayLayer.videoGravity = AVLayerVideoGravityResizeAspect; @@ -68,7 +66,14 @@ - (id)initWithView:(StreamView*)view _view = view; [self reinitializeDisplayLayer]; - + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(reinitializeDisplayLayer) + name:@"ScreenConnected" + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(reinitializeDisplayLayer) + name:@"ScreenDisconnected" + object:nil]; return self; } @@ -381,4 +386,4 @@ - (int)submitDecodeBuffer:(unsigned char *)data length:(int)length bufferType:(i return DR_OK; } -@end +@end \ No newline at end of file diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index a85d8ab1..ec65eca6 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -26,12 +26,41 @@ @implementation StreamFrameViewController { UITextView *_overlayView; StreamView *_streamView; BOOL _userIsInteracting; + UIWindow *_extWindow; + UIView *_renderView; + UIWindow *_deviceWindow; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; + _deviceWindow = self.view.window; + + if (UIScreen.screens.count > 1) { + [self prepExtScreen:UIScreen.screens.lastObject]; + } + else { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.view insertSubview:self->_renderView atIndex:0]; + }); + } + + // check to see if external screen is connected/disconnected + + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(extScreenDidConnect:) + name: UIScreenDidConnectNotification + object: nil]; + + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(extScreenDidDisconnect:) + name: UIScreenDidDisconnectNotification + object: nil]; + + + + #if !TARGET_OS_TV [[self revealViewController] setPrimaryViewController:self]; #endif @@ -61,8 +90,9 @@ - (void)viewDidLoad _controllerSupport = [[ControllerSupport alloc] initWithConfig:self.streamConfig presenceDelegate:self]; _inactivityTimer = nil; - + _renderView = (StreamView*)[[UIView alloc] initWithFrame:self.view.frame]; _streamView = (StreamView*)self.view; + _renderView.bounds = _streamView.bounds; [_streamView setupStreamView:_controllerSupport swipeDelegate:self interactionDelegate:self config:self.streamConfig]; #if TARGET_OS_TV @@ -91,11 +121,10 @@ - (void)viewDidLoad self.tipLabel.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height * 0.9); _streamMan = [[StreamManager alloc] initWithConfig:self.streamConfig - renderView:self.view - connectionCallbacks:self]; + renderView:_renderView + connectionCallbacks:self]; NSOperationQueue* opQueue = [[NSOperationQueue alloc] init]; [opQueue addOperation:_streamMan]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification @@ -160,6 +189,51 @@ - (void)updateOverlayText:(NSString*)text { - (void) returnToMainFrame { [self.navigationController popToRootViewControllerAnimated:YES]; + _extWindow = nil; +} + +// External Screen connected +- (void)extScreenDidConnect:(NSNotification *)notification { + Log(LOG_I, @"External Screen Connected"); + dispatch_async(dispatch_get_main_queue(), ^{ + [self prepExtScreen:notification.object]; + }); +} + +// External Screen disconnected +- (void)extScreenDidDisconnect:(NSNotification *)notification { + Log(LOG_I, @"External Screen Disconnected"); + if(UIScreen.screens.count < 2) + { + dispatch_async(dispatch_get_main_queue(), ^{ + [self removeExtScreen]; + }); + } +} + +// Prepare Screen +- (void)prepExtScreen:(UIScreen*)extScreen { + Log(LOG_I, @"Preparing External Screen"); + CGRect frame = extScreen.bounds; + extScreen.overscanCompensation = 3; + _extWindow = [[UIWindow alloc] initWithFrame:frame]; + _extWindow.screen = extScreen; + _renderView.bounds = frame; + _renderView.frame = frame; + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:@"ScreenConnected" object:self]; + [_extWindow addSubview:_renderView]; + _extWindow.hidden = NO; +} + +- (void)removeExtScreen { + Log(LOG_I, @"Removing External Screen"); + _extWindow.hidden = YES; + _renderView.bounds = _deviceWindow.bounds; + _renderView.frame = _deviceWindow.frame; + NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; + [nc postNotificationName:@"ScreenDisconnected" object:self]; + [self.view insertSubview:_renderView atIndex:0]; } // This will fire if the user opens control center or gets a low battery message @@ -221,12 +295,12 @@ - (void)edgeSwiped { - (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.spinner.hidden = YES; + }); } @@ -270,8 +344,8 @@ - (void)connectionTerminated:(int)errorCode { } - (void) stageStarting:(const char*)stageName { - Log(LOG_I, @"Starting %s", stageName); dispatch_async(dispatch_get_main_queue(), ^{ + Log(LOG_I, @"Starting %s", stageName); NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName]; NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]]; [self.stageLabel setText:titleCase]; @@ -414,4 +488,4 @@ - (BOOL)shouldAutorotate { } #endif -@end +@end \ No newline at end of file