观看准备

  1. 注册微吼开发者账号

  2. 创建应用 获取AppID

  3. 设置应用包名、签名

  4. 创建直播间 获取roomId

    可以通过 【测试工具】 或 【API】 获得

  5. 获取直播间包含看直播权限的access_token

    可以通过 【测试工具】 或 【API】 获得

工程配置

在开始使用sdk之前,我们要配置好IDE和创建基础的工程代码。相关内容在【工程配置】中有详细说明。

时序图

注:已知直播间ID的情况下虚线框部分无需请求。

对接流程

1 VHLivePlayer

1.1 VHVideoPlayerView 获取View

通过FindViewById 获取View的实例,此View重要用于看直播,拉流的数据会直接渲染到此View上,lss服务内部实现的一个普通渲染方案。

<com.vhall.lss.play.impl.VHVideoPlayerView
        android:id="@+id/player"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

渲染视图上添加水印,水印添加方式:1. 控制台配置;2.VHVideoPlayerView 代码设置;

说明:水印生效以先加载为准,控制台配置在初始化房间信息后异步加载;

 mVideoPlayer.setWaterMark(drawable);
 mVideoPlayer.setWaterMarkGravity(Gravity.LEFT);
    /**
     * 设置水印
     *
     * @param drawable
     */
    public void setWaterMark(Drawable drawable)
    /**
     * 设置水印的相对位置
     *
     * @param gravity Gravity.LEFT
     */
    public void setWaterMarkGravity(int gravity) 

1.2 构造VHLivePlayer

VHLivePlayer采用builder模式构造,也是观看直播的核心方法,更多构造参数,参见builder类具体内容

/**
 * 构造VHLivePlayer
 * Builder 具体参考1.3
 */
mPlayer = new VHLivePlayer.Builder()
	.videoPlayer(mVideoPlayer) // 播放视频View
	.listener(new MyListener()) // 添加监听,具体监听事件参考本文的事件监听
	.build();

1.3 VHLivePlayer的 Builder

IVHVideoPlayer/IVHAudioPlayer为视频、音频播放接口,用户可实现此接口来自定义视频渲染和音频播放。

Builder 描述
videoPlayer 添加视频播放器
aideoPlayer 添加音频播放器
listener 添加监听
reconnectTimes 重连次数
connectTimeout 超时时间
bufferSeconds 缓冲时间

2 开始观看

/**
 * 开始观看,传递观看准备中配置的roomId (房间ID)和AccessToken;
 * 次方法属于 VHLivePlayer
 * @param String roomId ; // 房间ID  通过 API 调用
 * @param String accessToken; // 发起的Token  通过 API 调用
 */
public void start(String roomId  , String accessToken);

3 设置观看显示模式

调整观看的预览模式,

显示模式 参数
VHLivePushFormat.DRAW_MODE_ASPECTFILL 将图像等比例铺满整个屏幕,多余部分裁剪掉,此模式下画面不会留黑边,但可能因为部分区域被裁剪而显示不全
VHLivePushFormat.DRAW_MODE_ASPECTFIT 将图像等比例缩放,适配最长边,缩放后的宽和高都不会超过显示区域,居中显示,画面可能会留有黑边
VHLivePushFormat.DRAW_MODE_NONE 默认
/**
 * 设置预览模式,具体查看表格
 * 次方法属于 VHLivePlayer
 * @param int mode 预览的类型
 */
public void setDrawMode(int mode);

4 设置观看清晰度

从 IVHLivePlayer.EVENT_DPI_LIST 获取当前地址可用的分辨率,确定可用的情况下在切换

清晰度 描述
IVHLivePlayer.DPI_SD 低清
IVHLivePlayer.DPI_HD 高清
IVHLivePlayer.DPI_XHD 超清
IVHLivePlayer.DPI_AUDIO 纯音频
IVHLivePlayer.DPI_SAME 原画
/**
 * 在设置清晰度时,需要先获取当前的视频可用的分辨率,确认可用的时在调用。
 * 次方法属于 VHLivePlayer
 * @param int dpi 定义的清晰度
 */
