| 类名 | 描述 |
|---|---|
| VHWatchLivePlayer | 播放器控制核心类 |
| VHWatchLivePlayerView | 播放器核心组件 |
| VHWatchLivePlayerCallback | 播放器事件回调 |
import { VHWatchLivePlayer} from "@vhall/vhall_live";
@Component
export struct VHWatchLivePlayerComponent {
@State message: string = 'Hello World';
/**
* 播放器控制类
* */
public livePlayer?:VHWatchLivePlayer = new VHWatchLivePlayer(this.getUIContext().getHostContext() as Context);
......
} build() {
Stack({ alignContent: Alignment.Center }){
// 播放器容器. 设置回调监听,播放器实例,播放器水印配置信息
VHWatchLivePlayerView({ componentListener: this, livePlayer: this.livePlayer,is_expand:this.is_expand, enableDefaultWaterMask:true,water:this.playerConfig?.water!})
.width('100%')
.height('100%')
.expandSafeArea(this.is_expand ? this.expandTypes : [], this.is_expand ? this.expandEdges : [])
.backgroundColor(Color.Black)
.align(Alignment.Center)
.zIndex(playerZIndex.indexOf(PLAYER_INDEX))
....
} public initWebinarInfo(webinarsInfo: VHWebinarData)| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| webinarsInfo | 是 | xx | 活动信息 |
aboutToAppear(): void {
this.livePlayer?.initWebinarInfo(this.webinars!);
} public setLivePlayerListener(listener: VHWatchLivePlayerCallback) aboutToAppear(): void {
this.livePlayer?.initWebinarInfo(this.webinars!);
this.livePlayer?.setLivePlayerListener(this);
} public startPlay(def: VHPlayDefinition) | 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| def | 是 | xx | VHPlayDefinition 清晰度 |
//底层播放器初始化成功后才能进行播放,需要监听onPlayerViewInitCompleted回调
onPlayerViewInitCompleted(){
this.livePlayer?.startPlay(this.playerConfig?.default_definition!);
this.isPlayError = true;
} public stopPlay() this.livePlayer?.stopPlay(); public pausePlay() //控制暂停和恢复
if(this.is_playing){
this.livePlayer?.pausePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PAUSE);
}else{
this.livePlayer?.resumePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PLAY);
} public resumePlay() //控制暂停和恢复
if(this.is_playing){
this.livePlayer?.pausePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PAUSE);
}else{
this.livePlayer?.resumePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PLAY);
} public changeDefinition(def: VHPlayDefinition)| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| def | 是 | xx | VHPlayDefinition 清晰度 |
//根据选择的清晰度进行播放
builder:definitionsPopup({onItemSelected: (item: popItemValueObj) => {
if (this.is_start) {
this.isLoading = true;
this.livePlayer?.changeDefinition(item.value as VHPlayDefinition)
this.isPlayError = true;
}
this.playDefinition = item.text;
this.isDefinition = false;
}},this.playDefinitionList), public setPlayerVolume(vol: number): number| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| vol | 是 | xx | 范围:0.01 ~ 1.0 |
//根据选择的清晰度进行播放
.onActionUpdate((event: GestureEvent | undefined) => {
if (event && event.fingerList && event.fingerList[0]) {
const touchY = event.fingerList[0].localY;
const deltaY = touchY - touchStartY;
// 移动距离占播放器高度的比例(deltaY取反是因为值的正负与滑动方向相反)
const percent = (-deltaY / changeHeight);
const width = changeWidth as number;
if (touchStartX <= (width / 2)) {
} else {
let v = this.playerVol - (event.offsetY)/3/10;
let newVol = this.playerVol + percent;
// 严格限制在0-100范围内
newVol = Math.max(0, Math.min(100, v));
this.playerVol = newVol;
this.isShowVol = true;
this.livePlayer?.setPlayerVolume(newVol/100);//设置音量
}
touchStartY = touchY;
}
}) public setPlayerScalingMode(mode: VHPlayerVideoScalingMode)| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| mode | 是 | xx | VHPlayerVideoScalingMode 图像拉伸,等比例缩放,平铺 |
| VHPlayerVideoScalingMode | 类型 | 备注 |
|---|---|---|
| VH_FILL | number | 将图像拉伸填充 |
| VH_ASPECT_FIT | number | 将图像等比例缩放,适配最长边,居中显示,可能会留有黑边 |
| VH_ASPECT_FILL | number | 将图像等比例铺满整个屏幕,多余部分裁剪掉 |
//根据选择的清晰度进行播放
aboutToAppear(): void {
this.livePlayer?.initWebinarInfo(this.webinars!);
if(this.playerConfig?.basic?.picture_in_picture == 1){
this.livePlayer?.initPipController(true);
}
this.livePlayer?.setLivePlayerListener(this);
this.livePlayer?.setPlayerScalingMode(VHPlayerVideoScalingMode.VH_ASPECT_FILL);
} public destroyPlayer() aboutToDisappear(): void {
this.barrageController.pause();
this.barrageController.clearInScreen();
this.livePlayer?.destroyPlayer();
} public initCastPlay(source: VHCastMediaSource) | 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| source | 是 | xx | VHCastMediaSource |
aboutToAppear(): void {
this.livePlayer?.initWebinarInfo(this.webinars!);
this.livePlayer?.setLivePlayerListener(this);
this.livePlayer?.setPlayerScalingMode(VHPlayerVideoScalingMode.VH_ASPECT_FILL);
this.source = {
title:this.webinars?.webinar?.subject!,
name:'微吼SaaS',
description:this.webinars?.webinar?.subject!,
headImage:"https://cnstatic01.e.vhall.com/.....c1651.jpg"
};
//初始化投屏后,会创建媒体会话绑定播控服务。如果不使用投屏功能不要进行初始化。
this.livePlayer?.initCastPlay(this.source);
}); public startCastingPlay() 使用投播控件自动实现投屏 public stopCastingPlay() .onClick(() => {
this.livePlayer?.stopCastingPlay();
this.isCasting = false;
}) public initPipController(autoStart:boolean,navId?:string)| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| autoStart | 是 | xx | boolean 退到后台是否自动开启画中画 |
| navId | 否 | xx | 1、UIAbility使用Navigation管理页面,需要设置Navigation控件的id属性,并将该id设置给画中画控制器,确保还原场景下能够从画中画窗口恢复到原页面; 2、UIAbility使用Router管理页面时(画中画场景不推荐该导航方式),无需设置navigationId。注意:该场景下启动画中画后,不要进行页面切换,否则还原场景可能出现异常; 3、UIAbility只有单页面时,无需设置navigationId,还原场景下也能够从画中画窗口恢复到原页面 |
aboutToAppear(): void {
//如果活动配置支持了画中画则进行配置
this.livePlayer?.initWebinarInfo(this.webinars!);
if(this.playerConfig?.basic?.picture_in_picture == 1){
this.livePlayer?.initPipController(true);
}
} public startPiP() this.livePlayer?.startPiP(); public updatePipControlStatus(status: VHPipControlPanelStatus)| 参数名称 | 是否必须 | 示例 | 备注 |
|---|---|---|---|
| status | 是 | xx | VHPipControlPanelStatus |
if(this.is_playing){
this.livePlayer?.pausePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PAUSE);
}else{
this.livePlayer?.resumePlay();
this.livePlayer?.updatePipControlStatus(VHPipControlPanelStatus.VH_CONTROL_PLAY);
} public stopPiP() this.livePlayer?.stopPiP(); onPlayerViewInitCompleted(){
this.livePlayer?.startPlay(this.playerConfig?.default_definition!);
this.isPlayError = true;
}
/**
* 播放器播放失败事件
*/
onPlayerError(error: VHErrorInfo) {
if(error.code == VHConstants.VH_PLAY_CURRENT_DEF_FAILED){
//没有可用的清晰度,重新进行播放。
this.livePlayer?.startPlay(this.playerConfig?.default_definition!);
}else if(error.code == VHConstants.VH_PLAY_STREAM_FAILED || error.code == VHConstants.PLAY_FORMAT_ERROR ||
error.code == VHConstants.VH_NETWORK_ERROR || error.code == VHConstants.VH_CAN_NOT_FIND_HOST || error.code == VHConstants.VH_PLAY_TIMEOUT){
this.livePlayer?.pausePlay();
this.is_playing = false;
this.isPlayError = true;//监听到播放异常时,为了点击播放按键时使用startPlay重新进行拉流
}
this.getUIContext().getPromptAction().showToast({
message: error.code + error.message,
duration: 4000,
showMode: promptAction.ToastShowMode.DEFAULT,
bottom: 80
});
}
/**
* 观看状态回调
* @param player 播放器实例
* @param state 状态类型 详见 VHPlayerStatus 的定义.
*/
onStatusDidChange(state: VHPlayerState){
if(state == VHPlayerState.VH_PLAYER_PLAYING){
this.is_start = true;
this.is_playing = true;
this.isLoading = false;
this.isPlayError = false;
}else if(state == VHPlayerState.VH_PLAYER_PAUSE || state == VHPlayerState.VH_PLAYER_STOP || state == VHPlayerState.VH_PLAYER_RELEASE){
this.is_playing = false;
}
if(state == VHPlayerState.VH_PLAYER_PREPARED){
this.isLoading = true;
}else if(state == VHPlayerState.VH_PLAYER_BUFFERING_END){
this.isLoading = false;
}
this.playerState = state;
}
/**
* 画中画状态
* @param state: 画中画播放状态
*/
onPipStatusChange(state: VHPlayerPipState){
}
/**
* 画中画控制中心播放状态
* @param state: VHPlayerPipControlPanelStatus
*/
onPipControlPanelStatusChange(state: VHPipControlPanelStatus){
if(state == VHPipControlPanelStatus.VH_CONTROL_PAUSE){
this.livePlayer?.pausePlay();
}else{
this.livePlayer?.resumePlay();
}
}
/**
* 播放器音量
* @param volume :当前播放器音量值
*/
onPlayerVolume(volume: number){
}
/**
* 当前房间支持的清晰度列表
* @param definitions 支持的清晰度列表
*/
onValidDefinitions(definitions: VHPlayDefinition[]){
let hasDef:boolean = false;
this.definitions_list = [];
this.playDefinitionList = [];
definitions.forEach((item)=>{
//是否隐藏原画
if(item == VHPlayDefinition.VH_ORIGIN && this.configList.live_hidden_same == 1){
return;
}
this.definitions_list.push(item);
if(this.playerConfig?.default_definition == item){
hasDef = true;
}
this.resetPlayDef(item);
})
if(!hasDef && this.playerConfig && definitions.length > 0){
definitions.forEach((item)=>{
//如果没有默认清晰度,则重新选择一个清晰度
if(item != VHPlayDefinition.VH_AUDIO && this.playerConfig){
this.resetPlayDef(item);
this.playerConfig.default_definition = item as VHPlayDefinition;
return;
}
})
}
}
/**
* 视频流播放成功后,回调视频流的宽髙。用户可根据视频流实际宽高,调整播放容器大小。
* @param width 视频帧宽度
* @param height 视频帧高度
*/
onVideoFrameSize(width: number, height: number){
}
/**
* 投屏设备状体事件回调。
* @param state. 0 设备已准备好可以播放。1:设备已断开
*/
onCastPlayDeviceState(state: number){
this.isCasting = state == 0? true :false;
}
/**
* 已连接的投屏设备。
* @param state. 0 设备已准备好可以播放。1:设备已断开
*/
onCastPlayDeviceConnected(device: VHCastPickerDevice){
this.castPickDevice = device.deviceName;
}
/**
* 投屏事件回调。
* @param state:VHCastPlayState
*/
onCastPlayState(state: VHCastPickerState){
if(state == VHCastPickerState.VH_CAST_PICKER_STATE_PLAY){
this.is_start = true;
this.is_playing = true;
}else if(state == VHCastPickerState.VH_CAST_PICKER_STATE_PAUSE || state == VHCastPickerState.VH_CAST_PICKER_STATE_STOP){
this.is_playing = false;
}
}
/**
* 投屏播放时长。
* @param duration:number 播放总时长 ,单位ms
*/
onCastPlayDuration(duration: number){
}
/**
* 投屏播放当前位置。
* @param position:number 播放当前进度 ,单位ms
*/
onCastPlayPosition(position: number){
}
/**
* 投屏操作失败。
* @param state:VHCastPlayState。执行相关操作失败。包括开播、暂停、设置进度
*/
onCastPlayError(state: VHCastPickerState){
this.getUIContext().getPromptAction().showToast({
message: '投屏异常' + state.toString(),
duration: 4000,
showMode: promptAction.ToastShowMode.DEFAULT,
bottom: 80
});
}| VHPlayerState | 类型 | 备注 |
|---|---|---|
| VH_PLAYER_INIT | number | 默认初始化 |
| VH_PLAYER_PREPARED | number | 播放器预加载 |
| VH_PLAYER_LOADING | number | 加载中 |
| VH_PLAYER_PLAYING | number | 播放中 |
| VH_PLAYER_PAUSE | number | 已暂停 |
| VH_PLAYER_STOP | number | 已停止 |
| VH_PLAYER_COMPLETE | number | 播放已完成 |
| VH_PLAYER_RELEASE | number | 播放器已释放 |
| VH_PLAYER_BUFFERING_END | number | 视频数据加载完成 |
| VHPlayerPipState | 类型 | 备注 |
|---|---|---|
| VH_PIP_START | number | 画中画开始 |
| VH_PIP_STOP | number | 画中画停止 |
| VH_PIP_ERROR | number | 画中画异常 |
| VH_PIP_RESTORE | number | 画中画点击小窗恢复 |
| VH_PIP_CONTROL_PAUSE | number | 画中画点击小窗暂停 |
| VH_PIP_CONTROL_RESUME | number | 画中画点击小窗恢复播放 |
| VHPlayerPipControlPanelStatus | 类型 | 备注 |
|---|---|---|
| CONTROL_PAUSE | number | 画中画点击小窗暂停 |
| CONTROL_PLAY | number | 画中画点击小窗恢复播放 |
| VHCastPickerState | 类型 | 备注 |
|---|---|---|
| VH_CAST_PICKER_STATE_NO_CAST_PLAY | number | 无投屏 |
| VH_CAST_PICKER_STATE_INITIAL | number | 初始化投屏中 |
| VH_CAST_PICKER_STATE_PREPARE | number | 投屏视频准备中 |
| VH_CAST_PICKER_STATE_PLAY | number | 投屏播放 |
| VH_CAST_PICKER_STATE_PAUSE | number | 投屏暂停 |
| VH_CAST_PICKER_STATE_STOP | number | 投屏停止 |
| VHCastPickerDevice | 类型 | 备注 |
|---|---|---|
| deviceName | string | 设备名称 |
| deviceId | string | 设备ID |
| VHPipControlPanelStatus | 类型 | 备注 |
|---|---|---|
| VH_CONTROL_PAUSE | number | 画中画暂停 |
| VH_CONTROL_PLAY | number | 画中画恢复播放 |
清晰度枚举值
| VHPlayDefinition | 值 | 描述 |
|---|---|---|
| VH_ORIGIN | 0 | 原画 |
| VH_UHD | 1 | 高清720p |
| VH_HD | 2 | 标清480p |
| VH_SD | 3 | 流畅360p |
| VH_AUDIO | 4 | 纯音频 |
| VH_FULL_HD | 6 | 超清1080p |
用于投屏时设置icon信息
| VHCastMediaSource | 值 | 描述 |
|---|---|---|
| name | string | 标题名字 |
| title | string | 标题内容 |
| description | string | 描述 |
| headImage | string | 显示头像 |