# 关于如何接入SDK直播功能

本文主要介绍如何接入SDK直播功能，包括两大部分，核心功能和其他功能

- 关于如何接入SDK直播功能

  - 1. 直播核心功能

    - 1.1直播登录

      - 1.1.1 主动调用api
      - 1.1.2 回调事件api
      - 1.1.3 关键代码示例

    - 1.2 直播播放视频和文档

      - 1.2.1主动调用api
      - 1.2.2 回调事件api
      - 1.2.3 关键代码示例
      - 1.2.4 集成说明

  - 2. 直播其他功能

    - 2.1 聊天功能
    - 2.2 问答功能
    - 2.3 签到功能
    - 2.4 抽奖1.0
    - 2.5 抽奖2.0
    - 2.6 公告功能
    - 2.7 问卷功能
    - 2.8 广播功能
    - 2.9 答题卡功能（投票功能）
    - 2.10 随堂测功能
    - 2.11 连麦功能
    - 2.12 音频模式（Deprecated 2021-10-08）
    - 2.13 获取在线人数
    - 2.14 用户踢出
    - 2.15 打卡
    - 2.16 上下课逻辑
    - 2.17 历史文档数据
    - 2.18 线路切换（Deprecated 2021-10-08）
    - 2.19 清晰度切换
    - 2.20 线路切换
    - 2.21 音视频播放模式切换

## 1. 直播核心功能

### 1.1直播登录

#### 1.1.1 主动调用api

直播登录需要主动调用方法在DWLive.java（DWLive为单例）中，如下

方法 | 说明
--- | ---
getInstance() | 获取DWLive单例
setDWLiveLoginParams(DWLiveLoginListener, LoginInfo) | （过时）设置直播间登录参数
startLogin() | （过时）开始登录
startLogin(LoginInfo, DWLiveLoginListener) | （>=3.14.0）设置参数并执行登录

登录所需参数LoginInfo参数如下

    xxxxxxxxxx// 用户ID   private String userId;   // 直播间ID   private String roomId;       // 观众名称  private String viewerName;    // 观众密码    private String viewerToken;   // 观众UA Type 信息 (选填) -- 主要是为了用户做统计使用，对登录无影响                      private String viewerCustomUa;// 自定义观众信息（选填）-- 该信息会记录在用户访问记录中，用于统计分析使用                       private String viewerCustomInfo; // 分组ID (选填)  用于聊天分组功能private String groupId;

#### 1.1.2 回调事件api

DWLiveLoginListener

方法 | 说明
--- | ---
onLogin(TemplateInfo info, Viewer viewer, RoomInfo roomInfo, PublishInfo publishInfo) | 登录成功回调
onException(DWLiveException exception); | 登录失败回调

回调返回参数说明

TemplateInfo 模版信息 参数如下

    xxxxxxxxxx// 直播间模版类型 1-6 对应后台配置：直播间模板配置private String type;// 模版名称private String name;   // 模版描述private String description;                  // 是否开课，"1"为开课 "0"为未开课                                                           private String status;

Viewer 用户信息 参数如下

    xxxxxxxxxx// 用户名private String name;       // 用户keyprivate String key;   // 用户唯一Idprivate String id;        // 分组Idprivate String groupId;

RoomInfo 房间信息 参数如下

    xxxxxxxxxx    //直播间Id    private String id;    //直播间名称    private String name;    //直播间描述    private String desc;    //直播间设置的最大回看时间    private int dvr;    //直播间设定的延迟时间 (单位：毫秒) 当延迟为0的时候，表示该房间为低延迟直播间    private int delayTime;    //极速文档展示模式 ：1——适合窗口，2——适合宽度    private int documentDisplayMode = 1;    //当前直播间是否封禁  0——未封禁，1——封禁 （直播观看专用）    private int isBan;    //是否展示直播间人数 （对应后台设置：显示在线人数），1——展示 ，0——不展示    private int showUserCount;    //多清晰度支持 0 为不支持 1 为支持    private int multiQuality;    //弹幕功能    0：关闭；1：开启    private int barrage;    //跑马灯功能  0：关闭；1：开启    private int openMarquee;    //倒计时功能  0：关闭；1：开启    private int openLiveCountdown;    //私聊开关，1开启，（默认开启），0：关闭    private String privateChat = "1";    //倒计时功能 还剩多久开始直播 单位：秒    private int liveCountdown;    //直播开始时间    private String estimateStartTime;    //回放的标题和简介    private BaseRecordInfo baseRecordInfo;    //播放器提示语    private String playerBackgroundHint;    //播放器背景图    private String playerBackgroundImageUri;

#### 1.1.3 关键代码示例

