Appearance
当前版本: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框架
总体框架分为两层:
SDK层: BJCastFramework.framework是一个iOS framework,以framework方式提供。实现了投屏控制协议,媒体传输和处理协议。
应用层:开发的具体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的初始化参数,在启动做初始化时调用。
参数
名称 | 描述 |
---|---|
configer | SDK初始化参数 |
其中BJCastOCConfiger支持以下常用属性的设置:
属性名 | 描述 | 必填 |
---|---|---|
enableWeaknetOpt | 是否启用弱网功能,请填入true为启用 | 是 |
ipAddress | BJCast接收端的ip地址 | 是 |
port | BJCast接收端服务端口,默认为8190 | 是 |
password | 投屏密码。请填入""空字符串。当前iOS发射端不支持投屏密码功能。 | 是 |
codecFlags | 发射端编码器能力集,为位域类型, 参考下表说明。默认建议初始化为0x01 | 是 |
heartbeatAttemps | 心跳超时尝试次数,推荐值3 | 是 |
heartbeatInterval | 心跳间隔,单位秒,推荐值2 | 是 |
其中codecFlags支持以下取值:
属性名 | 描述 |
---|---|
0x01 | H264 |
0x02 | H265 |
0x03 | H264&H265 |
3.1.2 设置详细的投屏场景配置参数
objectivec
+(void)setUserEncodeSceneDef:(NSString*)encodeSceneConf
描述
设置详细的投屏场景配置参数。
此接口用于设置编解码相关的策略,通常用户可以基于此接口实现高-中-低等编码质量等策略。这部分功能较复杂,若用户无类似业务需求可不做关注。
如关注此部分业务接口,请与必捷相关的业务接口人对接咨询。
参数
名称 | 描述 |
---|---|
encodeSceneConf | json格式的详细参数,具体请参考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;
}
}