Skip to content

当前版本:V1.5

苏州必捷网络有限公司

1 概述

1.1 目的

用于指导使用必捷BJCast接收端 SDK的开发人员进行开发及测试。

1.2 读者对象

本文档适用于开发Android平台BJCast接收端的开发人员。

1.3 缩略语定义

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

2 范围

2.1 功能

本SDK可以支持接收Mac发射端,Windows发射端,Android发射端,iOS发射端的投屏请求。

此4种发射端都是采用BJCast投屏协议。

BJCastV1与BJCastV2在接收端的对外接口保持一致。

2.2 SDK框架

BJCast Receiver SDK总体分为两层:

  1. cast_base_lib-1.0.53-release.aar:它是一个Android Module,定义了基础的MediaChannel,Module接口。
  2. bjcast_lib_common-1.1.51-release.aar :它是一个Android Module,定义了BJCastModule,以及相关JNI接口。

应用程序应基于bjcast_lib_common-1.1.51-release.aar进行开发。

2.3 SDK的DEMO实现

BJCastReceiverSDKDemo是接收端的一个参考实现,它基于bjcast_lib_common-1.1.51-release.aar实现了BJCast接收端功能。

其中BJCastModuleImp实现了ModuleImpItf接口,

GLScreenRenderChannel实现了MediaChannel接口。

2.4 SDK交付物

  • AAR: 包括cast_base_lib和bjcast_lib_common两个aar。
  • DEMO源代码
  • SDK接口文档

3 接口

3.1 说明

接口主要在BJCastModule和MediaChannel中;用户可以自己实现相关接口, 也可参考我司提供的DEMO源代码实现。

3.2 BJCastModule接口说明

BJCastModule中的接口由SDK提供,应用程序调用。

3.2.1 设置客户定制的实现类接口

java
public void setImp(ModuleImpItf imp);

描述:

ModuleImpItf提供了一组用户接口,需要由用户实现对应的实现类,由SDK调用其中的接口。

参数

imp:用户实现的ModuleImpItf接口实例。具体请参考3.2部分的接口。

调用示例

请参考Demo部分代码。

3.2.2 初始化接口

java
public int initModule(Context context,Properties props);

描述:

BJCastModule类的initModule方法初始化BJCast接收端模块。App在启动做初始化时调用,BJCastModule对象应设计为全局只有一个。

其中Properties支持以下属性的设置:

属性名描述必填
“device_name”或BJCastModule.PARA_NAME_DEVICE_NAME接收端名称,发现协议搜索到的名称(如果客户不需要使用我司的发现协议,可以不用关心该属性)。
“license_key”或BJCastModule.PARA_NAME_LICENSE_KEYlicense Key,为使用必捷授权申请库或者申请工具申请的license授权。sdk内部会对此进行授权和校验。
license_check_token由必捷分配,用于初始化SDK的license校验和包名认证,防止被他人盗用。
license_check_pass由必捷分配,用于初始化SDK的license校验密码,防止盗用。
max_session_numsSDK支持的最大投屏路数,取值范围为1-16,默认为5。根据实际情况进行设置。通常设为1,代表支持1路投屏。
注意:如果要支持抢投,则需要设置比实际最大路数多1。
BJCastModule.PARA_NAME_SERVICE_PORT此处初始化BJCastV1服务端口,BJCastV1服务端口默认为8188,BJCastV2的服务端口为BJCastV1服务端口+2,默认为8190。用户可设定该端口值。当前BJCastV1已经废弃。
BJCastModule.PARA_NAME_HEARTBEAT_LOSTTIMES_LIMIT**(已废弃)**心跳丢失通知周期,默认为3,即心跳丢失3次时,会调用onLostHeartbeat接口通知应用心跳丢失。当前该参数已经废弃,实际该参数默认由发射端协商控制。默认为3
BJCastModule.PARA_NAME_HEARTBEAT_INTERVAL_SEC**(已废弃)**心跳间隔时间,单位为秒,默认为3s。当前心跳周期由发射端控制。
enable_media_timeout_check是否启用无媒体数据检测。1:表示启用, 0:不启用。默认为1。启用该功能时,当检查到连续60秒无任何媒体(视频/音频/鼠标)数据时,SDK将自动断开投屏。

返回值:

0表示成功,其它表示错误

返回值含义
0成功
-1初始化失败
其他License授权相关错误参考3.5节定义

调用示例:

