# 关于如何接入SDK回放功能

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

- 关于如何接入SDK回放功能

  - 1. 回放核心功能

    - 1.1 回放登录

      - 1.1.1 主动调用api
      - 1.1.2 回调事件api

    - 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 回放页面信息
    - 2.5 切换线路功能 (2021年10月08日之后不再进行维护)
    - 2.6 清晰度切换
    - 2.7 线路切换
    - 2.8 音视频播放模式切换
    - 2.9 回放打点功能
    - 3.0 回放随堂测功能

## 1. 回放核心功能

### 1.1 回放登录

#### 1.1.1 主动调用api

回放登录需要主动调用方法在DWLiveReplay.java（DWLiveReplay为单例）中，如下

方法 | 说明
--- | ---
getInstance() | 获取DWLiveReplay单例
setLoginParams(DWLiveLoginListener dwLiveLoginListener, LoginInfo loginInfo) | (过时) 设置回放登录参数
startLogin() | (过时) 开始登录
startLogin(ReplayLoginInfo, final DWLiveReplayLoginListener) | （>=3.14.0）设置登录参数并开始登录

登录所需参数ReplayLoginInfo如下

    xxxxxxxxxx// 用户ID  private String userId;    // 直播间IDprivate String roomId;                 // 直播ID                                                   private String liveId;               // 回放ID                                                 private String recordId;               // 观众名称                                                private String viewerName;              // 观众密码                                                private String viewerToken;             // 用户分组ID                                                private String groupId;

#### 1.1.2 回调事件api

DWLiveReplayLoginListener

方法 | 说明
--- | ---
onException(DWLiveException exception) | 登录失败
onLogin(TemplateInfo templateInfo) | 登录成功
onLogin(TemplateInfo templateInfo, Marquee marquee) | 登录成功 附带跑马灯信息Marquee（重写方法）
onLogin(TemplateInfo templateInfo, Viewer viewer) | 登录成功 附个人信息Viewer（重写方法）

返回信息同直播相同，登录成功可监听onLogin任意一个互调

onLogin(TemplateInfo templateInfo, Marquee marquee)为定制方法，如需使用到界面跑马灯可单独实现该回调

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

#### 1.2.1 主动调用api

回放核心类代码在DWLiveReplay.java（DWLiveReplay为单例）如下

方法 | 说明
--- | ---
setReplayParams(DWLiveReplayListener replayListener, Context context) | 设置回调和上下文
setReplayPlayer(DWReplayPlayer player) | 设置播放器
setReplayDocView(DocView docView) | 设置文档
start() | 开始播放
stop() | 停止播放
pause() | 暂停播放
resume() | 恢复播放
setLastPosition(long position) | 设置开始播放位置，需在start之前调用
retryReplay(long position, boolean updateStream) | 重试播放 positon:播放位置updateStream更换流地址
onDestroy() | 释放资源
setSpeed(float speed) | 设置播放速率
changeLineWithPlayParameter(ReplayLineConfig ,ReplayLineSwitchListener) | (过时) 切换线路
changeLineWithNum(int line, ReplayLineSwitchListener changeLineCallback) | (过时) 切换线路
changeLine(int lineIndex, ReplayChangeSourceListener changeCallBack) | （>=3.13.0）切换线路
changeQuality(int quality, ReplayChangeSourceListener) | （>=3.13.0）切换清晰度
changePlayMode(PlayMode, ReplayChangeSourceListener ) | （>=3.13.0）切换音视频播放模式
setDocScaleType(DocView.ScaleType type) | 设置文档缩放类型
changeDocBackgroundColor(String color) | 更改文档背景颜色
reloadPageChange() | （>=3.17.9）刷新翻页，当文档回调DOC_DP_IMAGE_ERROR(4)错误时，可以调用此方法重试当前翻页。调用间隔需大于3s。
reloadPageData() | （>=3.17.9）刷新数据获取，当回放回调onPageDataError（3.17.9新增）时，可以调用此方法进行基础元数据重试。调用间隔需大于3s。

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

方法 | 说明
--- | ---
DWReplayPlayer(Context context) | 构造方法
updateSurface(Surface surface) | 更新Surface
start() | 开始播放
pause() | 暂停播放
stop() | 停止播放
reset() | 重置播放器
release() | 停止并释放资源，替代stop方法
destroy() | 完全释放
seekTo(long progress) | 拖动进度
setSpeed(float speed) | 设置播放速率
setOnPreparedListener(OnPreparedListener listener) | 设置准备回调
setOnErrorListener(IMediaPlayer.OnErrorListener listener) | 设置失败回调
setOnInfoListener(OnInfoListener listener) | 设置播放状态信息回调
setOnVideoSizeChangedListener(OnVideoSizeChangedListener listener) | 设置视频尺寸信息回调
setOnSeekCompleteListener(OnSeekCompleteListener listener) | 设置拖动进度完成回调
setSpeedListener(ReplaySpeedListener speedListener) | 设置视频缓冲的网速

