观看准备
-
创建直播间 获取roomId
-
获取直播间包含看直播权限的access_token
工程配置
在开始使用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;
}
}
}
}