Skip to content

当前版本:V1.4

苏州必捷网络有限公司

1 概述

1.1 目的

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

1.2 读者对象

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

1.3 缩略语定义

缩写名称英文中文
DLNADigital Living Network Alliance数字生活网络联盟

2 范围

2.1 功能

本SDK实现了DLNA中MediaRender的角色,以接受来自使用DLNA协议的发射端的投屏请求。

2.2 SDK框架

DLNAReceiver SDK总体分为两层:

  1. cast_base_lib-1.0.53-release.aar:它是一个Android Module,它定义了基础的MediaChannel,Module接口。

  2. bj_dlna_mediarender-1.0.39-release.aar :它是一个Android Module,定义了DlnaMediaRenderModule,以及相关JNI接口。

应用程序应基于bj_dlna_mediarender-1.0.39-release.aar 进行开发。应用程序原则上不应修改cast_base_lib-1.0.53-release.aar,bj_dlna_mediarender-1.0.39-release.aar 中的内容。

2.3 SDK的DEMO实现

DlnaMediaRenderDemo是接收端的一个参考实现,它基于bj_dlna_mediarender-1.0.39-release.aar实现了DLNA接收端功能。

其中DlnaModuleImp实现了ModuleImpItf接口;

DlnaPictureChannel实现了MediaChannel接口,实现了对DLNA图片会话的处理;

DlnaMusicChannel实现了MediaChannel接口,实现了对DLNA音频会话的处理;

DlnaVideoChannel实现了MediaChannel接口,实现了对DLNA视频播放会话的处理。

2.4 SDK交付物

  • SDK库(两个AAR文件)
  • DEMO源代码
  • SDK接口文档

3 接口

接口主要在DlnaModule,ModuleImpItf和MediaChannel中;

用户可以自己实现相关接口, 也可参考我司提供的DEMO源代码实现。

3.1 DlnaModule类中的接口说明

3.1.1 设置客户定制的模块实现类接口

java
public void setImp(ModuleImpItf imp);

描述

设置用户自定义的模块接口实现实例。具体请参考3.2部分的接口。

参数

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

调用示例

请参考Demo部分代码。

3.1.2 初始化接口

java
public boolean init(Context context, Properties props);

描述

DlnaModule类的Init方法初始化DLNA接收端模块。App在启动做初始化时调用。

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

属性名描述必填
DlnaModule.PARA_NAME_DEVICE_NAME接收端名称,DLNA接收端显示的名称。
DlnaModule.PARA_NAME_DEVICE_UUIDDLNA Media Renderer的唯一标识码,该UUID建议持久化保存,不可随意变化。
secretkey或DlnaModule.PARA_NAME_SECRETKEYlicense Key,为使用必捷授权申请库或者申请工具申请的license授权。sdk内部会对此进行授权和校验。
license_check_token由必捷分配,用于初始化SDK的license校验和包名认证,防止被他人盗用。
license_check_pass由必捷分配,用于初始化SDK的license校验密码,防止盗用。
DlnaModule.PARA_NAME_MANUFACTURER厂商名称。
DlnaModule.PARA_NAME_MANUFACTURERURL厂商网址。
DlnaModule.PARA_NAME_MODELDESCRIPTION设备描述。
DlnaModule.PARA_NAME_MODELNAME设备型号。
DlnaModule.PARA_NAME_MODELURL设备网址。

调用示例

