Skip to content

当前版本:V1.2.8

苏州必捷网络有限公司

1 概述

1.1 目的

用于指导使用必捷SDK开发iOS发送端应用程序。

1.2 读者对象

本文档适用于iOS发送端应用程序的开发人员和测试人员。

1.3 缩略语定义

缩写名称英文中文
BJCast必捷无线投屏协议

2 范围

2.1 功能

本SDK为BJCast发射端SDK,和BJCast接收端SDK配合进行无线投屏。

本SDK为标准的iOS framework模块,提供objective-c接口供应用集成。

2.2 SDK框架

总体框架分为两层:

  1. SDK层: BJCastFramework.framework是一个iOS framework,以framework方式提供。实现了投屏控制协议,媒体传输和处理协议。

  2. 应用层:开发的具体APP应用部分,我司交付的是DEMO APP,具体与客户应用集成,可做针对性开发。用户可参考修改,也可直接使用。

2.3 SDK交付物

  • SDK库
  • DEMO APP源代码,Demo APP基于最新SDK,作为参考实现提供给客户
  • SDK接口文档

2.4 版本要求

  • 支持的操作系统: iOS 12 及以上版本

3 接口

3.1 BJCastOCInterface类中的接口说明

3.1.1 初始化参数设置接口

objectivec
+(void)startConfig:(BJCastOCConfiger *)configer

描述

设置SDK的初始化参数,在启动做初始化时调用。

参数

名称描述
configerSDK初始化参数

其中BJCastOCConfiger支持以下常用属性的设置:

属性名描述必填
enableWeaknetOpt是否启用弱网功能,请填入true为启用
ipAddressBJCast接收端的ip地址
portBJCast接收端服务端口,默认为8190
password投屏密码。请填入""空字符串。当前iOS发射端不支持投屏密码功能。
codecFlags发射端编码器能力集,为位域类型, 参考下表说明。默认建议初始化为0x01
heartbeatAttemps心跳超时尝试次数,推荐值3
heartbeatInterval心跳间隔,单位秒,推荐值2

其中codecFlags支持以下取值:

属性名描述
0x01H264
0x02H265
0x03H264&H265

3.1.2 设置详细的投屏场景配置参数

objectivec
+(void)setUserEncodeSceneDef:(NSString*)encodeSceneConf

描述

设置详细的投屏场景配置参数。

此接口用于设置编解码相关的策略,通常用户可以基于此接口实现高-中-低等编码质量等策略。这部分功能较复杂,若用户无类似业务需求可不做关注。

如关注此部分业务接口,请与必捷相关的业务接口人对接咨询。

参数

名称描述
encodeSceneConfjson格式的详细参数,具体请参考demo实现。

示例代码:

objectivec
-(void)parseJson:(NSData *)jsonData
{
    NSDictionary *sceneDic=[NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:nil];
    NSArray *sceneCollArray=[sceneDic objectForKey:@"scene_define"];
    for(id obj in sceneCollArray){
        NSDictionary *sceneContentDic=obj;
        NSData *sceneData=[NSJSONSerialization dataWithJSONObject:sceneContentDic options:NSJSONWritingPrettyPrinted error:nil];
        NSString *sceneDataStr=[[NSString alloc] initWithData:sceneData encoding:NSUTF8StringEncoding];
        [self.sceneArray addObject:sceneDataStr];
    }
}

3.1.3 初始化接口

objectivec
+(void)initializeSDK;

描述

在SDK初始化的时候调用。

3.1.4 发起投屏

objectivec
+(void)createSession;

描述

通过此接口发起投屏,发起投屏的结果会已通过3.2.1.1接口异步通知用户。

示例代码:

objectivec
BJCastOCConfiger *configer = [[BJCastOCConfiger alloc] init];
configer.ipAddress=[self.settingParamGroup stringForKey:key_ReceiverIPAddress];
configer.port=(int32_t)[[self.settingParamGroup stringForKey:key_ReceiverPort] integerValue];
configer.password= @"";
configer.enableWeaknetOpt = [[self.settingParamGroup stringForKey:key_EnableWeaknetOpt] boolValue];
configer.codecFlags = 0x01; 
configer.heartbeatAttemps=(int)[self.settingParamGroup integerForKey:key_HeartbeatAttemps];
configer.heartbeatInterval=(int)[self.settingParamGroup integerForKey:key_HeartbeatInterval];
NSLog(@"heartbeat Attemps: %ld interval: %ld",[self.settingParamGroup integerForKey:key_HeartbeatAttemps],[self.settingParamGroup integerForKey:key_HeartbeatInterval]);
NSLog(@"start init BJCAST SDK.");
self->ctrlSessionConnRecoveredEventFlag=NO;
NSString *scenestr = [self.settingParamGroup stringForKey:key_EncSceneStr];
NSLog(@"use encode scene str: %@", scenestr);
[BJCastOCInterface setUserEncodeSceneDef:scenestr];
[BJCastOCInterface startConfig:configer];
[BJCastOCInterface initializeSDK];
[BJCastOCInterface createSession];