public void.setDPI(dpi);

5 暂停观看/ 恢复观看

停止拉流,而云端的视频源还在不断地更新着 , 当重新恢复时,会从最新的时间点播放

/**
 * 暂停观看/ 恢复观看
 * 次方法属于 VHLivePlayer
 */
public void pause();
public void resume();

6 结束观看

停止拉流,此时调用Stop()方法,不在继续拉流,播放器的实例还在,

/**
 * 停止拉流
 * 次方法属于 VHLivePlayer
 */
public void stop();

7 销毁

当调用release() 方法时,视频播放器和音频播放器被释放, 如果需要再次使用请重新初始化

/**
 * 退出播放并释放相关资源。
 * 次方法属于 VHLivePlayer
 */
public void release();

事件处理

观看事件 描述
IVHLivePlayer.EVENT_STATUS_STARTED 拉流成功
IVHLivePlayer.EVENT_STATUS_STOPED 拉流停止
IVHLivePlayer.EVENT_DPI_LIST 可用的清晰度
IVHLivePlayer.EVENT_DPI_CHANGED 清晰度改变
IVHLivePlayer.EVENT_DOWNLOAD_SPEED 下载速度
IVHLivePlayer.EVENT_START_BUFFER 开始缓冲
IVHLivePlayer.EVENT_STOP_BUFFER 停止缓冲
IVHLivePlayer.EVENT_VIDEO_SIZE_CHANGED 视频宽高发生改变
IVHLivePlayer.EVENT_STREAM_START 发起端发起
IVHLivePlayer.EVENT_STREAM_STOP 发起端停止
错误事件 描述
IVHLivePlayer.ERROR_CONNECT 连接错误
class MyListener implements VHPlayerListener {

        @Override
        public void onEvent(int event, String msg) {
            switch (event) {
                case IVHLivePlayer.EVENT_STATUS_STARTING:
                    break;
                case IVHLivePlayer.EVENT_STATUS_STARTED:
                    mPlayBtn.setImageResource(R.mipmap.icon_pause_bro);
                    break;
                case IVHLivePlayer.EVENT_STATUS_STOPED:
                    break;
                case IVHLivePlayer.EVENT_DPI_LIST:
                    break;
                case IVHLivePlayer.EVENT_DPI_CHANGED:
                    break;
                case IVHLivePlayer.EVENT_DOWNLOAD_SPEED:
                    break;
                case IVHLivePlayer.EVENT_START_BUFFER:
                    break;
                case IVHLivePlayer.EVENT_STOP_BUFFER:
                    break;
                case IVHLivePlayer.EVENT_VIDEO_SIZE_CHANGED:
                    break;
            }
        }

        @Override
        public void onError(int errorCode, String msg) {
            switch (errorCode) {
                case IVHLivePlayer.ERROR_CONNECT:
                    break;
                case IVHLivePlayer.ERROR_SEND:
                    break;
                case IVHLivePlayer.ERROR_PARAM:
                    break;
            }
        }
    }

示例代码:

public class LivePlayerActivity extends Activity {

    private static final String TAG = "LivePlayerActivity";

    VHLivePlayer mPlayer;
    VHVideoPlayerView mVideoPlayer;
    MyReceiver myReceiver;
    private String roomId = "";
    private String accessToken = "";
    //data
    String currentDPI = "";
    List<String> dipList = new ArrayList<>();
    int drawmode = IVHVideoPlayer.DRAW_MODE_NONE;
    //view
    ImageView mPlayBtn;
    ProgressBar mLoadingPB;
    TextView mSpeedTV;
    private DPIPopu popu;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        roomId = getIntent().getStringExtra("roomid");
        accessToken = getIntent().getStringExtra("token");
        setContentView(R.layout.player_layout);
        mVideoPlayer = (VHVideoPlayerView) this.findViewById(R.id.player);
        mPlayer = new VHLivePlayer.Builder().videoPlayer(mVideoPlayer).listener(new MyListener()).build();

