进程间通信-CFNotificationCenterGetDar

2020-12-01  本文已影响0人  斌小狼

文章写得不多、尽量只写干货

简要

CFNotificationCenterGetDarwinNotifyCenter,是CoreFundation中的一个类,可以实现进程间的通知,将通知从扩展App发送到主App中。

而之前文章说的屏幕共享,使用了Broadcast Upload Extension,而这就是扩展App,其负责采集和传输数据,本章将讲述数据传输的简单实现。

SampleHandler

SampleHandler中有诸多方法都是获取各种信息的、我们需要把信息传给主App:

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
    [self sendNotificationWithIdentifier:@"broadcastStartedWithSetupInfo" userInfo:setupInfo];
}

- (void)broadcastPaused {
    // User has requested to pause the broadcast. Samples will stop being delivered.
    [self sendNotificationWithIdentifier:@"broadcastPaused" userInfo:nil];
}

- (void)broadcastResumed {
    // User has requested to resume the broadcast. Samples delivery will resume.
    [self sendNotificationWithIdentifier:@"broadcastResumed" userInfo:nil];
}

- (void)broadcastFinished {
    // User has requested to finish the broadcast.
    [self sendNotificationWithIdentifier:@"broadcastFinished" userInfo:nil];
}

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:{
            // Handle video sample buffer
            //如果有网速不好的情况、请酌情丢弃数据、不要阻塞线程导致程序崩溃
            NSDictionary * info = [[NSDictionary alloc] initWithObjectsAndKeys:[self dataWithSampBuffer:sampleBuffer],@"buffer", nil];
            [self sendNotificationWithIdentifier:@"processSampleBuffer" userInfo:info];
        }
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}

identifier为通知标识,为区分哪个方法发出的通知。

传输数据流

CMSampleBufferRef不能直接传输,那么我们把它转换成NSData:

- (NSData *)dataWithSampBuffer:(CMSampleBufferRef)sampBuffer { CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    void *src_buff = CVPixelBufferGetBaseAddress(imageBuffer);
    NSData *data = [NSData dataWithBytes:src_buff length:bytesPerRow * height];
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    return data;
}

发送通知

- (void)sendNotificationWithIdentifier:(nullable NSString *)identifier userInfo:(NSDictionary *)info {
    CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
    CFDictionaryRef userInfo = (__bridge CFDictionaryRef)info;
    BOOL const deliverImmediately = YES;
    CFStringRef identifierRef = (__bridge CFStringRef)identifier;
    CFNotificationCenterPostNotification(center, identifierRef, NULL, userInfo, deliverImmediately);
}

主App

接收通知~首先需要:

注册通知

identifier需要与发送端保持一致哟~~

- (void)addNotifications {
    [self registerNotificationsWithIdentifier:@"broadcastStartedWithSetupInfo"];
    [self registerNotificationsWithIdentifier:@"broadcastPaused"];
    [self registerNotificationsWithIdentifier:@"broadcastResumed"];
    [self registerNotificationsWithIdentifier:@"broadcastFinished"];
    [self registerNotificationsWithIdentifier:@"processSampleBuffer"];
    //这里同时注册了分发消息的通知,在宿主App中使用
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(NotificationAction:) name:NotificationName object:nil];
}
- (void)registerNotificationsWithIdentifier:(nullable NSString *)identifier{
    CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
    CFStringRef str = (__bridge CFStringRef)identifier;
   
    CFNotificationCenterAddObserver(center,
                                    (__bridge const void *)(self),
                                    NotificationCallback,
                                    str,
                                    NULL,
                                    CFNotificationSuspensionBehaviorDeliverImmediately);
}

其中NotificationCallback为接到通知后使用此方法取值。