登录调用代码示例如下：

    xxxxxxxxxx...// 1.构造回调参数DWLiveLoginListener dwLiveListener = new DWLiveLoginListener() {                             @Override                                                                                 public void onLogin(TemplateInfo templateInfo, Viewer viewer, RoomInfo roomInfo, PublishInfo publishInfo) {              //TODO 登录成功了，跳转到直播播放页面                                                     }                                                                                         @Override                                                                                 public void onException(final DWLiveException e) {        // TODO 登录失败，添加告知用户登录失败的逻辑     }                                                                                     };// 2.构造登录参数LoginInfo loginInfo = new LoginInfo();                   loginInfo.setRoomId("房间ID"); loginInfo.setUserId("用户ID");                 loginInfo.setViewerName("用户名");                  loginInfo.setViewerToken("密码");                                    // 3.设置登录参数并登录DWLive.getInstance().startLogin(LiveLoginListener,loginInfo);  ...

### 1.2 直播播放视频和文档

#### 1.2.1主动调用api

直播核心类代码在DWLive.java类中（DWLive为单例）调用直播视频播放代码如下

方法 | 说明
--- | ---
setDWLivePlayParams(DWLiveListener dwLiveListener, Context context) | 设置回调和上下文
setDWLivePlayer(DWLivePlayer player) | 设置播放器
setDWLivePlayDocView(DocView docView) | 设置文档
start(Surface surface) | 开始播放，同步
start() | 开始播放，player需设置Surface
pause() | 暂停播放器
stop() | 停止播放
onDestroy() | 释放资源
restartVideo() | 重置播放器，不重新获取播放地址
reloadVideo() | 重置播放器，重新获取播放地址

直播DWLive文档自由翻页方法

方法 | 说明
--- | ---
changeDocModeType(DocModeType docModeType) | 切换自由翻页模式和跟随模式（默认）
changePageTo(String docId, int pageIndex) | 手动翻页

直播DWLive其他业务方法

方法 | 说明
--- | ---
setVolume(float left, float right) | 设置播放声音大小
changeQuality(int quality, LiveChangeSourceListener changeCallBack) | （>=3.14.0）切换视频清晰度
changeLine(int lineIndex, LiveChangeSourceListener changeCallBack) | （>=3.14.0）切换媒体源线路
changePlayMode(LivePlayMode playMode, LiveChangeSourceListener changeCallBack) | （>=3.14.0）切换播放模式
setDocScaleType(DocView.ScaleType type) | 设置文档缩放模式
changeDocBackgroundColor(String color) | 设置文档背景颜色

播放器核心代码在DWLivePlayer.java类中，调用方法如下

方法 | 说明
--- | ---
DWLivePlayer(Context context) | 构造方法
setSurface(Surface surface) | 设置Surface
start() | 开始播放
pause() | 暂停播放
stop() | 停止播放
reset() | 重置播放器
release() | 释放
setPlayerEventListener(PlayerEvent playerEvent) | （>=3.14.0）设置播放器监听
setAntiRecordScreen(Activity activity) | （>=3.14.0）设置防录屏
setOnPreparedListener(OnPreparedListener listener) | （过时）设置准备回调
setOnErrorListener(IMediaPlayer.OnErrorListener listener) | （过时）设置失败回调
setOnInfoListener(OnInfoListener listener) | （过时）设置播放状态信息回调
setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) | （过时）设置视频尺寸信息回调
setSpeedListener(LiveSpeedListener speedListener) | （过时）设置视频缓冲的网速

#### 1.2.2 播放器回调事件api

PlayerEvent回调事件如下

方法 | 说明
--- | ---
onPrepared() | 播放器初始化完成
onInfo(int what, int extra) | 播放器状态信息
onVideoSizeChanged(int width, int height) | 播放器尺寸信息
onBufferSpeed(float speed) | 媒体流网速
onError(int code, DWLiveException exception) | 播放器失败信息

onInfo播放器状态信息的回调

1. 缓冲开始

what = IMediaPlayer.MEDIA_INFO_BUFFERING_START

2. 缓冲结束

what = IMediaPlayer.MEDIA_INFO_BUFFERING_END

3. 开始渲染

what = IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START

#### 1.2.3 关键代码示例

设置播放器显示布局：

    xxxxxxxxxx<TextureView    android:id="@+id/video_view"    android:layout_width="match_parent"    android:layout_height="match_parent" />

设置文档展示的控件布局：

    xxxxxxxxxx<com.bokecc.sdk.mobile.live.widget.DocView    android:id="@+id/doc_view"    android:layout_width="match_parent"    android:layout_height="match_parent" />