#### 1.2.2 回调事件api

回调事件同直播

#### 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...DWLiveReplay dwLiveReplayTextureView video_view;  DocView doc_view;        Surface mSurface;        DWReplayPlayer mPlayer;  ... mPlayer = new DWReplayPlayer(this);   // 1. 设置Surface的回调                                                                    video_view.setSurfaceTextureListener(surfaceListener);                                 // 2. 获取单例                                                                                dwLiveReplay = DWLiveReplay.getInstance();         // 3. 设置播放器回调 mPlayer.setPlayerEventListener(playerEvent);   // 4. 设置回放业务的回调和上下文                                                                      dwLiveReplay.setReplayParams(dwLiveListener, DWLiveEngine.getInstance().getContext());    // 5. 设置播放器和监听 dwLiveReplay.setReplayPlayer(mPlayer);      ...

获取Surface

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

    xxxxxxxxxxprivate SurfaceTexture mSurfaceTexture; // surface回调                                                                           TextureView.SurfaceTextureListener surfaceListener = new TextureView.SurfaceTextureListener() {           @Override                                                                                public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1){          if (mSurfaceTexture != null) {                                      mVideoContainer.setSurfaceTexture(mSurfaceTexture);          } else {                                                            mSurfaceTexture = surfaceTexture;                               mSurface = new Surface(surfaceTexture);                 // 将surface设置给播放器             mPlayer.setSurface(mSurface);                                 }                                                                                     }                                                                                        @Override                                                                                public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {}                                                                                        @Override                                                                                public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {                    mSurface = null;                                                                          return false;                                                                        }     @Override                                                                                public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {                      }                                                                                    };

#### 1.2.4 集成说明

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

## 2. 回放其他功能

功能使用时相关的核心类：DWLiveReplayListener（回放回调接口类），DWLiveReplay（回放核心类）。

### 2.1 聊天功能

回放的聊天功能只包括公共聊天内容，此功能为方法回调功能，相关类DWLiveReplayListener，相关方法如下：

方法 | 说明
--- | ---
onChatMessage(TreeSet replayChatMsgs) | 全量回调回放聊天信息
onChatMessagePart(TreeSet chatMsgs) | 分段回调回放聊天信息

其中回调回来的对象ReplayChatMsg属性信息如下

    xxxxxxxxxx// 聊天消息内容private String content; // 分组IDprivate String groupId;// 聊天消息时间 秒private int time;        // 发送人用户名private String userName;     // 发送人userIdprivate String userId;     // 发送人头像private String avatar;// 用户角色 // 主讲（publisher）、助教（teacher）、主持人（host）、学生或观众（student）、其他没有角色（unknow）private String userRole;//发送人自定义标记private String userCustomMark;//是否显示此条消息（0: 不显示 1:显示）private String status;//发送人的角色 已过时private int classRole;

主动获取聊天数据 相关类DWLiveReplay

方法 | 说明
--- | ---
getAllChats(final BaseFunction<TreeSet> func) | 获取回放聊天信息（需在播放成功之后调用）

### 2.2 问答功能

回放的问答的功能包括已公开回答问答和已发布的答案，此功能为方法回调功能，相关类DWLiveReplayListener相关方法如下：

方法 | 说明
--- | ---
onQuestionAnswer(TreeSet qaMsgs) | 获取回放问答信息

返回对象ReplayQAMsg包含问题和回答列表，如何操作该类消息，请查看demo

主动获取问答数据 相关类DWLiveReplay

方法 | 说明
--- | ---
getAllQAs(final BaseFunction<TreeSet> func) | 获取所有的问答数据

其中 ReplayQuestionMsg 数据中包含的字段信息如下：

    xxxxxxxxxx//问答IDprivate String questionId;//问答内容private String content;//分组IDprivate String groupId;//问答发布时间 秒 （相对时间）private int time;//发送人IDprivate String questionUserId;//发送人昵称private String questionUserName;//发送人头像private String questionUserAvatar;// 是否是发布的问题private int isPublish;