        mPlayBtn = (ImageView) this.findViewById(R.id.btn_play);
        mLoadingPB = (ProgressBar) this.findViewById(R.id.pb_loading);
        mSpeedTV = (TextView) this.findViewById(R.id.tv_speed);
        popu = new DPIPopu(this);
        popu.setOnDPIChangedListener(new DPIPopu.OnDPIChangedListener() {
            @Override
            public void onDPIChanged(String dpi) {
                mPlayer.setDPI(dpi);
                currentDPI = dpi;
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mPlayer.isPlaying())
            mPlayer.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mPlayer.resumeAble())
            mPlayer.resume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPlayer.release();
        unRegistReceiver();
    }

    public void play(View view) {
        if (mPlayer.isPlaying()) {
            mPlayer.stop();
        } else {
            if (mPlayer.resumeAble())
                mPlayer.resume();
            else
                mPlayer.start(roomId, accessToken);
        }
    }

    public void changeDPI(View view) {
        popu.showAtLocation(getWindow().getDecorView().findViewById(android.R.id.content), Gravity.CENTER, 0, 0);
    }

    public void changeMode(View view) {
        mVideoPlayer.setDrawMode(++drawmode % 3);
    }

    class MyListener implements VHPlayerListener {

        @Override
        public void onEvent(int event, String msg) {

            switch (event) {
                case IVHLivePlayer.EVENT_STATUS_STARTING:
                    break;
                case IVHLivePlayer.EVENT_STATUS_STARTED:
                    mPlayBtn.setImageResource(R.mipmap.icon_pause_bro);
                    break;
                case IVHLivePlayer.EVENT_STATUS_STOPED:
                    mPlayBtn.setImageResource(R.mipmap.icon_start_bro);
                    break;
                case IVHLivePlayer.EVENT_DPI_LIST:
                    Log.i(TAG, "DPILIST:" + msg);
                    try {
                        JSONArray array = new JSONArray(msg);
                        if (array != null && array.length() > 0) {
                            dipList.clear();
                            for (int i = 0; i < array.length(); i++) {
                                dipList.add((String) array.get(i));
                            }
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    popu.notifyDataSetChanged(currentDPI, dipList);
                    break;
                case IVHLivePlayer.EVENT_DPI_CHANGED:
                    Log.i(TAG, "DPI:" + msg);
                    if (!msg.equals(currentDPI))
                        currentDPI = msg;
                    popu.notifyDataSetChanged(currentDPI, dipList);
                    break;
                case IVHLivePlayer.EVENT_DOWNLOAD_SPEED:
                    mSpeedTV.setText(msg + "kb/s");
                    break;
                case IVHLivePlayer.EVENT_START_BUFFER:
                    mLoadingPB.setVisibility(View.VISIBLE);
                    break;
                case IVHLivePlayer.EVENT_STOP_BUFFER:
                    mLoadingPB.setVisibility(View.GONE);
                    break;
                case IVHLivePlayer.EVENT_VIDEO_SIZE_CHANGED:
                    Log.i(TAG, msg);
                    break;
            }


        }

        @Override
        public void onError(int errorCode, String msg) {
            mLoadingPB.setVisibility(View.GONE);
            Log.i(TAG, "errorCode:" + errorCode + ",msg:" + msg);
            switch (errorCode) {
                case IVHLivePlayer.ERROR_CONNECT:
                    break;
                case IVHLivePlayer.ERROR_SEND:
                    break;
                case IVHLivePlayer.ERROR_PARAM:
                    break;
            }

        }
    }
}

其他相关文档

  1. 快速开始
  2. 如何集成发起直播
  3. 发起直播参考手册