相關(guān)文章
iOS 解決LFLiveKit 自帶GPUImage
iOS ReplayKit RPRecordingErrorFailedToStart
Replaykit是iOS對屏幕進(jìn)行直播推出的框架

本文涉及三方:
LFLiveKit-ReplayKit
準(zhǔn)備工作
使用Replaykit需要建立兩個擴(kuò)展
Broadcast Upload Extension 接受和上傳視頻幀和音頻幀(記錄:[RPScreenRecorder sharedRecorder]不開啟enableMic就沒mic聲音)
Broadcast Setup UI Extension 用戶交互界面,比如輸入直播地址
這兩個可以簡單理解為一個是拉皮條的,一個是干活的,缺一不可
選擇Broadcast Upload Extension

勾選上Include UI Extension選項(xiàng),就會自動添加Broadcast Setup UI Extension擴(kuò)展

建立這兩個擴(kuò)展之后,項(xiàng)目里就會多出兩個新的target

先簡單介紹一下這兩個擴(kuò)展里的那點(diǎn)勾當(dāng)
BroadcastSetupViewController,用來布局直播配置界面
這個Controller就像平常VC那樣用
其實(shí)擴(kuò)展就可以理解為一個新的app,平時怎么用,在這就怎么用
BroadcastSetupViewController里用戶輸入完信息之后,在控制器里調(diào)用
[self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo];
//該方法是iOS11后的的新方法
用來將用戶配置信息傳遞給剛建立的另一個擴(kuò)展Broadcast Upload Extension
其中的setupInfo是NSDictionary類型,用來存儲自定義信息
比如:@{
@"broadcastName" : @"example",
@"MyName":@"Pokkey"
};
這個會傳進(jìn)Broadcast Upload Extension里的
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {}
其中的setupInfo就是傳進(jìn)來的setupInfo
第一步
調(diào)起Replaykit進(jìn)行屏幕直播
咱們建立的 Broadcast Upload Extension 和 Broadcast Setup UI Extension 都是依附于主app的擴(kuò)展app,但是這個擴(kuò)展不是只有咱們的主App能吊起來,其他在主app里添加了調(diào)起直播擴(kuò)展的都能調(diào)起咱們寫的這個直播擴(kuò)展,當(dāng)然別人寫的直播擴(kuò)展你的app也能調(diào)起來。
在app里引入Replaykit
#import <ReplayKit/ReplayKit.h>
調(diào)起擴(kuò)展,調(diào)下面這個就能看到present了一個控制器,里面裝滿了你手機(jī)的直播擴(kuò)展,包括我們自己的那個。
[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>{
實(shí)現(xiàn)代理方法
這個方法是用戶選了擴(kuò)展之后回調(diào)的方法,我們在這方法里正式調(diào)起UI擴(kuò)展,
- (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);
}
直播關(guān)閉
// Broadcast service encountered an error
- (void)broadcastController:(RPBroadcastController *)broadcastController
didFinishWithError:(NSError *)error {
NSLog(@"didFinishWithError: %@", error);
}
>>> 特別提示!??!
>>> 特別提示!?。?>>> 特別提示?。?!
>>> 如果開始直播后畫面沒有變化,就沒有視頻幀
如果需要接入麥克風(fēng)
[[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];
接下來我們就要進(jìn)入Replaykit的關(guān)鍵部分了
第二步
進(jìn)入核心部分UploadExtension,建立UploadExtension擴(kuò)展會根據(jù)模版自動建立SampleHandle.h和.m兩個文件
UI調(diào)起這個方法,傳入自定義信息
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
// User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
}
這三個方法覆蓋父類,接受停止,繼續(xù),和停止事件
- (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));
數(shù)據(jù)傳輸
在擴(kuò)展里最好建立一個單例來進(jìn)行IO,防止擴(kuò)展多次調(diào)用造成重復(fù)創(chuàng)建。
在demo中使用ZFUploadTool負(fù)責(zé)進(jìn)行數(shù)據(jù)的傳輸
- (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 此項(xiàng)需要打開 [[RPScreenRecorder sharedRecorder] setMicrophoneEnabled:YES];
[self.tool sendAudioBuffer:sampleBuffer];
break;
default:
break;
}
}
在ZFUploadTool只需要
[self.session pushAudioBuffer:sampleBuffer];
[self.session pushVideoBuffer:sampleBuffer];
這兩個方法限于LFLiveKit-ReplayKit 版本
更多詳細(xì)查看Demo
有問題或者指正意見請不吝賜教和評論!