其中 ReplayAnswerMsg 数据中包含的字段信息如下：

    xxxxxxxxxx//回复内容private String content;//分组IDprivate String groupId;//发布回复的时间 秒 （相对时间）private int time;//发送人昵称private String userName;//发送人IDprivate String userId;//发送人头像private String userAvatar;//发送人角色 （具体参考 回放用到的 “角色” 字段含义）private String userRole;

### 2.3 广播功能

回放的广播的功能是直播时发布的广播信息列表，此功能为方法回调功能，相关类DWLiveReplayListener，相关方法如下：

方法 | 说明
--- | ---
onBroadCastMessage(ArrayList broadCastMsgList) | 获取广播信息

返回对象ReplayBroadCastMsg属性信息如下

    xxxxxxxxxx// 广播内容   private String content;                                 //  广播时间（单位：秒）                                                                     private int time;                                // 发广播的人的ID                                                                     private String publisherId;                           // 发广播的人的名字                                                                    private String publisherName;                           // 发广播的人的角色                                                                     //主讲（publisher）、助教（teacher）、主持人（host）、学生或观众（student）、其他没有角色（unknow）private String publisherRole;

主动获取广播数据 相关类DWLiveReplay

方法 | 说明
--- | ---
getAllBoardCasts(final BaseFunction<ArrayList> func) | 获取所有的广播数据

### 2.4 回放页面信息

回放页面信息是通过回调返回给上层调用，此功能为回调功能，相关类是DWLiveReplayListener，相关方法如下

方法 | 说明
--- | ---
onPageInfoList(ArrayList infoList) | 回放页面信息
onPageChange(String docId, String docName, int docWidth ,int docHeight, int pageNum, int docTotalPage); | 回调当前翻页的信息

返回列表对象ReplayPageInfo属性信息如下：

    xxxxxxxxxx// 当前文档名称               private String docName;     // 当前文档页面的标题  private String pageTitle;      // 当前文档页面的链接  private String url;       // 当前文档页面的翻页时间（单位：S） private int time;

### 2.5 切换线路功能 (2021年10月08日之后不再进行维护)

由于该方法不兼容清晰度的切换，故废弃该方法，使用 2.6清晰度切换和 2.7线路切换替代

回放可根据返回的线路索引进行线路切换

主动调用方法

方法 | 说明
--- | ---
changeLineWithPlayParameter(ReplayLineConfig config, ReplayLineSwitchListener callback) | 切换音视频线路、清晰度方法,已过时

监听回调方法在DWLiveReplayListener中

方法 | 说明
--- | ---
numberOfReceivedLines(int lines) | 回放线路回调，已过时
numberOfReceivedLinesWithVideoAndAudio(List videoLines, ReplayAudioLineParams audioLines) | 回放线路 清晰度回调,已过时

参数属性信息如下：

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

      xxxxxxxxxx//是否启用视频private boolean disableVideo = false;//线路索引  音频是视频都存在多条线路private ReplayLineParams replayLineConfig;

  ReplayLineParams属性信息如下

      xxxxxxxxxx//线路 对应ReplayVideoLineParams ReplayAudioLineParams中的linesprivate int lineNum = 0;//清晰度  如果是音频模式 设置无效private int quality = 0;

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

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

      xxxxxxxxxx//线路列表private List<Integer> lines ;//清晰度private int quality = 0;//清晰度描述private String desp;

  ReplayAudioLineParams属性信息如下

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

### 2.6 清晰度切换

回放可根据返回的清晰度列表进行清晰度切换

主动调用方法

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

监听回调方法在DWLiveReplayListener中，该api会存在多次回调 如：切换清晰度、调用开始播放api、从音频切回到视频模式

方法 | 说明
--- | ---
onHDReceivedVideoQuality(List videoQuality, ReplayQualityinfo currentQuality) | 回调清晰度列表和当前播放的清晰度

主动调用方法中ReplayChangeSourceListener类说明如下

    xxxxxxxxxx public interface ReplayChangeSourceListener {    /**     * 切换回调     * @param success 是否成功     *                -2：切换时间间隔小于3s     *                -1：切换的数据不正确     *                0 ：切换成功     */    void onChange(int success);}

回调方法中ReplayQualityinfo类属性信息如下：

    xxxxxxxxxx /**  * 清晰度的code值，对应主动调用方法中的quality参数  */private int quality; /**  * 清晰度描述  */private String desc;

### 2.7 线路切换

回放可根据返回的线路列表进行线路切换

主动调用方法

方法 | 说明
--- | ---
changeLine(int index,ReplayChangeSourceListener changeCallBack) | 切换线路

监听回调方法在DWLiveReplayListener中，该api会存在多次回调 如：切换清晰度、调用开始播放api、音频/视频模式切换