java
public void prepareBJCastModule(Context context, String deviceName,String key) {
        Properties props = new Properties();
    	////设置name
        props.setProperty(BJCastModule.PARA_NAME_DEVICE_NAME, deviceName);
    
    	//设置license校验相关的参数
        props.setProperty(BJCastModule.PARA_NAME_LICENSE_KEY, key);
    	props.setProperty("license_check_token",licenseCheckToken); 
		props.setProperty("license_check_pass",licenseCheckPass);
    
        this.castModule = new BJCastModule();
        this.castModule.setImp(new BJCastModuleImp());
        int code = castModule.initModule(context,props);
        if (code == 0) {
            LogUtils.dTag(TAG, "BJCastModule init success");
        } else {
            LogUtils.eTag(TAG, "BJCastModule init failed");
        }
    }

注意事项:

初始化时还支持指定一些其它定制化的属性,或者针对某些业务场景的属性(如酒店投屏场景需要自动隐藏不被外部发现),这部分属性属于特定业务场景才需要使用的功能,在本文没有列出,如有需求请与我司商务/技术接口人对接咨询。

3.2.3 去初始化接口

java
public native void fini();

描述:

BJCastModule类的fini方法去初始化BJCast模块。App销毁BJCast接收端服务时调用。

3.2.4 应用主动踢出某投屏接口

java
public void kickOut(MediaChannel channel);

描述:

应用层主动结束会话接口。

参数:

channel:为当前需要主动踢出的投屏通道。为3.3.1节reqMediaChannel返回的MediaChannel实例。

注意事项

kickOut函数的调用不能在SDK的回调接口调用,容易导致死锁。建议用户异步起一个子线程调用。具体请参考Demo源码中的调用示例。

3.2.5 应用暂停某投屏通道

java
public native void pause(MediaChannel channel);

描述:

应用层主动暂停某个投屏会话接口。暂停后不会再收到码流。暂停可使用3.2.6接口恢复。

参数:

channel:为当前需要暂停的投屏通道。为3.3.1节reqMediaChannel返回的MediaChannel实例。

注意事项

当前仅Mac/Windows BJCast发射端支持该功能。

3.2.6 应用恢复某投屏通道

java
public native void resume(MediaChannel channel);

描述:

应用层恢复某个投屏会话接口。通常对已经处于暂停的通道才需要调用该接口。

参数:

channel:为当前需要恢复的投屏通道。

注意事项

当前仅Mac/Windows BJCast发射端支持该功能。

3.2.7 通知发射端调整分辨率和码率

java
public void updateVideoCapability(MediaChannel channel, VideoTrackInfo info);

描述:

应用层可以通过该接口通知发射端调整分辨率和码率,用于发起投屏后的重协商场景。

接收端SDK从bjcast_lib-1.1.17版本开始支持。

参数:

名称描述
channel当前需要修改的发射端所在投屏的channel
InfoVideoTrackInfo类型,期望设定的视频部分的分辨率,码率,帧率参数

注意事项

当前该接口已经废弃。重协商请使用3.2.8接口实现。

3.2.8 要求某个通道进行重协商接口

java
public void mediaReNegotiation(MediaChannel channel);

描述

应用层要求某个投屏会话进行重协商。

此时发射端会发起重协商流程,3.4.11的接口会被调用,接收端可实现相应的重协商策略,进而可对该投屏会话进行帧率,码率,分辨率的重协商。

如用户无相关业务场景,不需要关注此接口。

参数

channel:投屏会话,3.3.1节reqMediaChannel创建的投屏通道。

注意事项

重协商视频参数部分业务逻辑比较复杂。如用户无相关业务场景,不需要关注此接口。

接收端SDK从bjcast_lib-1.1.19版本开始支持。

Android发射端SDK从bjcast_sender_lib-1.1.17版本开始支持。

Windows sdk从V2.0.18.20220921.001开始支持。

MAC SDK从Week_Net_V2.0.22.zip开始支持

Electron Addon SDK从V1.0.20开始支持。

3.3 ModuleImpItf接口说明

3.3.1 会话接入接口

java
public MediaChannel reqMediaChannel(MediaChannelInfo info, UserInfo userInfo);

描述:

这是一个回调接口,当BJCast协议栈发现有会话接入时,JNI层会主动调用此接口,应用层需要实现相关逻辑,需要在客户自身的ModuleItf实现类中去实现该逻辑。

参数:

名称描述
info会话信息,MediaChannelInfo类型,描述投屏会话具体的音视频Track信息。
userInfo用户自定义信息,投屏设备基本信息

返回值

用户创建的自定义的MediaChannel实例对象,用户需按照3.4部分的接口实现自己的MediaChannel类,在此接口中创建对应的实例。

若返回null, sdk内部会自动断开此次投屏会话,当用户拒绝此次投屏或其它原因不允许投屏接入时,可直接返回null。

参考样例

java
@Override
public MediaChannel reqMediaChannel(MediaChannelInfo channelInfo, UserInfo userInfo) {
        //创建用户自定义的GLScreenRenderChannel实例
    	GLScreenRenderChannel channel = new GLScreenRenderChannel(channelInfo);
        if (!openAndStartChannel(channel)){
            Log.e(BJCastDemoApplication.TAG, "reqMediaChannel failed,because openAndStartChannel failed.");
            return null;
        }
		
    	//aac解码设置csd-0参数
        byte[]  buffer = new byte[2];
        buffer[0] = (byte) 0xb9;
        buffer[1] = (byte) 0x91;
        channel.setAudioTrackCodecInfo(buffer, "csd-0");

        CastManager.getMgr().putChannel(channel, userInfo);
        BJCastDemoApplication.APP.getEventBus().post(new BJCastEvent(channel, userInfo));

        return channel;  //返回MediaChannel实例,sdk将通过该channel反馈投屏相关的数据和事件
    }

具体实现可以参考DEMO源代码。

3.3.2 会话结束接口

java
public void relMediaChannel(MediaChannel channel);

描述

这是一个回调接口,由用户重载实现。

当投屏结束时,SDK内部会主动调用此接口,需要在客户自身的ModuleItf实现类中去实现该接口,用户需要释放MediaChannel相关的资源。

参数

名称描述
channelreqMediaChannel返回的MediaChannel实例

调用示例

具体实现可参考DEMO源代码。

3.3.3 投屏接入参数协商接口

java
public VideoTrackInfo mediaNegotiation(VideoTrackInfo[] supportVideoCodecs, UserInfo userInfo);

描述:

用于发射端发起投屏时与接收端协商分辨率、码率、视频流格式;

用户可不重载该接口,基类中默认会返回supportVideoCodecs中的第一个成员作为协商后的视频参数。

参数:

名称描述
supportVideoCodecs一个VideoTrackInfo类型的数组,为发射端所支持的编码格式,期望的分辨率、码率等信息;
userInfo发射端的ip地址,用户名等信息

返回值:

接收端协商出的最终投屏会话的编码格式,分辨率、码率。具体策略由接收端实现。

注意事项:

从bjcast_lib-1.1.19版本开始支持。

用户可不重载该接口,基类中默认会返回supportVideoCodecs中的第一个成员作为协商后的视频参数。

该接口比较复杂,对于业务比较简单的用户不要考虑实现该接口。

具体实现可参考DEMO源代码。

3.4 MediaChannel投屏通道处理接口

描述:

当会话建立成功后,协议栈会调用MediaChannel类中的相应接口回调数据或者获取状态。以下接口需要在MediaChannel子类中实现,客户需要根据自身实际情况实现下列接口。

MediaChannel子类中重要的接口如下,BJCast接收端需要重点关注以下接口。

3.4.1 设置窗口句柄

java
public void setSurface(Surface surface);

描述

设置当前MediaChannel关联的显示相关的Surface,视频将显示到该Surface。该Surface来自用户用于显示视频的view。

参数

surface: 显示相关的Surface,通常来自用户用于显示视频的view。

调用示例

参考Demo中的实现。

3.4.2 音频数据回调接口

java
public abstract void onAudioFrame(byte[] buffer,int len,long ts);

描述

镜像音频数据回调接口,该接口中吐出的是音频AAC编码数据,用户需对音频数据做后续的解码播放处理功能。

音频格式如下,播放器需按照以下格式进行音频的播放。

音频参数
采样率48000
音频格式S16
声道数2
音频编码aac-ld

参数

名称描述
buffer音频数据数组,byte[]类型
len音频数据数据长度
ts时间戳,时间戳单位为1/1000000秒

具体实现可以参考SDK中DEMO源代码。

3.4.3 视频数据回调接口

java
public void onVideoFrame(byte[] buffer,int len,long ts);

描述:

BJCast镜像视频数据接口,该接口中吐出的是H264视频数据,用户需要进行解码并播放。

参数:

名称描述
buffer视频数据数组
len视频数据长度
ts时间戳,单位为1/1000000秒

具体实现可以参考SDK中DEMO源代码。

3.4.4 通知鼠标形状接口

java
public void updateCursorShape(byte[] pngData);

描述:

当鼠标形状变化时,通知新的鼠标形状接口,输入是PNG数据。可以参考demo中的实现将PNG数据解码为Bitmap。

参数

pngData:为鼠标形状的图片信息,为PNG格式。

注意事项

BJCast使用单独的通道来对鼠标信息进行传输,鼠标最高帧率能达到100fps。

3.4.5 通知鼠标位置更新接口

java
public void updateCursorPos(short x,short y);

描述:

该接口通知更新鼠标位置x,y。屏幕左上角坐标为(0,0)。

参数:

名称描述
x鼠标位置横坐标
y鼠标位置纵坐标

注意事项

播放器需要根据实际图像大小和当前屏幕大小换算坐标位置。例如发射端发射的视频图像为720P,坐标位置(1280,720),当前显示的播放器对应的视图为1080P屏幕,则很显然需要将实际鼠标的显示位置换算成(1920,1080),可参考demo中的实际位置计算方法进行换算。

3.4.6 通知隐藏鼠标接口

java
public void hindCursor();

描述:

该接口通知应用需要隐藏鼠标(比如发射端用播放器全屏播放视频时,鼠标会自动消失,此时会通知接收端隐藏鼠标),此时播放器需要将鼠标进行隐藏。当有新的updateCursorPos,或者updateCursorShape消息时鼠标需再次进行显示。

3.4.7 心跳丢失接口

java
public int onLostHeartbeat(int lostHeartbeatTicks);

描述:

该接口通知应用心跳丢失。应用可以根据此接口来做心跳丢失时的处理策略。

如心跳丢失时可以做界面提示,如果心跳丢失超过一定周期门限则通知sdk结束该会话。这种情况常见于网络出现了异常的情况。

参数:

名称描述
lostHeartbeatTicks丢失心跳的周期数

返回值:

返回值含义
1表示需要断开此投屏会话
0表示维持该会话

注意事项

1.0.36版本后支持。

SDK内部默认最大支持15周期的心跳丢失,达到最大周期sdk内部会自动断开投屏。

3.4.8 心跳恢复接口

java
public void onRecoverHeartbeat();

描述:

该接口通知应用心跳恢复。这种情况常见于网络出现了短暂中断又很快恢复的情况。如果在心跳丢失阶段UI做了响应提示,此时界面可以做类似投屏画面恢复这样的提示。

**说明:**1.0.36版本后支持。

3.4.9 重连接口

java
public void onReConnect(MediaChannelInfo info, UserInfo userInfo);

描述:

该接口通知应用意外断开的发射端已重连。

如网络中断后,客户端重新发起了投屏,此时接收端收到onReConnect接口按照新的业务类型处理。接收端原有的播放界面可保持不退出。

参数:

参数含义与reqMediaChannel中的类似。

名称描述
infoMediaChannelInfo类型,表示重连投屏会话的MediaChannel相关接口
userInfo用户自定义信息,投屏设备基本信息

具体实现可以参考SDK中DEMO源代码。

注意事项

从bjcast_lib-1.1.17版本开始支持。

3.4.10 丢包率和码率统计接口

java
public void onMediaStatistics(MediaStatistics videoStatistics,MediaStatistics audioStatistics);

描述:

该接口用于通知当前投屏会话的一些性能指标的统计,包括投屏的音频/视频,丢包率,码率等,用于性能统计和分析。

参数:

名称描述
videoStatistics视频的丢包率,码率统计等
audioStatistics音频的丢包率,码率统计等

具体实现可以参考SDK中DEMO源代码。

注意事项

从bjcast_lib-1.1.17版本开始支持。

3.4.11 重协商接口

java
public MediaChannelInfo mediaNegotiation(MediaChannelInfo channelInfo);

描述: .

当调用3.2.8部分BJCastModule的重协商接口后,该接口会回调。用户使用此接口可实现视频帧率,分辨率和码率的动态重协商。如用户无相关业务场景,不需要关注此接口。

参数:

名称描述
channelInfo客户端发起重协商时期望的channel参数

返回值

返回重协商处理后的MediaChannelInfo值,发射端会按照该协商值的参数进行音视频传输。

注意事项

用户可不重载该接口,基类中默认会返回客户端发送的channelInfo。