void NotificationCallback(CFNotificationCenterRef center,
                                   void * observer,
                                   CFStringRef name,
                                   void const * object,
                                   CFDictionaryRef userInfo) {
    NSString *identifier = (__bridge NSString *)name;
    NSObject *sender = (__bridge NSObject *)observer;
    //NSDictionary *info = (__bridge NSDictionary *)userInfo;
//    NSDictionary *info = CFBridgingRelease(userInfo);
    NSDictionary *notiUserInfo = @{@"identifier":identifier};
    [[NSNotificationCenter defaultCenter] postNotificationName:NotificationName
                                                        object:sender
                                                      userInfo:notiUserInfo];
}
结果输出
- (void)NotificationAction:(NSNotification *)noti {
    NSDictionary *userInfo = noti.userInfo;
    NSString *identifier = userInfo[@"identifier"];
    
    if ([identifier isEqualToString:@"broadcastStartedWithSetupInfo"]) {
        NSLog(@"broadcastStartedWithSetupInfo");
    }
    if ([identifier isEqualToString:@"broadcastPaused"]) {
        NSLog(@"broadcastPaused");
    }
    if ([identifier isEqualToString:@"broadcastResumed"]) {
        NSLog(@"broadcastResumed");
    }
    if ([identifier isEqualToString:@"broadcastFinished"]) {
        NSLog(@"broadcastFinished");
    }
    if ([identifier isEqualToString:@"processSampleBuffer"]) {
        NSLog(@"processSampleBuffer");
    }
}

测试

这时你会发现你接到了扩展中发出的通知,通过输出测试突然发现:传的数据流哪去了?为什么没有输出?好奇怪,是不是扩展没有传过来?

调试

运行扩展进行断点输出:


断点输出

呃、事实证明我们确实传输了数据、那么数据究竟哪去了?

调研

怀着官网肯定不会骗我的心态开始了官网的"扫描"
CFNotificationCenterPostNotification

难过
CFNotificationCenterAddObserver
并没有userInfo的接收参数

\color{red}{可以更改上边的sendNotificationWithIdentifier方法不必传输userInfo了😭}

所以:进程级通知不允许传输数据?!!!(咱也不确定、只能在此请求大佬给予指点🙏)

App Groups:数据共享

App Groups详情
此处直接使用代码完成了,详情请看上行链接

SampleHandler.m
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:{
            // Handle video sample buffer
            //如果有网速不好的情况、请酌情丢弃数据、不要阻塞线程导致程序崩溃
            [self saveNSDataWithFileManager:[self dataWithSampBuffer:sampleBuffer]];
            
        }
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}
- (void)saveNSDataWithFileManager:(NSData*)data{
    NSError *err = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.tongxun_xiaolang"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/data"];
    NSString *dataString = [[NSString alloc] initWithData:data encoding:kCFStringEncodingUTF8];
    BOOL result = [dataString writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err];
    if (result) {
        //已经修改完sendNotificationWithIdentifier方法(不传userInfo)
        [self sendNotificationWithIdentifier:@"processSampleBuffer"];
    }
}
主App
-(void)getDataWithFileManager{
    NSError *err = nil;
    NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.tongxun_xiaolang"];
    containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/data"];
    NSString *value = [NSString stringWithContentsOfURL:containerURL encoding:NSUTF8StringEncoding error:&err];
    NSData *data = [value dataUsingEncoding:NSUTF8StringEncoding];

    if (err != nil) {
        NSLog(@"xxxx %@",err);
        return;
    }
    NSLog(@"----%@",data);
}

且NotificationAction方法中:

if ([identifier isEqualToString:@"processSampleBuffer"]) {
        [self getDataWithFileManager];
    }
测试

主App已经能拿到NSData(非SampleBuffer)明天添加转化
但运行一下之后扩展突然崩溃了、原因:内存不足、扩展中不能大于50M数据、需要进行编解码处理~ 明天继续

ps:没那么简单、、、在多种操作合并时卡住了😢、修复中、、、

上一篇 下一篇

猜你喜欢

热点阅读