liyubing

feat: 1)处理直播结束view;2)添加获取拉流地址

... ... @@ -32,6 +32,11 @@ export class HttpUrlUtils {
* 详情页面详情接口
*/
static readonly DETAIL_PATH: string = "/api/rmrb-bff-display-zh/content/zh/c/content/detail";
/**
* 获取视频直播间拉流地址
*/
static readonly PULL_STREAM_PATH: string = "/api/live-center-video/zh/c/vlive/pull-stream/";
/**
* 批查接口,查询互动相关数据,如收藏数、评论数等
*/
... ...
... ... @@ -70,6 +70,8 @@ export { NewspaperTimeItemBean } from './src/main/ets/bean/newspaper/NewspaperTi
export { ContentDetailDTO } from './src/main/ets/bean/detail/ContentDetailDTO';
export { GetPullAddressBean } from './src/main/ets/bean/live/GetPullAddressBean';
export { RmhInfoDTO } from './src/main/ets/bean/detail/RmhInfoDTO';
export { UserInfoDTO } from './src/main/ets/bean/detail/UserInfoDTO';
... ...
... ... @@ -19,4 +19,9 @@ export interface RmhInfoDTO {
userId: string;
userType: string;
honoraryIcon:string;
/**
* 发布标识,0-cms;1-表示号主发布
*/
rmhPlatform:number
}
... ...
/**
* 获取拉流地址解析类
*/
export class GetPullAddressBean {
origin: OriginBean = new OriginBean();
transCode: Array<TransCodeBean> = new Array;
}
class OriginBean {
expireTime: number = -1;
definition: string = '';
flvUrl: string = '';
m3u8Url: string = '';
rtmpUrl: string = '';
rtsUrl: string = '';
}
export class TransCodeBean {
expireTime: number = -1;
definition: string = '';
flvUrl: string = '';
m3u8Url: string = '';
rtmpUrl: string = '';
rtsUrl: string = '';
}
\ No newline at end of file
... ...
... ... @@ -466,7 +466,8 @@ export struct SearchResultContentComponent {
rmhDesc: obj.introduction,
userId: obj.userId,
userType: obj.userType,
honoraryIcon:''
honoraryIcon:'',
rmhPlatform:0
}
if(rem.length>0){
rem.forEach(item=>{
... ... @@ -491,7 +492,8 @@ export struct SearchResultContentComponent {
rmhDesc: item.introduction,
userId: item.userId,
userType: item.userType,
honoraryIcon:''
honoraryIcon:'',
rmhPlatform:0
}
}
})
... ...
... ... @@ -883,7 +883,8 @@ class MinePageDatasModel{
rmhDesc: obj.introduction,
userId: obj.userId,
userType: obj.userType,
honoraryIcon:''
honoraryIcon:'',
rmhPlatform:0
}
if(rem.length>0){
rem.forEach(item=>{
... ... @@ -908,7 +909,8 @@ class MinePageDatasModel{
rmhDesc: item.introduction,
userId: item.userId,
userType: item.userType,
honoraryIcon:''
honoraryIcon:'',
rmhPlatform:0
}
}
})
... ...
import { Logger, ResourcesUtils, EmitterUtils, EmitterEventId } from 'wdKit';
import { HttpUrlUtils, ResponseDTO, WDHttp } from 'wdNetwork';
import { ContentDetailDTO, InteractDataDTO } from 'wdBean';
import { ContentDetailDTO, GetPullAddressBean, InteractDataDTO } from 'wdBean';
import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
const TAG = 'ContentDetailRequest';
... ... @@ -208,6 +208,19 @@ export class ContentDetailRequest {
return url;
}
static getLiveRoomPullStreamUrl(vliveId:string){
let url = HttpUrlUtils.getHost() + HttpUrlUtils.PULL_STREAM_PATH
url = url + vliveId
return url;
}
static getLiveRoomPullStream(vliveId: string): Promise<ResponseDTO<GetPullAddressBean>> {
let url = ContentDetailRequest.getLiveRoomPullStreamUrl(vliveId)
return WDHttp.get<ResponseDTO<GetPullAddressBean>>(url)
}
static getContentDetail(params: ContentDetailRequestParams): Promise<ResponseDTO<ContentDetailDTO[]>> {
if (mock_switch) {
return ContentDetailRequest.getContentDetailDataMock(getContext());
... ... @@ -216,6 +229,8 @@ export class ContentDetailRequest {
return WDHttp.get<ResponseDTO<ContentDetailDTO[]>>(url)
}
/**
* 查询沉浸式视频频道推荐楼层数据
* @returns
... ...
import { Action, ContentDetailDTO } from 'wdBean/Index';
import { Action, ContentDetailDTO, GetPullAddressBean } from 'wdBean/Index';
import { LiveViewModel } from '../viewModel/LiveViewModel';
import router from '@ohos.router';
... ... @@ -78,14 +78,7 @@ export struct DetailPlayLiveCommon {
this.liveState = detailData.liveInfo?.liveState
if (this.liveState === 'wait' || this.liveLandscape === 'news') {
this.contentDetailData = data[0]
} else if (this.liveLandscape === 'general') {
//todo 不加setTimeOut ,接口返回的数据 就没法让PlayerComponent #@Consume @Watch('updateData') liveDetailsBean 的updateData方法运行
setTimeout(() => {
this.contentDetailData = data[0]
}, 10)
}
this.contentDetailData = data[0]
console.log(TAG, '查询视频详情用于评论展示 openComment:', detailData.openComment)
this.publishCommentModel.targetId = String(detailData?.newsId || '')
... ... @@ -106,7 +99,20 @@ export struct DetailPlayLiveCommon {
if (detailData.liveInfo.liveState == 'end') {
this.playUrl = detailData.liveInfo.vlive[0].replayUri
}
//console.error('XXXXZZZZ', "liveLandscape =" + this.liveLandscape + ' this.liveState =' + this.liveState)
//人民号类型单独获取直播地址
if (detailData.rmhPlatform === 1) {
let vliveId = detailData.liveInfo.vlive[0].vliveId as string
console.error(TAG, 'vliveId==' + vliveId)
this.liveViewModel.getLiveRoomPullAddress(vliveId)
.then((data: GetPullAddressBean) => {
console.log(TAG, ' GetPullAddressBean:', JSON.stringify(data))
})
}
}
})
}
... ...
import { ContentDetailDTO, LiveDetailsBean, LiveRoomBean, LiveRoomDataBean, ValueType } from 'wdBean/Index'
import { ContentDetailDTO,
GetPullAddressBean,
LiveDetailsBean, LiveRoomBean, LiveRoomDataBean, ValueType } from 'wdBean/Index'
import { ContentDetailRequest } from 'wdDetailPlayApi/Index'
import { ResponseDTO } from 'wdNetwork/Index'
import { LiveModel } from './LiveModel'
... ... @@ -24,6 +27,28 @@ export class LiveViewModel {
}
getLiveRoomPullAddress(vliveId:string){
// return new Promise<GetPullAddressBean>((success, fail) => {
// this.liveModel.getContentDetail(contentId, relId, relType).then((data) => {
// success(data)
// }).catch((message: string) => {
// fail(message)
// })
// })
return new Promise<GetPullAddressBean>((success, fail) => {
ContentDetailRequest.getLiveRoomPullStream(vliveId).then(async (resDTO: ResponseDTO<GetPullAddressBean>) => {
console.log(TAG, 'getContentDetail:', JSON.stringify(resDTO.data))
if (resDTO.data) {
success(resDTO.data)
}
}).catch(() => {
fail("数据为空")
})
})
}
//直播详情
getLiveDetails(contentId: string, relId: string, relType: string) {
... ...
... ... @@ -52,7 +52,6 @@ export struct TopPlayComponent {
} else if (status === PlayerConstants.STATUS_COMPLETION) {
// 播放完成
} else {
this.isError = false
}
... ...
... ... @@ -28,7 +28,10 @@ export struct PlayerComponent {
this.playerController?.pause()
}
aboutToAppear(): void {
async aboutToAppear(): Promise<void> {
setTimeout(() => {
this.updateData()
}, 10)
}
async aboutToDisappear(): Promise<void> {
... ... @@ -36,6 +39,7 @@ export struct PlayerComponent {
await this.playerController?.pause()
await this.playerController?.stop()
await this.playerController?.release()
}
updateData() {
... ... @@ -58,6 +62,7 @@ export struct PlayerComponent {
this.liveStreamType = liveStreamType
this.playUrl = playUrl
}
console.error("XXXXZZZZ", 'updateData ----liveState==>' + this.playUrl)
}
build() {
... ... @@ -69,6 +74,7 @@ export struct PlayerComponent {
playerController: this.playerController,
onLoad: () => {
this.isCanplay = true
console.error("XXXXZZZZ", '------2------------')
this.playerController?.firstPlay(this.playUrl);
}
})
... ... @@ -77,7 +83,7 @@ export struct PlayerComponent {
playerController: this.playerController,
onLoad: () => {
this.isCanplay = true
console.error('WDAliPlayerController', '------1------------')
console.error('XXXXZZZZ', '------1------------')
this.playerController?.firstPlay(this.playUrl);
}
}).margin({ top: 195 }).height(211)
... ...
... ... @@ -4,20 +4,24 @@ import { SpConstants } from 'wdConstant/Index'
import { ContentDetailRequest, postInteractAccentionOperateParams } from 'wdDetailPlayApi/Index'
import { NumberFormatterUtils, DateTimeUtils, SPHelper } from 'wdKit/Index'
import { WDRouterPage, WDRouterRule } from 'wdRouter/Index'
import { router } from '@kit.ArkUI'
const TAG = 'PlayerEndView'
@Preview
@Component
export struct PlayerEndView {
// @Consume liveDetailsBean: LiveDetailsBean
// @Consume liveDetailsBean: LiveDetailsBean
@Consume contentDetailData: ContentDetailDTO
@Consume liveRoomDataBean: LiveRoomDataBean
@State duration: string = ''
@State followStatus: String = '0';
private onBack: () => void = () => {
}
aboutToAppear(): void {
const sn = DateTimeUtils.parseDate(this.contentDetailData.liveInfo.startTime, DateTimeUtils.PATTERN_DATE_TIME_HYPHEN)
const sn =
DateTimeUtils.parseDate(this.contentDetailData.liveInfo.startTime, DateTimeUtils.PATTERN_DATE_TIME_HYPHEN)
const en = DateTimeUtils.parseDate(this.contentDetailData.liveInfo.endTime, DateTimeUtils.PATTERN_DATE_TIME_HYPHEN)
const sd = DateTimeUtils.getDuration(sn, en)
this.duration = DateTimeUtils.secondToTime(sd / 1000)
... ... @@ -113,7 +117,12 @@ export struct PlayerEndView {
.fontWeight(400)
.fontSize(16)
.fontColor(Color.White)
.padding({ top: 8, bottom: 8, left: 122, right: 122 })
.padding({
top: 8,
bottom: 8,
left: 122,
right: 122
})
.backgroundColor(this.followStatus == '0' ? '#FFED2800' : Color.Grey)
.borderRadius(4)
.onClick(() => {
... ... @@ -140,8 +149,30 @@ export struct PlayerEndView {
}
.width(307)
.padding({ top: 40 })
Blank()
// 返回按钮
Row() {
Image($r('app.media.icon_arrow_left_white'))
.width(24)
.height(24)
.aspectRatio(1)
.interpolation(ImageInterpolation.High)
.hoverEffect(HoverEffect.Scale)
.margin({ bottom: 30 ,left:14})
.onClick(() => {
if (this.onBack) {
this.onBack()
}
router.back();
})
}.width('100%')
}
.height('100%')
.width('100%')
}
}
\ No newline at end of file
... ...
... ... @@ -7,12 +7,13 @@ import {
paused,
stopped,
completion,
error} from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
error
} from 'premierlibrary/src/main/ets/com/aliyun/player/IPlayer';
import { initGlobalPlayerSettings, setupPlayerConfig } from '../utils/GlobalSetting';
import prompt from '@ohos.promptAction';
import { PlayerConstants, AVPlayerStatus, Events } from '../constants/PlayerConstants';
import { Logger } from 'wdKit/Index';
import { Logger, StringUtils } from 'wdKit/Index';
const TAG = "WDAliPlayerController"
... ... @@ -26,7 +27,6 @@ const TAG = "WDAliPlayerController"
export class WDAliPlayerController {
private initPromise: Promise<void>;
private avPlayer?: AliPlayer;
// 内部播放器状态
private avPlayerStatus: number = idle
private duration: number = 0;
... ... @@ -38,18 +38,14 @@ export class WDAliPlayerController {
private seekTime: number = 0;
private positionY: number = 0;
private startTime: number = 0
public errorCode?: number
public errorMesage?: string
public onVideoSizeChange?: (width: number, height: number) => void;
public onBufferUpdate?: (buffered: number, duration: number) => void;
public onTimeUpdate?: (position: number, duration: number) => void;
public onVolumeUpdate?: (volume: number) => void;
// 播放完成,决定是否继续播放回调
public continue?: () => void;
// 准备完成,决定是否播放回调。如果不实现,则自动播放
public onCanplay?: () => void;
public onStatusChange?: (status: number) => void;
... ... @@ -94,11 +90,11 @@ export class WDAliPlayerController {
private bindState() {
this.avPlayer?.setOnPreparedListener({
// 当调用play()方法后,会调用
onPrepared: () => {
this.duration = this.avPlayer?.getDuration();
Logger.debug(TAG, "已准备好", `${this.duration}`)
}
onPrepared: () => {
this.duration = this.avPlayer?.getDuration();
Logger.debug(TAG, "已准备好", `${this.duration}`)
}
}
);
this.avPlayer?.setOnRenderingStartListener({
onRenderingStart: () => {
... ... @@ -117,12 +113,12 @@ export class WDAliPlayerController {
onInfo: (bean: InfoBean) => {
if (bean.getCode() === InfoCode.CurrentPosition) {
let position : number = bean.getExtraValue()
let position: number = bean.getExtraValue()
Logger.debug(TAG, `播放进度条:${position}/ ${this.duration}`)
this.initProgress(position);
} else if (bean.getCode() === InfoCode.BufferedPosition) {
let buffer : number = bean.getExtraValue()
let buffer: number = bean.getExtraValue()
if (this.onBufferUpdate) {
this.onBufferUpdate(buffer, this.duration)
}
... ... @@ -140,7 +136,8 @@ export class WDAliPlayerController {
switch (status) {
case initalized: {
//this.avPlayer?.prepare();
} break
}
break
case prepared: {
if (this.startTime) {
this.setSeekTime(this.startTime, SliderChangeMode.Begin);
... ... @@ -154,20 +151,24 @@ export class WDAliPlayerController {
} else {
this.play()
}
} break
}
break
case started: {
this.setBright();
this.status = PlayerConstants.STATUS_START;
this.watchStatus();
} break
}
break
case paused: {
this.status = PlayerConstants.STATUS_PAUSE;
this.watchStatus();
} break
}
break
case stopped: {
this.status = PlayerConstants.STATUS_STOP;
this.watchStatus();
} break
}
break
case completion: {
this.status = PlayerConstants.STATUS_COMPLETION;
this.watchStatus();
... ... @@ -179,7 +180,8 @@ export class WDAliPlayerController {
//this.url = this.avPlayer.url || '';
//this.avPlayer.reset();
}
} break
}
break
case error: {
// 这里拿不到错误信息
// this.status = PlayerConstants.STATUS_ERROR;
... ... @@ -189,7 +191,7 @@ export class WDAliPlayerController {
}
});
this.avPlayer?.setOnErrorListener({
onError:(errorInfo) => {
onError: (errorInfo) => {
Logger.error(TAG, "播放错误", JSON.stringify(errorInfo))
this.errorCode = errorInfo.getCode()
this.errorMesage = errorInfo.getMsg()
... ... @@ -220,21 +222,29 @@ export class WDAliPlayerController {
}
private setAliPlayerURL(url: string) {
let urlSource : UrlSource = new UrlSource()
let urlSource: UrlSource = new UrlSource()
urlSource.setUri(url)
this.avPlayer?.setUrlDataSource(urlSource)
}
private getStatusStringWith(status: number) : string {
private getStatusStringWith(status: number): string {
switch (status) {
case idle: return 'idle'
case initalized: return 'initalized'
case prepared: return 'prepared'
case started: return 'started'
case paused: return 'paused'
case stopped: return 'stopped'
case completion: return 'completion'
case error: return 'error'
case idle:
return 'idle'
case initalized:
return 'initalized'
case prepared:
return 'prepared'
case started:
return 'started'
case paused:
return 'paused'
case stopped:
return 'stopped'
case completion:
return 'completion'
case error:
return 'error'
}
return 'unknow'
}
... ... @@ -256,6 +266,10 @@ export class WDAliPlayerController {
}
async firstPlay(url: string) {
if (StringUtils.isEmpty(url)) {
return
}
this.url = url;
if (this.avPlayer == null) {
Logger.info(TAG, "等待播放器初始化")
... ... @@ -278,7 +292,7 @@ export class WDAliPlayerController {
this.avPlayer?.setAutoPlay(false)
Logger.debug(TAG, "开始播放", this.url)
Logger.debug(TAG, "开始播放:"+ this.url)
this.setAliPlayerURL(this.url);
Logger.info(TAG, "设置SurfaceId: " + this.surfaceId)
... ...
... ... @@ -175,7 +175,7 @@ export class WDPlayerController {
this.pageParam = pageParam
}
if (this.avPlayer == null) {
Logger.error("等待")
console.log("等待")
await this.initPromise;
} else {
if (this.avPlayer.state != AVPlayerStatus.IDLE) {
... ... @@ -188,7 +188,7 @@ export class WDPlayerController {
if (this.avPlayer == null) {
return
}
Logger.error("开始播放", this.url)
console.log("开始播放", this.url)
this.avPlayer.url = this.url;
//加载时长prepareTime
this.creatEndTime = DateTimeUtils.getTimeStamp()
... ...