从bjcast_lib-1.1.19版本开始支持。

3.5 License授权校验错误码说明

错误码值说明
801输入deviceId 无效
802proGuardSalt输入无效
803proGuardMode输入无效
804服务器返回值为空(请检查网络是否正常)
810获取本地 deviceId 地址失败
811输入的deviceId无法通过验证(请检查本地设备初始化是否正常)
812license 申请结果异常, 请检查网络状态
1001license_check_token校验失败,包名不匹配
1002license_check_token校验失败
1003license_check_pass密码校验失败
1004license_check_token校验失败,非法的校验类型
-101无法获取deviceId
-102无法获取硬件信息
-103检验deviceId失败
-104校验硬件信息失败
-105SDK类型不一致
-106授权(license Key)已过期
-107无法解析license
-108license Key解析错误, 请检查 license 是否读取成功,申请license过程是否出现异常
-109license Key为空
-110平台类型不匹配(SDK用于windows, android平台必须匹配)
-111productId不匹配

4 服务发现

发射端在发起投屏会话到接收端时,首要需要确定接收端的通信IP和通信端口(8190),即可发起投屏。

以下业务场景的用户不需要使用自发现功能,无需关心本章节的内容:

  1. 扫码投屏:将接收端的IP地址定义在二维码中。
  2. 使用投屏码方式投屏:将接收端的IP地址通过投屏码进行转换。

发现协议则用于在局域网内通过搜索自动发现无线投屏系统的接收端设备。

客户应根据自身业务系统的需要选择投屏协议。如客户需通过云平台管理接收端设备,则需考虑自定义无线投屏协议。

当前BJCast SDK统一使用Zeroconf的方式来实现服务发布和服务发现。

4.1 Zeroconf方式

当前BJCast接收端基于mdns使用Zeroconf的方式来实现服务发布。

客户端应用可使用标准的ns-sd接口来发现服务。

4.1.1 服务发布

ServiceName: BJCastReceiver@Name@DeviceID, ServiceName分为3段,每一段使用@符号隔开,第一段固定为BJCastReceiver,第二段为接收端名称(用于描述接收端),第三段为设备ID(用于唯一标识一台设备,当前默认取接收端的MAC地址)。

ServiceType: “_ bjcast2._tcp”

4.1.2 发射端zeroconf服务发现实现方法

当前Android,IOS/MAC平台有标准的API接口支持NSD方式的服务发现。Windows可使用苹果开源的mDNSResponder实现服务发现。

Android平台可使用NsdManager相关接口实现服务的发现,可参考https://developer.android.com/reference/android/net/nsd/NsdManager.html。

IOS/MAC平台可使用Bonjour相关接口实现服务发现。

windows平台可使用Bonjour相关接口实现服务,可参考windows版本的mDNSResponder来实现服务发现功能。可参考https://opensource.apple.com/tarballs/mDNSResponder/。

5 客户如何使用SDK

5.1 混淆规则

Android APP集成该SDK时,混淆规则方面请加入以下规则。

-keepclasseswithmembernames class * {
    native <methods>;
}
-keep class com.bjnet.cbox.module.* { *; }
-keep class com.bjnet.cbox.util.Log { *; }

5.2 集成简要说明

  1. 导入aar,在app目录下新建libs目录并将aar文件放在该目录下,然后在build.gradle(app)中dependencies上方及内部分别添加如下代码:repositories{ flatDir { dirs ’libs ’} },compile (name: ‘bjcast_lib_common-1.1.51-release.aar’, ext: ‘aar’) compile (name: ‘cast_base_lib-1.0.53-release.aar’, ext: ‘aar’),可参考Demo。

  2. 混淆规则请注意按照第5.1节进行设置。

  3. 实现ModuleImpItf接口,参考BJCastModuleImp。reqMediaChannel接口返回自定义的MediaChannel实现类的实例,并启动播放界面。

  4. 实现MediaChannel相关功能接口,参考GLScreenRenderChannel类。

  5. 实现自身的播放界面,可参考view这个package中的view的实现,将播放界面的Surface设置到MediaChannel中。

5.3 Demo简要说明

Demo中BJCastModuleImp实现了ModuleImpItf接口,其中reqMediaChannel中创建了GLScreenRenderChannel,并启动播放相关的View,创建用于播放的Surface。

GLScreenRenderChannel实现了MediaChannel相关功能接口,使用MediaCodec接口对音视频数据进行解码和播放。