方法 | 说明
--- | ---
onHDReceivedVideoAudioLines(List lines, int currentLineIndex) | 回调清晰度列表和当前播放的清晰度

主动调用方法中ReplayChangeSourceListener类说明如下

    xxxxxxxxxx public interface ReplayChangeSourceListener {    /**     * 切换回调     * @param success 是否成功     *                -2：切换时间间隔小于3s     *                -1：切换的数据不正确     *                0 ：切换成功     */    void onChange(int success);}

回调方法中ReplayLineInfo参数属性信息如下：

    xxxxxxxxxx   /**    * 线路名称，该属性参数表示线路代号，如：line1、line2 ...    * 主动调用时传入List<ReplayLineInfo>的索引    */ private String line;

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

回放可切换播放模式

主动调用方法

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

监听回调方法在DWLiveReplayListener中， 该api会存在多次回调 如：调用开始播放api、音频/视频模式切换

方法 | 说明
--- | ---
onHDAudioMode(Audio hasAudio) | 是否开启音频模式

主动调用方法中PlayMode 参数属性信息如下：

    xxxxxxxxxx  /**     * 播放模式     * VIDEO: 视频播放模式     * SOUND: 音频播放模式     */    public enum PlayMode {        VIDEO, SOUND    }

ReplayChangeSourceListener详细说明如下

    xxxxxxxxxxpublic interface ReplayChangeSourceListener {    /**     * 切换回调     * @param success 是否成功     *                -2：切换时间间隔小于3s     *                -1：切换的数据不正确     *                0 ：切换成功     */    void onChange(int success);}

回调方法中Audio类参数信息如下：

    xxxxxxxxxx   /**     * 音频模式     * HAVE_AUDIO_LINE_TURE: 有音频模式     * HAVE_AUDIO_LINE_FALSE: 无音频模式     */    public enum Audio {        HAVE_AUDIO_LINE_TURE, HAVE_AUDIO_LINE_FALSE    }

### 2.9 回放打点功能

回放打点功能，可根据返回的打点数据展示打点数据，界面显示请参考demo

DWLiveReplayListener类监听回调方法

方法 | 说明
--- | ---
onHDReplayDotList(List dotList) | 回放打点数据列表

其中ReplayDot类属性如下

    xxxxxxxxxx// 对应回放的时间 单位（秒）                  private int time;    // 打点描述                private String desc;

### 3.0 回放随堂测功能

回放随堂测功能

DWLiveReplay类主动获取

方法 | 说明
--- | ---
getAllPractices(final BaseFunction<ArrayList> func) | 回放随堂测数据列表

其中ReplayPracticeInfo类属性如下

    xxxxxxxxxx//随堂测统计数据private PracticeStatisInfo statisInfo;//随堂测排名数据private PracticeRankInfo rankInfo;//回放随堂测数据private ReplayPracticeInfoBase replayPracticeInfoBase;
    public class PracticeStatisInfo {    private String id;             // 随堂测ID    private int type;              // 随堂测类型: 0 判断 1 单选 2 多选    private int status;            // 随堂测状态  1 发布中 2 停止发布    private int answerPersonNum;   // 回答该随堂测的人数    private int correctPersonNum;  // 回答正确的人数    private String correctRate;    // 正确率    private int stopTime;          // 停止时间    private ArrayList<OptionStatis> optionStatis; // 选项的统计信息    public static class OptionStatis {        private String id;      //  选项ID        private int index;      // 选项编号        private int count;      // 选择该选项的人数        private String percent;   // 选择的比例        private int isCorrect;    // 是否为正确选项 1 正确 0 错误    }}public class PracticeRankInfo {    // 排名id:暂不可用    private String id;    // 排名人员信息    private ArrayList<ViewerRankInfo> rankList = new ArrayList<>();    public class ViewerRankInfo {            //提交者的用户id        private String viewerId;          //提交者的名称        private String viewerName;          //提交答案的时间与随堂测发布的时间的差值        private int costTime;           }}public static class ReplayPracticeInfoBase {        private String id;              //随堂测ID        private int type;               //随堂测类型（判断：0，单选：1，多选：2）        private int status;             //状态（正在发布：1  已停止：2）        private String publishTime;     //发布时间        private long recordId;          //回放ID        private int recordTime;         //相对于回放开始时长        private int stopRecordTime;     //相对于回放开始停止时长        private int closeRecordTime;    //相对于回放开始关闭时长        private List<Option> options;   //选项    public static class Option {            private double index;       //选项（0,1,2,3）            private String id;          //选项ID            private double isCorrect;   //是否正确（1：正确0：错误）    }}