初始化播放器并设置播放参数

    xxxxxxxxxx...DWLive dwLive;TextureView video_view;DocView doc_view;Surface mSurface;DWLivePlayer mPlayer;         ... mPlayer = new DWLivePlayer(this);   // 1. 设置Surface的回调 video_view.setSurfaceTextureListener(surfaceListener); // 2. 获取单例 dwLive = DWLive.getInstance(); // 3. 设置播放器回调 mPlayer.setPlayerEventListener(playerEvent);   // 4. 设置直播回调和上下文                                                                      dwLive.setDWLivePlayParams(dwLiveListener, DWLiveEngine.getInstance().getContext());  // 5. 设置播放器 dwLive.setDWLivePlayer(mPlayer);                                                         ...

获取Surface

下面是通过实现SurfaceTextureListener回调获得

    xxxxxxxxxxprivate SurfaceTexture mSurfaceTexture;@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {   // 设置Surface  if (mSurfaceTexture != null) {                               mVideoContainer.setSurfaceTexture(mSurfaceTexture);  } else {                                                     mSurfaceTexture = surfaceTexture;                        mSurface = new Surface(surfaceTexture);         // 将surface设置给播放器      mPlayer.setSurface(mSurface);                         }                                                      }
    @Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {    surface = null;    return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}

调用播放视频和文档方法

    xxxxxxxxxx//设置并播放文档                                    dwLive.setDWLivePlayDocView(doc_view);//播放视频dwLive.start(mSurface);

#### 1.2.4 集成说明

完成上面的步骤后，我们就能够观看到直播间的视频画面和文档画面了，也就基本完成了获得视频直播的核心功能的集成，即观看视频和观看文档的功能。

## 2. 直播其他功能

### 2.1 聊天功能

聊天历史记录回调在DWLiveListener类，相关方法如下：

方法 | 说明
--- | ---
onHistoryChatMessage(ArrayList chatLogs) | 历史聊天信息

注意该api可能会存在多次回调，回调情况如下:

- 首次进入直播间并调用start()开启直播回调
- 网络切换会回调
- 弱网造成直播尝试重连的情况会回调

聊天功能分为公共聊天和私聊，聊天时主动调用的方法在DWLive类，相关方法如下：

方法 | 说明
--- | ---
DWLive.sendPublicChatMsg(String publicChatMsg) | 发送公聊
DWLive.sendPrivateChatMsg(String toUserId, String msg) | 发送私聊

聊天功能的核心回调类为DWLiveListener，相关的回调方法如下：

接收公共聊天对应的回调方法为：自己发的公共聊天数据和别人的公共聊天数据都是通过此接口回调回来。

方法 | 说明
--- | ---
onPublicChatMessage(ChatMessage msg) | 接收公共聊天消息

返回的实体类ChatMessage 属性如下

    xxxxxxxxxxpublic class ChatMessage { //聊天消息的id, 该参数有可能为空(只有开启⼈⼯审核功能,同时⽤户角⾊为学员时,此字段才会有数据) private String chatId; //发送者用户id private String userId; //发送者的用户名 private String userName; //聊天内容 private String message; //聊天时间 private String currentTime; //是否是公聊 private boolean isPublic; //发送者的头像 private String avatar; //发送者的角色 private String userRole; // 用户自定义标记(用于客户自定义一些属性) 默认为空字符串 private String userCustomMark;  //聊天分组id private String groupId; //聊天消息的状态 0 显示 1 不显示 private String status;}

接收别人私聊我的方法和接收我私聊别人的回调方法是两个方法，如下

方法 | 说明
--- | ---
onPrivateChat(PrivateChatInfo info) | 接收别人发我的消息
onPrivateChatSelf(PrivateChatInfo info) | 接收我发给别人的消息

返回的实体类PrivateChatInfo 属性如下

    xxxxxxxxxx public class PrivateChatInfo {    //发送者的userid    private String fromUserId;    //发送者的名字    private String fromUserName;    //发送者的角色    private String fromUserRole;    //发送者的头像    private String formUserAvatar;    //接受者的userid    private String toUserId;    //接受者的名字    private String toUserName;    //消息内容    private String msg;    //发送时间    private String time;   }

- 自己被禁言后，发出的聊天数据会从onSilenceUserChatMessage(ChatMessage msg)方法回调回来，而不会通过onPublicChatMessage(ChatMessage msg)回调。
- 客户端禁止聊天后，发出的聊天数据不会回调，会通过onInformation方法回调内容为：讲师暂停了文字聊天，请专心看直播吧。

### 2.2 问答功能

问答历史记录回调在DWLiveListener类，，相关方法如下：

方法 | 说明
--- | ---
onHistoryQuestionAnswer(List questions, List answers) | 问答历史记录回调

注意该api可能会存在多次回调，回调情况如下:

- 首次进入直播间并调用start()开启直播回调
- 网络切换会回调
- 弱网造成直播尝试重连的情况会回调

提问时主动调用的方法在DWLive类，相关方法如下：

方法 | 说明
--- | ---
DWLive.sendQuestionMsg(String question) | 发送问题

问答功能的核心回调类为DWLiveListener，相关的回调方法如下：

方法 | 说明
--- | ---
onQuestion(Question question) | 接收问题的回调
onPublishQuestion(String questionId) | 接收问题发布的ID的回调
onAnswer(Answer answer) | 接收回答的回调

返回的实体类Question属性如下

    xxxxxxxxxx public class Question {    //问答的id    private String id;    //问答的内容    private String content;    //发布问答的userid    private String questionUserId;    //发布问答的username    private String questionUserName;    //问答的时间    private String time;    //发布问答的头像    private String userAvatar;    //分组id    private String groupId;    //是否是公开的    private int isPublish;   }

返回的实体类属性如下

    xxxxxxxxxx public class Answer {    //问答的id  private String questionId;    //回答的内容    private String content;    //回答的用户id    private String answerUserId;    //回答的用户名    private String answerUserName;    //收到的时间    private String receiveTime;    //是否公开    private int isPrivate;    //回答的头像    private String userAvatar;    //回答的角色    private String userRole;    //分组id    private String groupId;   }

### 2.3 签到功能

签到时主动调用的方法在DWLive类，相关方法如下：

方法 | 说明
--- | ---
DWLive.sendRollCall() | 发送签到

签到功能的核心回调类为DWLiveListener，相关的回调方法如下：

方法 | 说明
--- | ---
onRollCall(int duration) | 收到签到事件的回调，duration 签到持续时间，单位为秒

### 2.4 抽奖1.0

此功能为方法回调功能，相关类DWLiveListener，相关方法如下：

方法 | 说明
--- | ---
onStartLottery(String lotteryId) | 收到开始抽奖事件开始的回调
onLotteryResult(boolean isWin, String lotteryCode, String lotteryId, String winnerName); | 收到抽奖结果事件的回调
onStopLottery(String lotteryId) | 收到结束抽奖事件的回调

    xxxxxxxxxx /**     * 开始抽奖     *     * @param lotteryId 本次抽奖的id     */public void onStartLottery(String lotteryId);

    xxxxxxxxxx /**     * 抽奖结果     *     * @param isWin       是否中奖，true表示中奖了     * @param lotteryCode 中奖码     * @param lotteryId   本次抽奖的id     * @param winnerName  中奖者的名字     */    public void onLotteryResult(boolean isWin, String lotteryCode, String lotteryId, String winnerName);

    xxxxxxxxxx /**     * 结束抽奖     *     * @param lotteryId 本次抽奖的id     */    public void onStopLottery(String lotteryId);

### 2.5 抽奖2.0

此功能需要主动获取和监听回调，首次进入需要主动获取抽奖，随后的抽奖需要去监听回调 ，相关类DWLiveListener、DWLive，相关方法如下： 进入直播间前可设置是否去重 默认为true：

方法 | 说明
--- | ---
DWLive.getInstance().setLotteryRepetition(boolean isRepetition ) | 是否sdk内部进行去重

首次进入直播间主动获取抽奖 调用时机在sdk初始化完成之后:

方法 | 说明
--- | ---
DWLive.getInstance().queryLotteryStatus() | 查询当前正在进行的抽奖

收到抽奖的回调 相关类DWLiveListener：

    xxxxxxxxxx   /**     * 收到抽奖     * @param lotteryAction 抽奖的一些信息     */    void onLottery(LotteryAction lotteryAction);

提交抽奖 相关类DWLive：

    xxxxxxxxxx   /**     * 提交抽奖信息     *     * @param commitInfos 提交的信息     * @param lotteryId   抽奖id     * @param callback    提交回调      *                                    -2：切换时间间隔小于3s     *                                    -1：切换的线路不正确     *                                    0 ：切换成功     */    public void commitLottery(final List<LotteryCommitInfo> commitInfos, final String lotteryId, final BaseCallback<String> callback)

相关的参数:

    xxxxxxxxxxpublic class LotteryCommitInfo {    //收到中奖信息中对应的 LotteryCollectTemplate.index    private int index;    //用户填写的信息    private String value;}public class LotteryAction {    //抽奖订单ID    private String lotteryId;    //抽奖订单状态   0抽奖创建成功， 1抽奖取消成功， 2抽奖已完成， 3抽奖异常结束    private int lotteryStatus;    //抽奖订单类型   0普通抽奖类型（暂无别的抽奖类型）    private int lotteryType;    //是否存在抽奖  注意当该字段为false的时候 存在其他字段无数据    private boolean haveLottery;    //中奖信息    private  LotteryWinInfo lotteryWinInfo;}public class LotteryWinInfo {    //中奖人需要提交的信息    private List<LotteryCollectTemplate> collectTemplate;    //是否中奖  true中奖  false未中奖    private boolean isWinner;    //自己的信息    private LotteryOwnUserInfo ownUserInfo;    //中奖人名单信息    private List<LotteryUserInfo> userInfos;    //奖品信息    private LotteryPrize prize;}public class LotteryCollectTemplate {    //索引 提交抽奖的时候用到    private int index;    //标题    private String title;    //提示语    private String tips;}public class LotteryOwnUserInfo {    //头像    private String userAvatar;    //名称    private String userName;    //用户id    private String userId;    //中奖码    private String prizeCode;}public class LotteryUserInfo {    //头像    private String userAvatar;    //用户名    private String userName;    //用户id    private String userId;}public class LotteryPrize {    //奖品名称    private String name;}

### 2.6 公告功能

此功能需要主动获取和监听回调，首次进入需要主动获取公告，随后的公告需要去监听回调 ，相关类DWLiveListener、DWLive，相关方法如下： 首次进入直播间主动获取公告:

方法 | 说明
--- | ---
DWLive.getInstance().getAnnouncement() | 获取公告
收到公告的回调： |

    xxxxxxxxxx /**     * 公告     * @param isRemove     是否是公告删除，如果为true，表示公告删除且announcement参数为null     * @param announcement 公告内容     */    public void onAnnouncement(boolean isRemove, String announcement);

### 2.7 问卷功能

问卷功能主要为方法回调功能，相关类DWLiveListener，相关方法如下：

- 收到问卷发布的回调：

    xxxxxxxxxx /**     * 发布问卷     *     * @param info 问卷内容     */    public void onQuestionnairePublish(QuestionnaireInfo info);    //参数说明    public class QuestionnaireInfo {       private String id;  // 问卷ID       private String title; // 问卷标题       private int submitedAction; // 提交后的操作，非必须，默认为0，0：关闭，1：提交后显示答案       private ArrayList<Subject> subjects; // 问卷题目       private int forcibly;  // 强制答卷   }

- 收到停止问卷的回调：

    xxxxxxxxxx   /**     * 停止问卷     *     * @param questionnaireId 问卷Id     */    public void onQuestionnaireStop(String questionnaireId);

- 收到第三方问卷发布的回调：

    xxxxxxxxxx   /**     * 发布第三方问卷     *     * @param title 问卷标题     * @param externalUrl 第三方问卷链接     */    public void onExeternalQuestionnairePublish(String title, String externalUrl);

- 收到问卷统计信息的回调：

    xxxxxxxxxx   /**     * 问卷统计信息     */    public void onQuestionnaireStatis(QuestionnaireStatisInfo info);    //参数    public class QuestionnaireStatisInfo {       private String id;  // 问卷ID       private String title; // 问卷标题       private int submitAnswerViewerCount; // 提交答案的观众的数量       private ArrayList<Subject> subjects; // 问卷题目    }

同时提供了主动获取当前正在进行问卷的方法：

- 主动获取问卷的方法：fetchQuestionnaire()。调用获取当前问卷的方法后，如果有正在进行的问卷，就会触发收到问卷发布回调方法onQuestionnairePublish。

### 2.8 广播功能

此功能为方法回调功能，相关类DWLiveListener，相关方法如下：

- 收到广播消息的回调：

    xxxxxxxxxx/** * 收到广播信息（实时） * * @param msg 广播消息 */void onBroadcastMsg(String msg);
    /**                                                         * 收到广播信息（实时）                                               *                                                          * @param msg 广播消息 包含id                                     */                                                                                                       void onBroadcastMsg(BroadCastMsg msg)；

- 收到历史广播消息的回调：

    xxxxxxxxxx /**                                                                * 收到历史广播信息(目前服务端只返回最后一条历史广播)                                      *                                                                 * @param msgs 广播消息列表                                              */                                                               void onHistoryBroadcastMsg(ArrayList<BroadCastMsg> msgs);

注意该api可能会存在多次回调，回调情况如下:

- 首次进入直播间并调用start()开启直播回调
- 网络切换会回调
- 弱网造成直播尝试重连的情况会回调
- 收到广播删除事件

    xxxxxxxxxx/**                                                 * 收到广播信息操作功能                                       *                                                  * @param action 广播操作信息类                            *               <p>                                *               BroadCastAction                    *               ｛                                  *               action：操作 1.删除                     *               id：广播ID                            *               ｝                                  */                                                void onBroadcastMsgAction(BroadCastAction action);

### 2.9 答题卡功能（投票功能）

- 收到开始答题（投票）的回调

    xxxxxxxxxx    /**     * 开始投票     *     * @param voteCount 总共的选项个数2-5     * @param VoteType  0表示单选，1表示多选，目前只有单选     */    public void onVoteStart(int voteCount, int VoteType);

- 收到结束答题（投票）的回调：

    xxxxxxxxxx   /**     * 结束投票     */    public void onVoteStop();

- 收到答题（投票）结果统计的回调：

    xxxxxxxxxx    /**     * 投票结果统计     */    public void onVoteResult(JSONObject jsonObject);

### 2.10 随堂测功能

主动获取随堂测的方法在DWLive类中，方法为：

- 获取当前实时的随堂测：

    xxxxxxxxxx    /**     * 获取当前的随堂测     * <br/>     * 获取成功后会回调DwLiveListener.onPracticePublish()方法     */    public void getPracticeInformation();

调用主动获取方法或者监听到主播端发布随堂测，就会触发接受随堂测题目的回调。

接收随堂测题目的方法为回调功能，相关类为DWLiveListener，方法为：

- 收到随堂测发布的事件：

    xxxxxxxxxx       /**         * 发布随堂测         *         * @param info 随堂测内容         */        @Override        public void onPracticePublish(PracticeInfo info);

参数说明

    xxxxxxxxxx    public class PracticeInfo {       //随堂测ID       private String id;       //随堂测类型 0 判断题 1 单选题 2 多选题       private int type;       //随堂测的状态: 1 正在发布 2 停止       private int status;       //随堂测发布时间 格式：yyyy-MM-dd HH:mm:ss       private String publishTime;       //是否已答过此随堂测       private boolean isAnswered;       //随堂测选项       private ArrayList<Option> options;       // 服务器响应时间       private long serverTime;       // 答过题的答案id列表(如果答过题 当时选择的答案列表)       private List<SubmitOption> submitRecord;    }

答完随堂测题目后，可以通过发送随堂测结果的方法来提交答案。

提交随堂测结果的方法为主动方法，在DWLive类中，方法为：

- 提交随堂测结果：

    xxxxxxxxxx    /**     * 发送随堂测结果     * @param practiceId    随堂测ID     * @param answerOptions 随堂测回答的结果信息     */    public void sendPracticeAnswer(String practiceId, ArrayList<String> answerOptions)

提交后会通过DWLiveListener下的onPracticeSubmitResult回调随堂测提交结果。

- 收到随堂测结果回调事件：

    xxxxxxxxxx    /**     * 收到随堂测提交结果     *     * @param info 随堂测结果     */    public void onPracticeSubmitResult(PracticeSubmitResultInfo info);

参数说明

    xxxxxxxxxx   public class PracticeSubmitResultInfo {    //随堂测ID    private String id    //随堂测类型 0 判断题 1 单选题 2 多选题    private int type;    //回答是否正确 1 正确 0 错误    private int answerResult;    //随堂测选项    private ArrayList<Option> options;   }

获取当前随堂测的统计信息，可调用DWLive下的getPracticeStatis(String practiceId)，此方法为主动调用方法。

- 获取随堂测统计信息：getPracticeStatis(String practiceId)

调用获取统计信息的方法后，会通过DWLiveListener的onPracticStatis(PracticeStatisInfo info)方法回调当前的随堂测统计信息：

- 收到随堂测统计信息：onPracticStatis(PracticeStatisInfo info)

    xxxxxxxxxx   public class PracticeStatisInfo {    //随堂测ID    private String id    //随堂测类型 0 判断题 1 单选题 2 多选题    private int type;    // 随堂测状态 1 发布中 2 停止发布    private int status;    // 回答该随堂测的人数    private int answerPersonNum;    // 回答正确的人数    private int correctPersonNum;    // 正确率    private String correctRate;    // 停止时间    private int stopTime;    // 选项的统计信息    private ArrayList<OptionStatis> optionStatis;    public class OptionStatis {        //  选项ID        private String id;        // 选项编号        private int index;        // 选择该选项的人数        private int count;        // 选择的比例        private String percent;        // 是否为正确选项 1 正确 0 错误        private int isCorrect;    }   }

### 2.11 连麦功能

连麦时主动调用的方法都在DWLive类，相关方法如下：

- 设置连麦相关的参数：setRtcClientParameters(RtcClientListener rtcClientListener, CCRTCRender localRender, CCRTCRender remoteRender)
- 开始视频连麦：startRtcConnect()
- 开始音频连麦：startVoiceRTCConnect()
- 断开连麦：disConnectSpeak()
- 断开连麦申请：disConnectApplySpeak()
- 关闭摄像头，释放资源：closeCamera()
- 移除本地摄像头渲染：removeLocalRender()

连麦功能的核心回调类为RtcClient.RtcClientListener，相关的回调方法如下：

- 回调当前是否能够连麦：onAllowSpeakStatus(boolean isAllowSpeak)
- 回调主播端接通连麦,开始连麦：onEnterSpeak(String videoSize)
- 回调连麦断开：onDisconnectSpeak()
- 回调连麦异常：onSpeakError(Exception e)
- 回调摄像头打开：onCameraOpen(int width, int height)

### 2.12 音频模式（Deprecated 2021-10-08）

该方法无法满足现有需求，用 2.21 音视频播放模式切换替代

此功能为主动调用功能，调用的方法在DWLive，相关方法如下：

- 切换当前播放模式：changePlayMode(Surface surface, PlayMode playMode)

如果是切换到音频模式下，surface可以传null

### 2.13 获取在线人数

此功能为方法回调功能，相关类DWLiveListener，相关方法如下：

- 在线人数：onUserCountMessage(int count)

返回的在线人数，是客户端设置的基数+实际人数之和

### 2.14 用户踢出

此方法为方法回调功能，相关类DWLiveListener，相关方法如下：

- 用户被踢出房间的回调：onKickOut(int type)

其中type的值对应的内容如下： 10: 在允许重复登录前提下，后进入者登录踢出先前登录者 20：讲师、助教、主持人通过页面踢出按钮踢出用户

### 2.15 打卡

此方法为方法回调功能，相关类BaseCallback，相关方法如下：

    xxxxxxxxxx    /**     * 打卡失败     * @param error 失败详情     */    void onError(String error);
        /**     * 打卡成功     *     * @param PunchAction message 成功返回的一些参数数据     */    void onSuccess(T msg);

设置打卡回调

    xxxxxxxxxx   DWLive.getInstance().setPunchCallback(new BaseCallback<PunchAction());

### 2.16 上下课逻辑

此方法为方法回调功能，相关类DWLiveListener，相关方法如下

    xxxxxxxxxx  /**     * 流结束 执行下课逻辑     *     * @param isNormal 流是否正常结束     */    public void onStreamEnd(boolean isNormal);    /**     * 流开始 执行上课逻辑     */    public void onStreamStart();

### 2.17 历史文档数据

此方法为方法回调功能，相关类DWLiveListener，相关方法如下

    xxxxxxxxxx     /**       * 回调当前翻页的信息<br/>       * 注意：<br/>       * 白板docTotalPage一直为0，pageNum从1开始<br/>       * 其他文档docTotalPage为正常页数，pageNum从0开始       *       * @param docId        文档Id       * @param docName      文档名称       * @param pageNum      当前页码       * @param docTotalPage 当前文档总共的页数       */      public void onPageChange(String docId, String docName, int docWidth, int docHeight, int pageNum, int docTotalPage);

注意该api可能会存在多次回调，回调情况如下:

- 首次进入直播间并调用start()开启直播回调
- 网络切换会回调
- 弱网造成直播尝试重连的情况会回调

### 2.18 线路切换（Deprecated 2021-10-08）

由于该方法无法兼容切换视频清晰度，故将该方法列为废弃，在标记的时间之后不再维护，由 2.20 清晰度切换和 2.21线路切换代替

直播可根据返回的线路进行线路切换和清晰度切换

主动调用方法（DWLive）

方法 | 说明
--- | ---
changePlaySource(LiveLineConfig liveLineConfig, LiveLineSwitchListener changeLineCallback) | 切换清晰度和线路

监听回调方法（DWLiveListener）注意该api可能会存在多次回调，回调情况如下:

- 首次进入直播间并调用start()开启直播回调
- 网络切换会回调
- 弱网造成直播尝试重连的情况会回调
- 上课会触发

方法 | 说明
--- | ---
HDReceivedVideoAudioLines(List videoPlaySource, LiveLineAudioParams audioPlaySource); | 返回视频线路列表和音频线路列表

- 主动调用方法中LiveLineConfig类属性信息如下

      xxxxxxxxxx /**  * 是否启用视频  */private boolean disableVideo = false; /**  * 线路配置信息  */private LiveLineParams liveLineParams;

  LiveLineParams属性参数信息如下

      xxxxxxxxxx  /**   * 线路num  该参数对应回调方法中LiveLineVideoParams和LiveLineAudioParams的lines列表   */private int lineNum = 0;  /**   * 清晰度   */private int quality = 0;

  LiveLineSwitchListener类详细信息如下

      xxxxxxxxxxpublic interface LiveLineSwitchListener {    /**     * 切换线路回调     * @param success 是否成功     *                -2：切换时间间隔小于3s     *                -1：切换的线路不正确     *                0 ：切换成功     *     * @param currentSourceIndex  当前线路索引     * @param currentQuality  当前清晰度     */    void onChangeLine(int success, int currentSourceIndex,int currentQuality);}

- 回调方法中LiveLineVideoParams类属性信息如下

  注意：lines 该属性信息代表的是线路列表，如0，1；0代表线路1，1代表线路2，对应主动调用方法中的lineNum

      xxxxxxxxxx/** * 线路列表 */private List<Integer> lines ;/** * 清晰度   0是原画  200是流畅  300是标清 */private int quality = 0;

  LiveLineAudioParams类属性信息如下

      xxxxxxxxxx/** * 线路列表 */private List<Integer> lines;

### 2.19 清晰度切换

直播可根据回调返回的清晰度列表进行视频清晰度的切换

监听回调类 DWLiveListener

方法 | 说明
--- | ---
onHDReceivedVideoQuality(List videoQuality, LiveQualityInfo currentQuality) | 返回清晰度列表和默认清晰度对象

该api会存在多次回调 如：切换清晰度、网络不稳定、从音频切回到视频模式

回调方法中 LiveQualityInfo 属性信息如下

    xxxxxxxxxx /**  * 清晰度对应的code码  */ private int quality; /**  * 清晰度描述  */ private String desc;

主动调用类DWLive

方法 | 说明
--- | ---
changeQuality(int quality, LiveChangeSourceListener changeCallBack) | 切换清晰度

主动调用方法中参数信息如下

quality：清晰度对应的code码

changeCallBack：

    xxxxxxxxxx/**                                     * 切换回调                                 *                                      * @param success 是否成功                  *                -2：切换时间间隔小于3s         *                -1：参数错误           *                0 ：切换成功               */                                    void onChange(int success);

### 2.20 线路切换

直播可根据回调返回的线路列表进行视频和音频线路的切换

监听回调类 DWLiveListener

方法 | 说明
--- | ---
onHDReceivedVideoAudioLines(List lines, int indexNum) | 返回线路列表和当前线路的索引

该api会存在多次回调 如：切换清晰度、网络不稳定、音频/视频模式切换

用户账号开启音频线路功能并切换到音频播放模式（详见2.21）时时才会返回音频线路

回调方法中 LiveLineInfo 属性信息如下

    xxxxxxxxxx/** * 线路名称 如：line1、line2 */private String line;

主动调用类DWLive

方法 | 说明
--- | ---
changeLine(int lineIndex, LiveChangeSourceListener changeCallBack) | 切换音频或者视频线路

主动调用方法中参数信息如下

lineIndex ：回调方法中参数lines的索引

changeCallBack :

    xxxxxxxxxx/**                                     * 切换回调                                 *                                      * @param success 是否成功                  *                -2：切换时间间隔小于3s         *                -1：参数错误           *                0 ：切换成功               */                                    void onChange(int success);

### 2.21 音视频播放模式切换

直播可切换音频/视频播放模式，该方法需要账号开启音频线路功能

监听回调类DWLiveListener

方法 | 说明
--- | ---
onHDAudioMode(DWLive.Audio hasAudio) | 返回支持的播放模式

回调方法中hasAudio枚举说明如下

    xxxxxxxxxx  /**     * HAVE_AUDIO_LINE_TRUE:  账号已开启音频模式     * HAVE_AUDIO_LINE_FALSE: 账号未开启音频模式     */    public enum Audio {        HAVE_AUDIO_LINE_TRUE, HAVE_AUDIO_LINE_FALSE;    }

主动调用方法DWLive

方法 | 说明
--- | ---
changePlayMode(PlayMode playMode, LiveChangeSourceListener changeCallBack) | 切换播放模式

该方法只有在回调方法返回类型为 DWLive.Audio.HAVE_AUDIO_LINE_TRUE 时才生效

主动调用方法中参数信息如下

playMode ：

    xxxxxxxxxx/**     * 播放模式     * PLAY_MODE_TYEP_VIDEO: 视频播放模式     * PLAY_MODE_TYEP_AUDIO: 音频播放模式     */public enum LivePlayMode {    PLAY_MODE_TYEP_VIDEO, PLAY_MODE_TYEP_AUDIO}

changeCallBack ：

    xxxxxxxxxx/** * 切换回调 * * @param success 是否成功 *                -2：切换时间间隔小于3s *                -1：参数错误 *                0 ：切换成功 */void onChange(int success);