mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-29 16:11:01 +03:00
ios
This commit is contained in:
33
flutter/ios/BroadcastExtension/Info.plist
Normal file
33
flutter/ios/BroadcastExtension/Info.plist
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>RustDesk Screen Broadcast</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.broadcast-services-upload</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>SampleHandler</string>
|
||||
<key>RPBroadcastProcessMode</key>
|
||||
<string>RPBroadcastProcessModeSampleBuffer</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
5
flutter/ios/BroadcastExtension/SampleHandler.h
Normal file
5
flutter/ios/BroadcastExtension/SampleHandler.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#import <ReplayKit/ReplayKit.h>
|
||||
|
||||
@interface SampleHandler : RPBroadcastSampleHandler
|
||||
|
||||
@end
|
||||
122
flutter/ios/BroadcastExtension/SampleHandler.m
Normal file
122
flutter/ios/BroadcastExtension/SampleHandler.m
Normal file
@@ -0,0 +1,122 @@
|
||||
#import "SampleHandler.h"
|
||||
#import <os/log.h>
|
||||
|
||||
@interface SampleHandler ()
|
||||
@property (nonatomic, strong) dispatch_queue_t videoQueue;
|
||||
@property (nonatomic, assign) CFMessagePortRef messagePort;
|
||||
@property (nonatomic, assign) BOOL isConnected;
|
||||
@end
|
||||
|
||||
@implementation SampleHandler
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_videoQueue = dispatch_queue_create("com.rustdesk.broadcast.video", DISPATCH_QUEUE_SERIAL);
|
||||
_isConnected = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
|
||||
// Create message port to communicate with main app
|
||||
NSString *portName = @"com.rustdesk.screencast.port";
|
||||
|
||||
self.messagePort = CFMessagePortCreateRemote(kCFAllocatorDefault, (__bridge CFStringRef)portName);
|
||||
|
||||
if (self.messagePort) {
|
||||
self.isConnected = YES;
|
||||
os_log_info(OS_LOG_DEFAULT, "Connected to main app via message port");
|
||||
} else {
|
||||
os_log_error(OS_LOG_DEFAULT, "Failed to connect to main app");
|
||||
[self finishBroadcastWithError:[NSError errorWithDomain:@"com.rustdesk.broadcast"
|
||||
code:1
|
||||
userInfo:@{NSLocalizedDescriptionKey: @"Failed to connect to main app"}]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)broadcastPaused {
|
||||
// Handle pause
|
||||
}
|
||||
|
||||
- (void)broadcastResumed {
|
||||
// Handle resume
|
||||
}
|
||||
|
||||
- (void)broadcastFinished {
|
||||
if (self.messagePort) {
|
||||
CFRelease(self.messagePort);
|
||||
self.messagePort = NULL;
|
||||
}
|
||||
self.isConnected = NO;
|
||||
}
|
||||
|
||||
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
|
||||
if (!self.isConnected || !self.messagePort) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sampleBufferType) {
|
||||
case RPSampleBufferTypeVideo:
|
||||
dispatch_async(self.videoQueue, ^{
|
||||
[self processVideoSampleBuffer:sampleBuffer];
|
||||
});
|
||||
break;
|
||||
|
||||
case RPSampleBufferTypeAudioApp:
|
||||
case RPSampleBufferTypeAudioMic:
|
||||
// Handle audio if needed
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer {
|
||||
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
if (!imageBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
|
||||
size_t width = CVPixelBufferGetWidth(imageBuffer);
|
||||
size_t height = CVPixelBufferGetHeight(imageBuffer);
|
||||
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
|
||||
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
|
||||
|
||||
if (baseAddress) {
|
||||
// Create a header with frame info
|
||||
struct FrameHeader {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t dataSize;
|
||||
} header = {
|
||||
.width = (uint32_t)width,
|
||||
.height = (uint32_t)height,
|
||||
.dataSize = (uint32_t)(width * height * 4) // Always RGBA format
|
||||
};
|
||||
|
||||
// Send header first
|
||||
CFDataRef headerData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)&header, sizeof(header));
|
||||
|
||||
if (headerData) {
|
||||
SInt32 result = CFMessagePortSendRequest(self.messagePort, 1, headerData, 1.0, 0.0, NULL, NULL);
|
||||
CFRelease(headerData);
|
||||
|
||||
if (result == kCFMessagePortSuccess) {
|
||||
// Send frame data
|
||||
CFDataRef frameData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)baseAddress, header.dataSize);
|
||||
if (frameData) {
|
||||
CFMessagePortSendRequest(self.messagePort, 2, frameData, 1.0, 0.0, NULL, NULL);
|
||||
CFRelease(frameData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -70,6 +70,8 @@
|
||||
<string>This app needs camera access to scan QR codes</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>This app needs photo library access to get QR codes from image</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>This app needs microphone access for screen recording with audio</string>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
|
||||
Reference in New Issue
Block a user