Feature: Add power management to keep macOS client always responsive
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#import <CoreGraphics/CoreGraphics.h>
|
#import <CoreGraphics/CoreGraphics.h>
|
||||||
#import <dispatch/dispatch.h>
|
#import <dispatch/dispatch.h>
|
||||||
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
#import "../client/IOCPClient.h"
|
#import "../client/IOCPClient.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@@ -132,4 +133,7 @@ private:
|
|||||||
|
|
||||||
// Input handler for mouse/keyboard control
|
// Input handler for mouse/keyboard control
|
||||||
std::unique_ptr<InputHandler> m_inputHandler;
|
std::unique_ptr<InputHandler> m_inputHandler;
|
||||||
|
|
||||||
|
// Power management: prevent display sleep during remote desktop
|
||||||
|
IOPMAssertionID m_displayAssertionID;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ ScreenHandler::ScreenHandler(IOCPClient* client)
|
|||||||
, m_maxFPS(15)
|
, m_maxFPS(15)
|
||||||
, m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility
|
, m_qualityLevel(QUALITY_GOOD) // Use fixed QUALITY_GOOD (H264) for web compatibility
|
||||||
, m_h264Bitrate(3000000) // 3 Mbps (matches Windows QUALITY_GOOD)
|
, m_h264Bitrate(3000000) // 3 Mbps (matches Windows QUALITY_GOOD)
|
||||||
|
, m_displayAssertionID(0)
|
||||||
{
|
{
|
||||||
memset(&m_bmpHeader, 0, sizeof(m_bmpHeader));
|
memset(&m_bmpHeader, 0, sizeof(m_bmpHeader));
|
||||||
|
|
||||||
@@ -115,6 +116,21 @@ void ScreenHandler::start(IOCPClient* client, uint64_t clientID)
|
|||||||
m_clientID = clientID;
|
m_clientID = clientID;
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
|
||||||
|
// Prevent display sleep during remote desktop session
|
||||||
|
if (m_displayAssertionID == 0) {
|
||||||
|
IOReturn result = IOPMAssertionCreateWithName(
|
||||||
|
kIOPMAssertionTypeNoDisplaySleep,
|
||||||
|
kIOPMAssertionLevelOn,
|
||||||
|
CFSTR("SimpleRemoter - remote desktop session active"),
|
||||||
|
&m_displayAssertionID
|
||||||
|
);
|
||||||
|
if (result == kIOReturnSuccess) {
|
||||||
|
NSLog(@"Display sleep disabled for remote desktop (ID: %u)", m_displayAssertionID);
|
||||||
|
} else {
|
||||||
|
NSLog(@"Warning: Failed to prevent display sleep (error: 0x%x)", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_captureThread = std::thread(&ScreenHandler::captureLoop, this);
|
m_captureThread = std::thread(&ScreenHandler::captureLoop, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +146,13 @@ void ScreenHandler::stop()
|
|||||||
m_h264Encoder->close();
|
m_h264Encoder->close();
|
||||||
m_h264Encoder.reset();
|
m_h264Encoder.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release display sleep assertion - allow screen to turn off
|
||||||
|
if (m_displayAssertionID != 0) {
|
||||||
|
IOPMAssertionRelease(m_displayAssertionID);
|
||||||
|
NSLog(@"Display sleep re-enabled (released ID: %u)", m_displayAssertionID);
|
||||||
|
m_displayAssertionID = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::sendBitmapInfo()
|
void ScreenHandler::sendBitmapInfo()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#import <signal.h>
|
#import <signal.h>
|
||||||
#import <unistd.h>
|
#import <unistd.h>
|
||||||
#import <IOKit/IOKitLib.h>
|
#import <IOKit/IOKitLib.h>
|
||||||
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
#import <fstream>
|
#import <fstream>
|
||||||
#import <thread>
|
#import <thread>
|
||||||
#import <atomic>
|
#import <atomic>
|
||||||
@@ -478,6 +479,30 @@ int main(int argc, const char* argv[])
|
|||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSLog(@"=== macOS Ghost Client ===");
|
NSLog(@"=== macOS Ghost Client ===");
|
||||||
|
|
||||||
|
// ============== Power Management: Keep System Awake ==============
|
||||||
|
// 1. Disable App Nap - prevent macOS from suspending this process
|
||||||
|
id<NSObject> powerActivity = [[NSProcessInfo processInfo]
|
||||||
|
beginActivityWithOptions:(NSActivityUserInitiated | NSActivityIdleSystemSleepDisabled)
|
||||||
|
reason:@"Remote control client must maintain persistent connection"];
|
||||||
|
NSLog(@"App Nap disabled, activity token acquired");
|
||||||
|
|
||||||
|
// 2. Prevent system idle sleep using IOKit power assertion
|
||||||
|
IOPMAssertionID sleepAssertionID = 0;
|
||||||
|
IOReturn result = IOPMAssertionCreateWithName(
|
||||||
|
kIOPMAssertionTypeNoIdleSleep,
|
||||||
|
kIOPMAssertionLevelOn,
|
||||||
|
CFSTR("SimpleRemoter macOS client - maintaining remote connection"),
|
||||||
|
&sleepAssertionID
|
||||||
|
);
|
||||||
|
if (result == kIOReturnSuccess) {
|
||||||
|
NSLog(@"Power assertion created: system idle sleep disabled (ID: %u)", sleepAssertionID);
|
||||||
|
} else {
|
||||||
|
NSLog(@"Warning: Failed to create power assertion (error: 0x%x)", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Display sleep: managed by ScreenHandler - only prevents display sleep
|
||||||
|
// when remote desktop is actively connected (saves power when idle)
|
||||||
|
|
||||||
// Setup signal handlers
|
// Setup signal handlers
|
||||||
setupSignals();
|
setupSignals();
|
||||||
|
|
||||||
@@ -549,6 +574,15 @@ int main(int argc, const char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"Shutting down...");
|
NSLog(@"Shutting down...");
|
||||||
|
|
||||||
|
// Release power assertions
|
||||||
|
if (sleepAssertionID) {
|
||||||
|
IOPMAssertionRelease(sleepAssertionID);
|
||||||
|
NSLog(@"Released sleep assertion");
|
||||||
|
}
|
||||||
|
// Display assertion is managed by ScreenHandler (released in stop())
|
||||||
|
// powerActivity is automatically released when exiting @autoreleasepool
|
||||||
|
(void)powerActivity; // Suppress unused variable warning
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user