3.1.5 停止投屏

objectivec
+(void)destroySession;

描述

调用此接口停止投屏。在需要结束投屏时,调用此接口。

3.1.6 去初始化接口

objectivec
+(void)uninitSDK;

描述

用于去初始化BJCast模块。App销毁BJCast发射端服务时调用。

3.1.7 视频数据传输接口

objectivec
+(void)transportMediaVideoDataByData:(uint8_t*)data size:(uint32_t)size pts:(uint64_t)pts

描述

镜像视频数据传输接口,用户需要进行屏幕的录制,并将录屏视频数据转换为H264格式。

通过此接口将录制的视频数据传输到接收端进行显示。

参数

名称描述
data视频数据数组
size数据块长度
pts时间戳,时间戳单位为1/1000000秒

返回值

调用示例

可以参考SDK中DEMO源代码中outPutH264Data方法中的实现。

3.1.8 音频数据传输接口

objectivecobjectivec
+(void)transportMediaAudioDataByData:(uint8_t*)data size:(uint32_t)size pts:(uint64_t)pts

描述

镜像音频数据传输接口,用户需要进行音频的录制,并将录制的PCM数据转换为AAC格式。

通过此接口将音频数据传输到接收端进行播放。

参数

名称描述
data音频数据数组
size数据块长度
pts时间戳,时间戳单位为1/1000000秒

返回值

调用示例

可以参考SDK中DEMO源代码中encodedAAC方法中的实现。

3.1.9 投屏密码重试

objectivec
+(void)reAuthSession:(NSString*)pass

描述

投屏密码校验错误后,通过此接口重新输入投屏密码。

当前该接口不生效

参数

pass:用户输入的新的投屏密码。

3.2 注册状态通知监听的接口说明

3.2.1 注册投屏状态通知监听

objectivec
extern NSString  *const BJCastOCInterfaceStatusNotification

描述

注册名为BJCastOCInterfaceStatusNotification通知的监听者,当通知被发送时,调用相应的方法获取到投屏的状态。

3.2.1.1 BJCastConnectStatus属性

参数描述
BJCastConnectInitFailed信令连接失败
BJCastConnectInitSuccessed信令连接成功
BJCastConnectSessionFailed投屏失败
BJCastConnectSessionSuccessed投屏成功
BJCastConnectSessionEnded投屏结束
BJCastConnectSessionFailedNetworkFail投屏网络异常
BJCastConnectSessionFailedCallReject投屏被拒
BJCastConnectSessionFailedNoScreenResource达到最大投屏数量
BJCastConnectSessionFailedAuthFailed投屏密码校验失败
BJCastConnectSessionKickOut投屏被踢出

示例代码:

objectivec
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(libeventStatusChange:) name:BJCastOCInterfaceStatusNotification object:nil];

-(void)libeventStatusChange:(NSNotification *)notification
{
    NSDictionary *userInfo = notification.userInfo;
    NSNumber *status = userInfo[BJCastConnectStatusKey];
    connectStatus = (BJCastConnectStatus)status.integerValue;
    NSLog(@"libeventStatusChange: %d", connectStatus);
    switch (connectStatus) {
        case BJCastConnectSessionSuccessed:
        {
            NSLog(@"cast status before BJCastConnectSessionSuccessed: %@",[self.settingParamGroup boolForKey:key_CastStatus]?@"YES":@"NO");
            [self.settingParamGroup setBool:YES forKey:key_CastStatus];
            [self.settingParamGroup synchronize];
            NSLog(@"cast status turned into YES");
            break;
        }
        case BJCastConnectInitSuccessed:
            break;
        case BJCastConnectSessionFailedNetworkFail:
        case BJCastConnectSessionKickOut:
        case BJCastConnectSessionFailed:
        case BJCastConnectInitFailed:
        case BJCastConnectSessionEnded:
        case BJCastConnectSessionFailedNoScreenResource:
        case BJCastConnectSessionFailedAuthFailed://E_AUTH_FAILED
//        case BJCastConnectSessionFailedNetworkFail://E_NETWORK_FAILURE E_TIMEOUT
//        case BJCastConnectSessionFailedCallReject://E_CALL_REJECTED
//        case BJCastConnectSessionFailedNoScreenResource://E_CALL_NO_SCREEN_RESOURCE
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSError *endErr = [NSError errorWithDomain:@"com.bj.BJNativeLiveIOS.BJNativeLiveIOSBroadcastExtension" code:0 userInfo:@{NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"投屏已结束", nil)}];
                [self.settingParamGroup setBool:NO forKey:key_CastStatus];
                [self.settingParamGroup synchronize];
                [self finishBroadcastWithError:endErr];
                [BJCastOCInterface destroySession];
                [BJCastOCInterface uninitSDK];
            });
        }
            break;
        default:
            break;
    }
}

3.2.2 注册全屏状态通知监听

objectivec
extern NSString  *const BJCastOCInterfaceSessionNotification

