iOS 直播屏幕Replaykit

相關(guān)文章
iOS 解決LFLiveKit 自帶GPUImage
iOS ReplayKit RPRecordingErrorFailedToStart

Github地址

Replaykit是iOS對屏幕進(jìn)行直播推出的框架

流程圖

本文涉及三方:

LFLiveKit-ReplayKit

準(zhǔn)備工作

使用Replaykit需要建立兩個擴(kuò)展

Broadcast Upload Extension  接受和上傳視頻幀和音頻幀(記錄:[RPScreenRecorder sharedRecorder]不開啟enableMic就沒mic聲音)
Broadcast Setup UI Extension 用戶交互界面,比如輸入直播地址
這兩個可以簡單理解為一個是拉皮條的,一個是干活的,缺一不可

選擇Broadcast Upload Extension


建立擴(kuò)展

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


勾選上UI這個選項(xiàng)就會自動建立UI的擴(kuò)展了

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


擴(kuò)展

先簡單介紹一下這兩個擴(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
有問題或者指正意見請不吝賜教和評論!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,171評論 3 119
  • 私心,每個月都有自己的私心!你得私心是什么呢? 我的私心是希望父親及家人身體健康,快樂! 今年利用工作辦事的時間帶...
    f84c7f8e61da閱讀 279評論 0 0
  • 你有沒有過被一首歌唱的潸然淚下?多年以前,我堅定的認(rèn)為聽歌會哭的人都是矯情,好吧,我承認(rèn)我錯了。 01 很久很久以...
    撐爆的錢包閱讀 491評論 0 0
  • 物以類聚,人與群分這個自古流傳的成語,很大程度的印證了社群的客觀存在及其價值。無論對于誰來說,只有當(dāng)你的客戶變成用...
    四汐緣閱讀 2,048評論 0 13

友情鏈接更多精彩內(nèi)容