文章寫得不多、盡量只寫干貨
簡要
CFNotificationCenterGetDarwinNotifyCenter,是CoreFundation中的一個(gè)類,可以實(shí)現(xiàn)進(jìn)程間的通知,將通知從擴(kuò)展App發(fā)送到主App中。
而之前文章說的屏幕共享,使用了Broadcast Upload Extension,而這就是擴(kuò)展App,其負(fù)責(zé)采集和傳輸數(shù)據(jù),本章將講述數(shù)據(jù)傳輸?shù)暮唵螌?shí)現(xiàn)。
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
//如果有網(wǎng)速不好的情況、請酌情丟棄數(shù)據(jù)、不要阻塞線程導(dǎo)致程序崩潰
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為通知標(biāo)識,為區(qū)分哪個(gè)方法發(fā)出的通知。
傳輸數(shù)據(jù)流
CMSampleBufferRef不能直接傳輸,那么我們把它轉(zhuǎn)換成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;
}
發(fā)送通知
- (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需要與發(fā)送端保持一致喲~~
- (void)addNotifications {
[self registerNotificationsWithIdentifier:@"broadcastStartedWithSetupInfo"];
[self registerNotificationsWithIdentifier:@"broadcastPaused"];
[self registerNotificationsWithIdentifier:@"broadcastResumed"];
[self registerNotificationsWithIdentifier:@"broadcastFinished"];
[self registerNotificationsWithIdentifier:@"processSampleBuffer"];
//這里同時(shí)注冊了分發(fā)消息的通知,在宿主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];
}
結(jié)果輸出
- (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");
}
}
測試
這時(shí)你會發(fā)現(xiàn)你接到了擴(kuò)展中發(fā)出的通知,通過輸出測試突然發(fā)現(xiàn):傳的數(shù)據(jù)流哪去了?為什么沒有輸出?好奇怪,是不是擴(kuò)展沒有傳過來?
調(diào)試
運(yùn)行擴(kuò)展進(jìn)行斷點(diǎn)輸出:

呃、事實(shí)證明我們確實(shí)傳輸了數(shù)據(jù)、那么數(shù)據(jù)究竟哪去了?
調(diào)研
懷著官網(wǎng)肯定不會騙我的心態(tài)開始了官網(wǎng)的"掃描"
CFNotificationCenterPostNotification:

CFNotificationCenterAddObserver:
并沒有userInfo的接收參數(shù)
所以:進(jìn)程級通知不允許傳輸數(shù)據(jù)??。。。ㄔ垡膊淮_定、只能在此請求大佬給予指點(diǎn)??)
App Groups:數(shù)據(jù)共享
App Groups詳情
此處直接使用代碼完成了,詳情請看上行鏈接
SampleHandler.m
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
switch (sampleBufferType) {
case RPSampleBufferTypeVideo:{
// Handle video sample buffer
//如果有網(wǎng)速不好的情況、請酌情丟棄數(shù)據(jù)、不要阻塞線程導(dǎo)致程序崩潰
[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) {
//已經(jīng)修改完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已經(jīng)能拿到NSData(非SampleBuffer)明天添加轉(zhuǎn)化
但運(yùn)行一下之后擴(kuò)展突然崩潰了、原因:內(nèi)存不足、擴(kuò)展中不能大于50M數(shù)據(jù)、需要進(jìn)行編解碼處理~ 明天繼續(xù)
ps:沒那么簡單、、、在多種操作合并時(shí)卡住了??、修復(fù)中、、、