java
private void prepareDlnaMediaRender(String deviceName, String secrectKey){
    dlnaMediaRenderModule = DlnaMediaRenderModule.getInstance();
    dlnaMediaRenderModule.setImp(new DlnaModuleImp()); //设置ModuleIm实现实例
    Properties prop = new Properties();
    prop.put(DlnaMediaRenderModule.PARA_NAME_DEVICE_NAME,deviceName+"_MediaRender");
    prop.put(DlnaMediaRenderModule.PARA_NAME_DEVICE_UUID, UtilTool.getInstance().get32UUID());  //此处UUID的生成方法由用户定义,请保证UUID的合法性和唯一性
    
    //设置license校验相关的参数
    paras.setProperty(AirplayModule.PARA_NAME_SECRETE_KEY,secrectKey);
    paras.setProperty("license_check_token",licenseCheckToken); 
    paras.setProperty("license_check_pass",licenseCheckPass);
    
    prop.put(DlnaMediaRenderModule.PARA_NAME_MANUFACTURER, "Bijie Networks Co.,Ltd");
    prop.put(DlnaMediaRenderModule.PARA_NAME_MANUFACTURERURL, "https://www.bijienetworks.com/");
    prop.put(DlnaMediaRenderModule.PARA_NAME_MODELDESCRIPTION, "Bijie Media Renderer Device");
    prop.put(DlnaMediaRenderModule.PARA_NAME_MODELNAME, "Bijie MediaRenderer Device");
    prop.put(DlnaMediaRenderModule.PARA_NAME_MODELURL, "https://www.bijienetworks.com/");
    prop.put(DlnaMediaRenderModule.PARA_NAME_SECRETKEY,secrectKey);


    if (dlnaMediaRenderModule.init(DemoApplication.getContext(),prop) == 0) {
        Log.d(TAG, "dlnaMediaRenderModule init success");
    } else {
        Log.d(TAG, "dlnaMediaRenderModule init failed");
    }
}

返回值

0表示成功,其它表示初始化失败。

返回值含义
0成功
-1初始化失败,常见为端口冲突。比如已经运行了某支持DLNA的投屏软件。
其它license授权错误码license授权相关的失败错误码请参考3.4节。

注意事项:

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

3.1.3 去初始化接口

java
public native void fini();

描述

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

3.1.4 与发射端交互的接口

以下接口主要用于和发射端进行音视频播放的进度同步:

3.1.4.1 接收端通知发射端准备播放接口

java
public void setTranstionEvent(MediaChannel channel);

描述

接收端正在准备播放音视频时调用,用于通知发射端播放器进行状态更新。此时播放器还处于初始化加载状态。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。

调用示例

java
case DlnaEvent_SetState:{
    int state = msg.arg1;
    if (state == PlayerState.PLAYER_STATE_PREPARING.getValue()){   
        DlnaMediaRenderModule.getInstance().setTranstionEvent(channel);  //播放器处于加载状态
    }else if (state == PlayerState.PLAYER_STATE_STARTED.getValue()){
        DlnaMediaRenderModule.getInstance().setPlayStateEvent(channel); //播放器处于播放状态
    }else if (state == PlayerState.PLAYER_STATE_PAUSED.getValue()){ 
        DlnaMediaRenderModule.getInstance().setPauseStateEvent(channel);//播放器处于暂停状态
    }else if (state == PlayerState.PLAYER_STATE_RELEASED.getValue()
            || state == PlayerState.PLAYER_STATE_COMPLETED.getValue()
            || state == PlayerState.PLAYER_STATE_ERROR.getValue()){ //播放器处于停止状态
        DlnaMediaRenderModule.getInstance().setPositionEvent(channel, 0);  状态
        DlnaMediaRenderModule.getInstance().setStopStateEvent(channel);
    }

    break;
}

3.1.4.2 接收端通知发射端准备完成接口

java
public void sendDurationEvent(MediaChannel channel, int duration);

描述

接收端音视频播放准备完成时调用,用于通知发射端播放器的进度条总时长更新。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。
duration当前视频资源的总的播放时长,单位为毫秒。

3.1.4.3 接收端通知发射端播放进度更新接口

java
public void setPositionEvent(MediaChannel channel, int position);

描述

接收端音视频播放过程中调用,用于通知发射端播放器进行播放进度更新。

此结口需播放器定时调用以通知发射端当前播放位置。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。
position当前播放位置,单位为毫秒。

3.1.4.4 接收端通知发射端播放接口

java
public void setPlayStateEvent(MediaChannel channel);

描述

接收端音视频开始播放时调用,用于通知发射端播放器进行状态更新。

此结口需播放器定时调用以通知发射端当前播放位置。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。

调用示例

