iOS 直播屏幕Replaykit
相关文章
iOS 解决LFLiveKit 自带GPUImage
iOS ReplayKit RPRecordingErrorFailedToStart
Replaykit是iOS对屏幕进行直播推出的框架
流程图本文涉及三方:
LFLiveKit-ReplayKit
准备工作
使用Replaykit需要建立两个扩展
Broadcast Upload Extension 接受和上传视频帧和音频帧(记录:[RPScreenRecorder sharedRecorder]不开启enableMic就没mic声音)
Broadcast Setup UI Extension 用户交互界面,比如输入直播地址
这两个可以简单理解为一个是拉皮条的,一个是干活的,缺一不可
选择Broadcast Upload Extension
建立扩展
勾选上Include UI Extension选项,就会自动添加Broadcast Setup UI Extension扩展
勾选上UI这个选项就会自动建立UI的扩展了
建立这两个扩展之后,项目里就会多出两个新的target
扩展
先简单介绍一下这两个扩展里的那点勾当
BroadcastSetupViewController,用来布局直播配置界面
这个Controller就像平常VC那样用
其实扩展就可以理解为一个新的app,平时怎么用,在这就怎么用
BroadcastSetupViewController里用户输入完信息之后,在控制器里调用
[self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo];
//该方法是iOS11后的的新方法
用来将用户配置信息传递给刚建立的另一个扩展Broadcast Upload Extension
其中的setupInfo是NSDictionary类型,用来存储自定义信息
比如:@{
@"broadcastName" : @"example",
@"MyName":@"Pokkey"
};
这个会传进Broadcast Upload Extension里的
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {}
其中的setupInfo就是传进来的setupInfo
起手
调起Replaykit进行屏幕直播
咱们建立的 Broadcast Upload Extension 和 Broadcast Setup UI Extension 都是依附于主app的扩展app,但是这个扩展不是只有咱们的主App能吊起来,其他在主app里添加了调起直播扩展的都能调起咱们写的这个直播扩展,当然别人写的直播扩展你的app也能调起来。
在app里引入Replaykit
#import <ReplayKit/ReplayKit.h>
调起扩展,调下面这个就能看到present了一个控制器,里面装满了你手机的直播扩展,包括我们自己的那个。
[RPBroadcastActivityViewController loadBroadcastActivityViewControllerWithHandler:^(RPBroadcastActivityViewController * _Nullable broadcastActivityViewController, NSError * _Nullable error) {
if (error) {
NSLog(@"RPBroadcast err %@", [error localizedDescription]);
} else {
broadcastActivityViewController.delegate = self;
broadcastActivityViewController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:broadcastActivityViewController animated:YES completion:nil];
}
}];
加上代理
@interface ViewController ()<RPBroadcastActivityViewControllerDelegate, RPBroadcastControllerDelegate>{
实现代理方法
这个方法是用户选了扩展之后回调的方法,我们在这方法里正式调起UI扩展,
- (void)broadcastActivityViewController:(RPBroadcastActivityViewController *) broadcastActivityViewController
didFinishWithBroadcastController:(RPBroadcastController *)broadcastController
error:(NSError *)error {
[broadcastActivityViewController dismissViewControllerAnimated:YES
completion:nil];
NSLog(@"BundleID %@", broadcastController.broadcastExtensionBundleID);
self.broadcastController = broadcastController;
if (error) {
NSLog(@"BAC: %@ didFinishWBC: %@, err: %@",
broadcastActivityViewController,
broadcastController,
error);
return;
}
[broadcastController startBroadcastWithHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"--fshfka----success");
}
else {
NSLog(@"startBroadcast %@",error.localizedDescription);
}
}];
}
这个方法用来接收直播传回来的NSDictionary
// Watch for service info from broadcast service
- (void)broadcastController:(RPBroadcastController *)broadcastController
didUpdateServiceInfo:(NSDictionary <NSString *, NSObject <NSCoding> *> *)serviceInfo {
NSLog(@"didUpdateServiceInfo: %@", serviceInfo);
}
直播关闭
// Broadcast service encountered an error
- (void)broadcastController:(RPBroadcastController *)broadcastController
didFinishWithError:(NSError *)error {
NSLog(@"didFinishWithError: %@", error);
}
>>> 特别提示!!!
>>> 特别提示!!!
>>> 特别提示!!!
>>> 如果开始直播后画面没有变化,就没有视频帧
如果需要接入麦克风
[[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];
接下来我们就要进入Replaykit的关键部分了
开干
进入核心部分UploadExtension,建立UploadExtension扩展会根据模版自动建立SampleHandle.h和.m两个文件
UI调起这个方法,传入自定义信息
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
}
这三个方法覆盖父类,接受停止,继续,和停止事件
- (void)broadcastPaused {
// User has requested to pause the broadcast. Samples will stop being delivered.
}
- (void)broadcastResumed {
// User has requested to resume the broadcast. Samples delivery will resume.
}
- (void)broadcastFinished {
// User has requested to finish the broadcast.
}
这个接收传过来的
<视频帧 RPSampleBufferTypeVideo>
< app音效 RPSampleBufferTypeAudioApp >
< 话筒 RPSampleBufferTypeAudioMic >
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
switch (sampleBufferType) {
case RPSampleBufferTypeVideo:
// Handle video sample buffer
break;
case RPSampleBufferTypeAudioApp:
// Handle audio sample buffer for app audio
break;
case RPSampleBufferTypeAudioMic:
// Handle audio sample buffer for mic audio
break;
default:
break;
}
}
这个方法才是核心方法,在这个里拿到了视频帧和音频帧就可以推给直播平台了
不过后来又出了个方法,在这个里也是直接拿到视频帧和音频帧,而且不需要掉Extension,不过这两种方法见仁见智,看哪种更适合你的需求
[RPScreenRecorder sharedRecorder]
- (void)startCaptureWithHandler:(nullable void(^)(CMSampleBufferRef sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error))captureHandler completionHandler:(nullable void(^)(NSError * _Nullable error))completionHandler API_AVAILABLE(ios(11.0), tvos(11.0));
数据传输
在扩展里最好建立一个单例来进行IO,防止扩展多次调用造成重复创建。
在demo中使用ZFUploadTool负责进行数据的传输
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
switch (sampleBufferType) {
case RPSampleBufferTypeVideo:
// 将视频帧交给ZFUploadTool
[self.tool sendVideoBuffer:sampleBuffer];
break;
case RPSampleBufferTypeAudioApp:
// [self.tool sendAudioBuffer:sampleBuffer];
break;
case RPSampleBufferTypeAudioMic:
// 将音频帧交给ZFUploadTool 此项需要打开 [[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];
[self.tool sendAudioBuffer:sampleBuffer];
break;
default:
break;
}
}
在ZFUploadTool只需要
[self.session pushAudioBuffer:sampleBuffer];
[self.session pushVideoBuffer:sampleBuffer];
这两个方法限于LFLiveKit-ReplayKit 版本
更多详细查看Demo
有问题或者指正意见请不吝赐教和评论!