美文网首页
进程间通信-CFNotificationCenterGetDar

进程间通信-CFNotificationCenterGetDar

作者: 斌小狼 | 来源:发表于2020-12-01 16:04 被阅读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:没那么简单、、、在多种操作合并时卡住了😢、修复中、、、

相关文章

  • 进程间通信-CFNotificationCenterGetDar

    文章写得不多、尽量只写干货 简要 CFNotificationCenterGetDarwinNotifyCente...

  • linux进程间通信(1)

    一、进程通信概述 1、什么是进程间通信?什么是线程间通信? 进程间通信: 进程间通信就指的是用户空间中进程A与进程...

  • 第二十三章 进程间通信介绍(一)

    本章目标: 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对...

  • 进程间的通信

    进程间的通信主要分为本机器进程间的通信和不同机器间进程的通信。本文主要描述本机进程间的通信。 一、传统Linux的...

  • 进程间通信

    进程间通信 进程空间相对独立,资源无法相互获取,此时在不同进程间通信需要专门方法 进程间通信就是在不同的进程间进行...

  • 进程间通信,线程间通信

    进程间通信 进程间通信又称IPC(Inter-Process Communication),指多个进程之间相互通信...

  • Android IPC机制

    IPC 即Inter-Process-Communication,含义是进程间通信/跨进程通信。是指多个进程间通信...

  • 进程管理(五)进程间通信、死锁

    (一)进程间通信 除了同步和互斥外,进程间还有其他的通信手段。 进程间的通信 --> IPC (InterProc...

  • 6. 进程间通信

    参考链接:1. 进程间通信及使用场景2. 进程间通信机制IPC3. 看图理解进程间通信IPC==重点4. 进程间通...

  • 【python】进程间通信:Queue的详细用法

    关于python 进程间通信 Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。 进程间通...

网友评论

      本文标题:进程间通信-CFNotificationCenterGetDar

      本文链接:https://www.haomeiwen.com/subject/jsojwktx.html