java
case DlnaEvent_SetState:{
    int state = msg.arg1;
    if (state == PlayerState.PLAYER_STATE_PREPARING.getValue()){   
        DlnaMediaRenderModule.getInstance().setTranstionEvent(channel);  //播放器处于加载状态
    }else if (state == PlayerState.PLAYER_STATE_STARTED.getValue()){
        DlnaMediaRenderModule.getInstance().setPlayStateEvent(channel); //播放器处于播放状态
    }else if (state == PlayerState.PLAYER_STATE_PAUSED.getValue()){ 
        DlnaMediaRenderModule.getInstance().setPauseStateEvent(channel);//播放器处于暂停状态
    }else if (state == PlayerState.PLAYER_STATE_RELEASED.getValue()
            || state == PlayerState.PLAYER_STATE_COMPLETED.getValue()
            || state == PlayerState.PLAYER_STATE_ERROR.getValue()){ //播放器处于停止状态
        DlnaMediaRenderModule.getInstance().setPositionEvent(channel, 0);  状态
        DlnaMediaRenderModule.getInstance().setStopStateEvent(channel);
    }

    break;
}

3.1.4.5 接收端通知发射端暂停播放接口

java
public void setPauseStateEvent(MediaChannel channel);

描述

接收端音视频暂停播放时调用,用于通知发射端播放器进行状态更新。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。

调用示例

java
case DlnaEvent_SetState:{
    int state = msg.arg1;
    if (state == PlayerState.PLAYER_STATE_PREPARING.getValue()){   
        DlnaMediaRenderModule.getInstance().setTranstionEvent(channel);  //播放器处于加载状态
    }else if (state == PlayerState.PLAYER_STATE_STARTED.getValue()){
        DlnaMediaRenderModule.getInstance().setPlayStateEvent(channel); //播放器处于播放状态
    }else if (state == PlayerState.PLAYER_STATE_PAUSED.getValue()){ 
        DlnaMediaRenderModule.getInstance().setPauseStateEvent(channel);//播放器处于暂停状态
    }else if (state == PlayerState.PLAYER_STATE_RELEASED.getValue()
            || state == PlayerState.PLAYER_STATE_COMPLETED.getValue()
            || state == PlayerState.PLAYER_STATE_ERROR.getValue()){ //播放器处于停止状态
        DlnaMediaRenderModule.getInstance().setPositionEvent(channel, 0);  状态
        DlnaMediaRenderModule.getInstance().setStopStateEvent(channel);
    }

    break;
}

3.1.4.6 接收端通知发射端停止播放接口

java
public void setStopStateEvent(MediaChannel channel);

描述

接收端音视频停止播放时调用,用于通知发射端播放器进行状态更新。

参数

名称描述
channel3.2.1节reqMediaChannel接口返回的MediaChannel实例,表示当前投屏会话。

调用示例

java
case DlnaEvent_SetState:{
    int state = msg.arg1;
    if (state == PlayerState.PLAYER_STATE_PREPARING.getValue()){   
        DlnaMediaRenderModule.getInstance().setTranstionEvent(channel);  //播放器处于加载状态
    }else if (state == PlayerState.PLAYER_STATE_STARTED.getValue()){
        DlnaMediaRenderModule.getInstance().setPlayStateEvent(channel); //播放器处于播放状态
    }else if (state == PlayerState.PLAYER_STATE_PAUSED.getValue()){ 
        DlnaMediaRenderModule.getInstance().setPauseStateEvent(channel);//播放器处于暂停状态
    }else if (state == PlayerState.PLAYER_STATE_RELEASED.getValue()
            || state == PlayerState.PLAYER_STATE_COMPLETED.getValue()
            || state == PlayerState.PLAYER_STATE_ERROR.getValue()){ //播放器处于停止状态
        DlnaMediaRenderModule.getInstance().setPositionEvent(channel, 0);  状态
        DlnaMediaRenderModule.getInstance().setStopStateEvent(channel);
    }

    break;
}

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

3.1.5 禁用DLNA功能

java
public  void disable()

描述

通过该接口可对已经初始化好的模块临时禁用。适用于某些业务场景需要临时关闭/打开DLNA的功能。

禁用后,DLNA信号不能被发现,无法投屏。

3.1.6 启用DLNA功能

java
public  void enable()

描述

通过该接口可对已经调用3.1.5的模块临时禁用后再次启用的情况。适用于某些业务场景需要临时关闭/打开DLNA的功能。