描述

注册名为BJCastOCInterfaceStatusNotification通知的监听者,当通知被发送时,调用相应的方法获取到全屏的状态。

3.2.3 注册关键帧请求通知监听

objectivec
extern NSString  * const BJCastOCInterfaceMediaSessionIFrameReqNotification

描述

注册名为BJCastOCInterfaceMediaSessionIFrameReqNotification通知的监听者,当通知被发送时,调用相应的方法请求关键帧。

3.2.4 注册心跳丢失通知监听

objectivec
extern NSString  * const BJCastSessionHeartBeatLostNotification

描述

注册名为BJCastSessionHeartBeatLostNotification通知的监听者,当通知被发送时,从user Info[BJCastSessionHeartBeatLossCountKey]中获取到信令连接心跳丢失次数信息。用户根据心跳丢失的次数自主判断是否结束投屏。

3.2.5 心跳恢复通知监听

objectivec
extern NSString  * const BJCastCtrlSessionConnectionRecoveredNotification;

描述

注册名为BJCastCtrlSessionConnectionRecoveredNotification通知的监听者,当通知被发送时,表示信令连接恢复正常。

3.2.6 注册暂停投屏通知监听

objectivec
extern NSString  * const BJCastSessionPauseMediaNotification

描述

注册名为BJCastSessionPauseMediaNotification通知的监听者,当通知被发送时,调用中断录屏方法中断录屏。

3.2.7 注册恢复投屏通知监听

objectivec
extern NSString  *const BJCastSessionResumeMediaNotification

描述

注册名为BJCastSessionResumeMediaNotification通知的监听者,当通知被发送时,调用开启录屏方法开启录屏。

3.2.8 注册媒体协商通知监听

objectivec
extern NSString  *const BJCastUpdateMediaNegotiationNotification;

描述

注册名为BJCastUpdateMediaNegotiationNotification通知的监听者,当收到该通知时,需要按照userInfo中提供的参数重置编码器,具体示例代码请见demo。

备注

userInfo中的参数key值如下:

key描述
BJCastCodecNegotiationFramerate帧率(单位:fps)
BJCastCodecNegotiationBitrate码率(单位:kbps)
BJCast CodecNegotiationResolutionWidth图像宽度(单位:像素)
BJCastCodecNegotiationResolutionHeight图像高度(单位:像素)
BJCastCodecNegotiationCodecType编码类型(0x01=H264,0x02=H265)
BJCastCodecNegotiationMaxFramerate最大帧率(单位:fps)

4 客户如何使用SDK

4.1 集成简要说明

iOS 端基于苹果提供的 Replaykit 框架实现屏幕录制,可以分享整个系统的屏幕内容。但由于苹果的隐私设置,不同 App 之间数据无法互通,因此需要当前 App(主 App 进程)额外提供一个 Extension 扩展组件(Extension 进程),并且把 App 和 Extension 配置为同一 App Group(有关 app group的相关配置请参考文档Configuring App Groups | Apple Developer Documentation),让 Extension 录屏进程可以同主 App 进程进行跨进程通信,实现屏幕内容分享。

步骤一:创建 App Group

为使 Extension 录屏进程可以和主 App 进程进行跨进程通信,需要将 Extension 和 App 配置为同一 App Group。

步骤二:创建 Extension 扩展组件

新建 Broadcast Upload Extension 组件并进行相关配置。

在 Xcode 中,点击 File > New > Target...,在弹出对话框中选择 Broadcast Upload Extension,点击 Next。

步骤三:在 Extension 组件中实现屏幕采集逻辑

参考如下代码在 SampleHandler.m 文件中实现屏幕采集逻辑。在新创建的 Target 中,Xcode 将自动创建 SampleHandler.h 文件。

objc
#import "SampleHandler.h"
@interface SampleHandler()<EncodeH264Delgate, LDAACEncodeerDelegate>
@end
    
@implementation SampleHandler

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
    self.angle = -1;
    isFirstVideo = true;
    baseVideoTime = 0;
    //    [self initBJCastSDK];
    //    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(libeventStatusChange:) name:BJCastOCInterfaceStatusNotification object:nil];
	dispatch_async(dispatch_get_main_queue(), ^{
        [self requestGetData];
    });
}

- (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.
    // 结束屏幕采集
    NSLog(@"broadcastFinished");
    [self.settingParamGroup setBool:NO forKey:key_CastStatus];
    [self.settingParamGroup synchronize];
    [h264Encoder stopEncodeSession];
    h264Encoder = nil;
    [BJCastOCInterface uninitSDK];
}

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:// 采集到的屏幕视频流
            [h264Encoder encodeSmapleBuffer:sampleBuffer];
            break;
        case RPSampleBufferTypeAudioApp:// 采集到的设备音频流
            [aacEncoder encodeSampleBuffer:sampleBuffer];
            break;
        case RPSampleBufferTypeAudioMic:
            // 采集到的麦克风音频流
            break;
            
        default:
            break;
    }
}