3.2 ModuleImpItf接口说明

ModuleImpItf定义了一个接口类,需要用户去实现这些接口。

3.2.1 会话接入接口

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

描述

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

参数

名称描述
channelInfo当前会话的类型信息。
userInfo发射端的IP,设备型号,设备名称等信息。

返回值

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

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

调用示例

更详细的细节请参考demo源码中的处理。

java
@Override
public MediaChannel reqMediaChannel(MediaChannelInfo mediaChannelInfo, UserInfo userInfo) {
    MediaChannel channel = null;
    synchronized (this) {
        /**
         * 根据不同的ChannelPlayType,创建不同的channel
         */
        Log.d(TAG, "reqMediaChannel: " + mediaChannelInfo.getChannelPlayType());
        switch (mediaChannelInfo.getChannelPlayType()) {

            case MediaConst.MEDIA_TYPE_DLNA_VIDEO:  //投视频类型(视频软件的投Tv)
                channel = new DlnaVideoChannel(mediaChannelInfo);
                break;
            case MediaConst.MEDIA_TYPE_DLNA_PICTURE: //投图片类型
                channel = new DlnaPictureChannel(mediaChannelInfo);
                break;
            case MediaConst.MEDIA_TYPE_DLNA_AUDIO:  //投纯音乐类型
                channel = new DlnaMusicChannel(mediaChannelInfo);
                    break;
            default: {
                Log.e(TAG, "reqMediaChannel failed,because info.getChannelPlayType() invalid:" + mediaChannelInfo.getChannelPlayType());
                return null;
            }
        }
    }

    //初始化channel并分配唯一性的channal ID
    if (!openAndStartChannel(channel)) {
        Log.e(TAG, "reqMediaChannel failed,because openAndStartChannel failed.");
        return null;
    }

    //根据不同的业务类型创建不同的view
    switch (mediaChannelInfo.getChannelPlayType()) {
        case MediaConst.MEDIA_TYPE_DLNA_VIDEO: {
            DemoApplication.APP.getEventBus().post(new DlnaVideoChannelEvent(channel));
        }
        break;
        case MediaConst.MEDIA_TYPE_DLNA_PICTURE: {
            DemoApplication.APP.getEventBus().post(new DlnaPicChannelEvent(channel));
        }
        break;
        case MediaConst.MEDIA_TYPE_DLNA_AUDIO:
            DemoApplication.APP.getEventBus().post(new DlnaMusicChannelEvent(channel));
        default:
            break;
    }
    return channel;
}

3.2.2 会话结束接口

java
public void relMediaChannel(MediaChannel channel);

描述

回调接口, 当底层收到会话结束时调用.应用层实现相关逻辑。

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

3.3 MediaChannel会话处理接口

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

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

3.3.1 设置窗口句柄

java
public void setSurface(Surface surface);

描述

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

参数

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

调用示例

参考Demo中的实现。

3.3.2 音量控制接口

3.3.2.1 设置音量接口

java
public void setVolume(int volume);

描述

设置音量。用户一般在视频投屏后通过调节手机音量或者应用内音量调节按钮控制音量。

参数

名称描述
volume取值范围为0-100。0表示静音,100表示音量为最高。

3.3.2.2 设置静音接口

java
public void setVolumeMute();

描述

设置静音后播放器应进行静音处理。

调用示例

参考Demo中的实现。

3.3.2.3 取消静音接口

java
Public void setVolumeUnmute();

描述

取消静音。

以上接口涉及DLNA音频投屏会话和视频投屏会话。参考Demo中的实现。

3.3.3 音视频播放控制相关接口

3.3.3.1 暂停接口

java
public void pause();

描述

该接口通知播放器暂停视频播放。

通知播放器暂停播放,通常可由发射端触发;也可由接收端界面上用户进行暂停操作触发。

此时需要调用3.1.4.5 接收端通知发射端暂停播放接口通知发射端状态。

调用示例

请参考demo代码中DlnaVideoChannel类和DLNAMediaPlayerEngine类中的实现。

3.3.3.2 播放接口

java
public void play();

描述

该接口通知播放器开始或继续视频播放。

调用示例

请参考demo代码中DlnaVideoChannel类和DLNAMediaPlayerEngine类中的实现。

3.3.3.3 拖动进度条接口

java
public void seek(int sec);

描述

通知播放器进度条拖放到的位置。单位为秒。

参数

名称描述
sec播放器进度条的位置,单位为秒

调用示例

请参考demo代码中DlnaVideoChannel类和DLNAMediaPlayerEngine类中的实现。

3.3.3.4 获取播放到的当前位置的接口

java
public int getPts();

描述

SDK回调接口,SDK获取当前播放器当前播放到的位置。单位为毫秒。

该接口涉及视频投屏播放场景。

返回值

当前播放器当前播放到的位置。单位为毫秒。

调用示例

请参考demo代码中DlnaVideoChannel类和DLNAMediaPlayerEngine类中的实现。

3.3.3.5 获取视频URL时长的接口

java
public int getDuation();

描述

SDK回调接口,SDK获取当前播放器播放的视频URL的总时长。单位为毫秒。

以上接口涉及DLNA音视频投屏播放场景。

返回值

当前播放的视频URL的时长。单位为毫秒。

调用示例

请参考demo代码中DlnaVideoChannel类和DLNAMediaPlayerEngine类中的实现。

3.3.4 图片显示接口

java
public void showPicture(String pic);

描述

该接口涉及图片投屏播放场景。

SDK回调接口,通过该接口通知应用显示图片。

参数

名称描述
pic显示图片的路径

调用示例

请参考demo代码中DlnaPictureChannel类中的实现。

3.3.5 音视频详细信息接口

MediaModel包含作者、标题、所属专辑以及专辑封面信息,该对象可通过MediaChannelInfo的getMediaModel()方法获取,而MediaChannelInfo可以通过MediaChannel的getMediaInfo()方法获取,即MediaModle model = MediaChannel.getMediaInfo().getMediaModel()。需要注意该功能需要发射端播放器支持。

标题名称可通过MediaModle的getTitle()获得;

作者名字可通过MediaModle的getArtist()获得;

专辑名称可通过MediaModle的getAlbum()获得;

专辑封面图可通过MediaModle的getAlbumUri()获得。

3.4 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 用户如何使用SDK

4.1 混淆规则

用户APP如启用混淆,则需加入以下混淆规则,保证用户的使用。

java
-keep class com.bjnet.dlna.mediarender.DlnaMediaRenderModule { *; }

-keepclasseswithmembernames class * {
    native <methods>;
}

-keep class com.bjnet.dlna.mediarender.DlnaBJReflection { *; }
-keep class com.bjnet.dlna.mediarender.DlnaMediaRenderEgine { *; }

-keep class com.bjnet.cbox.module.* { *; }
-keep class com.bjnet.cbox.util.Log { *; }

4.2 集成简要说明

  1. 导入aar,在app目录下新建libs目录并将aar文件放在该目录下,然后在build.gradle(app)中dependencies上方及内部分别添加如下代码:repositories{ flatDir { dirs ’libs ’} },compile (name: ‘bj_dlna_mediarender-1.0.39-release.aar’, ext: ‘aar’) compile (name: ‘cast_base_lib-1.0.53-release.aar’, ext: ‘aar’),可参考Demo。
  2. 实现ModuleImpItf接口,参考DlnaModuleImp。reqMediaChannel接口返回自定义的MediaChannel实现类的实例,并启动播放界面。
  3. 实现MediaChannel相关功能接口,参考DlnaPictureChannel, DlnaVideoChannel, DlnaMusicChannel。实现自身的播放界面,可参考这个package中的view的实现,将播放界面的Surface设置到MediaChannel中。
  4. 混淆规则请按照4.1节设置。

4.3 Demo简要说明

Demo中DlnaModuleImp实现了ModuleImpItf接口,实现了relMediaChannel方法,此处可以控制是否接入某个会话的逻辑控制。

其中reqMediaChannel中创建了与会话类型对应的MediaChannel实现,并启动播放相关的View,创建用于播放的Surface。

DlnaPictureChannel, DlnaVideoChannel, DlnaMusicChannel分别对应DLNA图片投屏,视频投屏,纯音频播放这几种业务类型,实现了MediaChannel中相关功能接口。