wangliang_wd

Merge branch 'main' of http://192.168.1.42/developOne/harmonyPool into main

* 'main' of http://192.168.1.42/developOne/harmonyPool:
  ref |> 处理直播上墙、回复消息、封禁、解封、预显控制、弹幕开关、结束直播、显示垫片控制
  ref |> 直播IM消息显示,处理竖屏直播
  ref |> 直播IM动态接收消息和显示。目前是横屏直播已处理
  ref |> 处理播控中心不生效问题
  ref |> 音频播放接入系统播控中心
Showing 25 changed files with 804 additions and 150 deletions
... ... @@ -19,11 +19,11 @@ export interface LiveRoomItemBean {
//guest :嘉宾,host:主持人
role: string
//ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
dataType: string
dataType: LiveMessageOptType
//管理直播间的消息类型 ZH_BARRAGE_SWITCH_MSG:弹幕开关 ZH_TOP_MSG:置顶,ZH_UN_TOP_MSG:取消置顶 ZH_STOP_LIVE: 直播结束,ZH_CHANGE_PAD直播垫片等
optionType: string
optionType: LiveMessageOptType
///房间类型,标识这个消息属于大家聊还是直播间,ZH_VIDEO:直播间 ZH_CHAT:大家聊
messageRoom: string
messageRoom: LiveMessageRoomType
//视频封面图
transcodeImageUrl: string
//视频地址
... ... @@ -39,4 +39,72 @@ export interface LiveRoomItemBean {
//观看人次
pv: string
///------- from IM
// 自义定表情
customizeExpression: number
// 已登录的用户id
senderUserId?: string
// 未登录的设备id
deviceId?: string
// data字段,评论预显开关
data?: string
// receiver
receiverText?: string
receiverTime?: string
receiverUserId?: string
receiverUserName?: string
receiverAvatarUrl?: string
// 自定义字段
customFormIM?: boolean // 默认来自网络接口
}
export enum LiveMessageOptType {
ZH_BARRAGE_SWITCH_MSG = "ZH_BARRAGE_SWITCH_MSG",
ZH_UPDATE_MSG = "ZH_UPDATE_MSG",
ZH_DELETE_MSG = "ZH_DELETE_MSG",
ZH_TOP_MSG = "ZH_TOP_MSG",
ZH_UN_TOP_MSG = "ZH_UN_TOP_MSG",
ZH_STOP_LIVE = "ZH_STOP_LIVE",
ZH_CHANGE_PAD = "ZH_CHANGE_PAD",
ZH_PRE_DISPLAY_CHANGE = "ZH_PRE_DISPLAY_CHANGE",
ZH_TEXT_MSG = "ZH_TEXT_MSG",
ZH_IMAGE_MSG = "ZH_IMAGE_MSG",
ZH_TEXT_AND_IMAGE_MSG = "ZH_TEXT_AND_IMAGE_MSG",
ZH_WALL_MSG = "ZH_WALL_MSG",
ZH_AUDIO_MSG = "ZH_AUDIO_MSG",
ZH_VIDEO_MSG = "ZH_VIDEO_MSG",
ZH_REPLY_MSG = "ZH_REPLY_MSG",
ZH_ROOM_NUMBER_MSG = "ZH_ROOM_NUMBER_MSG",
ZH_BARRAGE_BAN_MESSAGE = "ZH_BARRAGE_BAN_MESSAGE",
ZH_BARRAGE_UNBAN_MESSAGE = "ZH_BARRAGE_UNBAN_MESSAGE",
ZH_VOTE_MESSAGE = "ZH_VOTE_MESSAGE",
ZH_START_LIVE = "ZH_START_LIVE",
}
export enum LiveMessageRoomType {
living = "ZH_VIDEO", // 直播间
chat = "ZH_CHAT", // 大家聊
}
export enum LiveMessageRole {
host = "host",
guest = "guest",
tourist = "tourist",
}
export function LiveMessageIsHistoryMessage(optionType: LiveMessageOptType): boolean {
let isHistoryMessage = false
switch (optionType) {
case LiveMessageOptType.ZH_TEXT_MSG:
case LiveMessageOptType.ZH_IMAGE_MSG:
case LiveMessageOptType.ZH_TEXT_AND_IMAGE_MSG:
case LiveMessageOptType.ZH_AUDIO_MSG:
case LiveMessageOptType.ZH_VIDEO_MSG: {
isHistoryMessage = true
} break;
default:
break;
}
return isHistoryMessage
}
\ No newline at end of file
... ...
import { DateTimeUtils, Logger } from 'wdKit/Index';
import { WDPlayerController } from 'wdPlayer/Index';
import { PlayerConstants, WDPlayerController } from 'wdPlayer/Index';
let TAG: string = 'AudioRowComponent'
... ... @@ -12,6 +12,16 @@ export struct AudioRowComponent {
@State isPlaying: boolean = false
aboutToAppear(): void {
this.playerController.onCanplay = () => {
this.playerController.play()
}
this.playerController.onStatusChange = (status: number) => {
if (status == PlayerConstants.STATUS_START) {
this.isPlaying = true
} else {
this.isPlaying = false
}
}
this.playerController.firstPlay(this.audioUrl)
// this.playerController.onTimeUpdate = (nowSeconds, totalSeconds) => {
// console.log('现在时间', nowSeconds)
... ... @@ -30,7 +40,7 @@ export struct AudioRowComponent {
left: 8,
right: 6
})
.visibility(this.isPlaying ? Visibility.Visible : Visibility.Hidden)
.visibility(this.isPlaying ? Visibility.Hidden : Visibility.Visible)
Text(`${DateTimeUtils.getFormattedDuration(this.duration)}`)
.fontColor('#666666')
.fontWeight(400)
... ...
... ... @@ -73,7 +73,7 @@ export struct LiveOperRowListView {
private isLlive = false
/// comment
@State showCommentInput: boolean = false
private banComment: boolean = true // 是否已禁言
@Consume banComment: boolean // 上层可以直播IM控制
private commentInputDialogController?: CustomDialogController
@State publishCommentModel: publishCommentModel = new publishCommentModel()
... ...
... ... @@ -372,7 +372,7 @@ export struct OperRowListView {
.gesture(
TapGesture()
.onAction((event: GestureEvent) => {
this.AudioSuspension.setPlayerUrl(this.audioUrl, this.audioTitle)
this.AudioSuspension.setPlayerUrl(this.audioUrl, this.audioTitle, this.contentDetailData.newsId + "", this.contentDetailData.newsSourceName)
TrackingButton.click('suspendedWindow',this.pageId,this.pageName)
}))
}
... ...
import window from '@ohos.window';
import { Logger } from 'wdKit';
import { WDPlayerController } from 'wdPlayer';
import { BackgroundAudioController, WDPlayerController } from 'wdPlayer';
import { BusinessError } from '@ohos.base';
import { EmitterEventId, EmitterUtils } from 'wdKit/Index'
... ... @@ -39,9 +39,18 @@ export class AudioSuspensionModel {
/**
* 配置音频地址
*/
public setPlayerUrl(url: string, srcTitle: string) {
public async setPlayerUrl(url: string, srcTitle: string, srcContentId?: string, srcSource?: string) {
/*console.log(TAG,'this.url', this.url)
console.log(TAG,'url', url)*/
this.playerController.get().keepOnBackground = true
BackgroundAudioController.sharedController().avplayerController = this.playerController.get()
await BackgroundAudioController.sharedController().createSession()
BackgroundAudioController.sharedController().startContinuousTask()
let id = $r('app.media.newspaper_default').id
BackgroundAudioController.sharedController().setSessionMetaData(srcContentId ?? "", srcTitle, 'file://', srcSource ?? "")
BackgroundAudioController.sharedController().stopUseFeatures()
BackgroundAudioController.sharedController().listenPlayEvents()
if (this.url === url) {
this.isMinimize = AppStorage.link<boolean>('isMinimize')
console.log(TAG, 'this.isMinimize', this.isMinimize?.get())
... ...
... ... @@ -10,6 +10,8 @@ import { LiveRoomItemBean } from 'wdBean/Index';
import { LiveRoomBaseInfo } from './LiveRoomBaseInfo'
import { JSON } from '@kit.ArkTS';
import { LiveMessageIsHistoryMessage, LiveMessageOptType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean';
const TAG = "LiveRoomManager"
export class LiveRoom extends ChatroomStatusListener {
... ... @@ -32,7 +34,7 @@ export class LiveRoom extends ChatroomStatusListener {
enterRoom() {
let roomId = this.connectRoomBaseInfo?.roomID
let msgCount = 10;
let msgCount = 0;
Logger.debug(TAG, `will enterRoom roomId: ${roomId}`);
IMEngine.getInstance().joinExistingChatroom(roomId, msgCount).then(result => {
... ... @@ -107,7 +109,8 @@ export class LiveRoom extends ChatroomStatusListener {
let optionType = liveRoomItemBean.optionType != undefined ? liveRoomItemBean.optionType : liveRoomItemBean.dataType
if (this.isHistoryMessage(optionType)) {
if (LiveMessageIsHistoryMessage(optionType)) {
liveRoomItemBean.customFormIM = true
if (this.onHistoryMessage) {
this.onHistoryMessage(liveRoomItemBean)
}
... ... @@ -120,20 +123,4 @@ export class LiveRoom extends ChatroomStatusListener {
}
isHistoryMessage(optionType: string): boolean {
let isHistoryMessage = false
switch (optionType) {
case "ZH_TEXT_MSG":
case "ZH_IMAGE_MSG":
case "ZH_TEXT_AND_IMAGE_MSG":
case "ZH_AUDIO_MSG":
case "ZH_VIDEO_MSG": {
isHistoryMessage = true
} break;
default:
break;
}
return isHistoryMessage
}
}
\ No newline at end of file
... ...
... ... @@ -116,6 +116,7 @@ export class LiveRoomManager {
}
private connectWithIMToken(token: string) {
Logger.debug(TAG, "连接开始,IM Token:" + token)
const timeout = 5
IMEngine.getInstance().connect(token, timeout).then(result => {
if (EngineError.Success === result.code) {
... ...
... ... @@ -12,6 +12,8 @@ import { publishCommentModel } from 'wdComponent/src/main/ets/components/comment
import { TrackConstants, TrackingContent, TrackParamConvert } from 'wdTracking/Index';
import { onlyWifiLoadVideo } from 'wdComponent/src/main/ets/utils/lazyloadImg';
import { LiveDetailChatRoomController } from '../im/LiveDetailChatRoomController';
import { LiveMessageOptType, LiveMessageRoomType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean';
import { LiveDetailPageLogic } from '../viewModel/LiveDetailPageLogic';
let TAG: string = 'DetailPlayLivePage';
... ... @@ -40,9 +42,13 @@ export struct DetailPlayLivePage {
// 尽量不要动属性。用来作为输入了评论之后,值传递
@State lastInputedLiveComment: LiveRoomItemBean = {} as LiveRoomItemBean // 上次输入的直播间消息
@State lastInputedChatComment: LiveRoomItemBean = {} as LiveRoomItemBean // 上次输入的大家聊消息
@State lastLiveControl: LiveRoomItemBean = {} as LiveRoomItemBean // IM 控制消息
// 顶部状态栏高度
@Consume topSafeHeight: number
chatRoomController: LiveDetailChatRoomController = new LiveDetailChatRoomController()
@Provide banComment: boolean = true
@State isEnd: boolean = false
@Consume liveDetailPageLogic: LiveDetailPageLogic
@State toastText: ResourceStr = "这是一个非Wi-Fi环境。请注意流量消耗"
dialogToast: CustomDialogController = new CustomDialogController({
... ... @@ -83,30 +89,79 @@ export struct DetailPlayLivePage {
if(!await onlyWifiLoadVideo()){
this.showToastTip(this.toastText)
}
this.configChatRoom()
}
async aboutToDisappear() {
Logger.info(TAG, `wyj-aboutToDisappear`)
await this.playerController?.stop()
await this.playerController?.release()
}
configChatRoom() {
this.chatRoomController.onHistoryMessage = (liveRoomItemBean: LiveRoomItemBean) => {
if (liveRoomItemBean.messageRoom == "ZH_VIDEO") {
const preDisplay = this.contentDetailData.liveInfo.preCommentFlag == 1
if (this.liveViewModel.filterMySelfCommentNoPreDisplay(liveRoomItemBean, preDisplay)) {
return
}
if (liveRoomItemBean.messageRoom == LiveMessageRoomType.living) {
this.lastInputedLiveComment = liveRoomItemBean
} else if (liveRoomItemBean.messageRoom == "ZH_CHAT") {
} else if (liveRoomItemBean.messageRoom == LiveMessageRoomType.chat) {
this.lastInputedChatComment = liveRoomItemBean
}
}
this.chatRoomController.onLiveMessage = (liveRoomItemBean: LiveRoomItemBean) => {
if (liveRoomItemBean.optionType == "ZH_ROOM_NUMBER_MSG") {
this.liveRoomDataBean.pv = Number(liveRoomItemBean.pv)
switch (liveRoomItemBean.optionType) {
case LiveMessageOptType.ZH_ROOM_NUMBER_MSG: {
this.liveRoomDataBean.pv = Number(liveRoomItemBean.pv)
} break
case LiveMessageOptType.ZH_BARRAGE_SWITCH_MSG: {
const openComment = liveRoomItemBean.data == "1"
this.contentDetailData.liveInfo.openComment = openComment ? 1 : 0
} break
case LiveMessageOptType.ZH_PRE_DISPLAY_CHANGE: {
const preCommentFlag = liveRoomItemBean.data == "1"
this.contentDetailData.liveInfo.preCommentFlag = preCommentFlag ? 1 : 0
} break
case LiveMessageOptType.ZH_BARRAGE_BAN_MESSAGE:
case LiveMessageOptType.ZH_BARRAGE_UNBAN_MESSAGE: {
const banComment = liveRoomItemBean.data == "1"
this.banComment = banComment
} break
case LiveMessageOptType.ZH_STOP_LIVE:
case LiveMessageOptType.ZH_START_LIVE:
case LiveMessageOptType.ZH_CHANGE_PAD: { // 直播垫片控制
this.lastLiveControl = liveRoomItemBean
} break
case LiveMessageOptType.ZH_REPLY_MSG: {
this.lastInputedChatComment = liveRoomItemBean
} break
case LiveMessageOptType.ZH_UPDATE_MSG: {
this.lastInputedLiveComment = liveRoomItemBean
} break
case LiveMessageOptType.ZH_DELETE_MSG: {
this.lastInputedLiveComment = liveRoomItemBean
} break
case LiveMessageOptType.ZH_TOP_MSG: {
this.lastInputedLiveComment = liveRoomItemBean
} break
case LiveMessageOptType.ZH_UN_TOP_MSG: {
this.lastInputedLiveComment = liveRoomItemBean
} break
case LiveMessageOptType.ZH_WALL_MSG: {
this.lastInputedLiveComment = liveRoomItemBean
} break
default: {
Logger.warn(TAG, "暂未处理类型:" + liveRoomItemBean.optionType)
} break
}
}
this.chatRoomController.configDetail(this.contentDetailData)
}
async aboutToDisappear() {
Logger.info(TAG, `wyj-aboutToDisappear`)
await this.playerController?.stop()
await this.playerController?.release()
}
build() {
Column() {
TopPlayComponent({ playerController: this.playerController })
TopPlayComponent({ playerController: this.playerController, isEnd: this.isEnd, lastLiveControl: this.lastLiveControl })
.height(this.displayDirection == DisplayDirection.VERTICAL ? 211 : '100%')
.margin({
top: this.displayDirection == DisplayDirection.VERTICAL ? px2vp(this.topSafeHeight) : 0
... ...
import { ContentDetailDTO, LiveRoomDataBean } from 'wdBean/Index';
import { ContentDetailDTO, LiveRoomDataBean, LiveRoomItemBean } from 'wdBean/Index';
import { LiveViewModel } from '../viewModel/LiveViewModel';
import { CustomToast, WindowModel } from 'wdKit/Index';
import { CustomToast, Logger, WindowModel } from 'wdKit/Index';
import { PlayerComponent } from '../widgets/vertical/PlayerComponent';
import { PlayerInfoComponent } from '../widgets/vertical/PlayerInfoComponent';
import { WDAliPlayerController } from 'wdPlayer/Index';
... ... @@ -12,6 +12,8 @@ import { LiveDetailPageLogic } from '../viewModel/LiveDetailPageLogic';
import { onlyWifiLoadVideo } from 'wdComponent/src/main/ets/utils/lazyloadImg';
import { StringUtils } from 'wdKit';
import { LiveDetailChatRoomController } from '../im/LiveDetailChatRoomController';
import { LiveMessageOptType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean';
import { JSON } from '@kit.ArkTS';
const storage = LocalStorage.getShared();
const TAG = 'DetailPlayVLivePage'
... ... @@ -40,11 +42,13 @@ export struct DetailPlayVLivePage {
@Consume contentId: string
@State swiperIndex: number = 1
@Consume liveDetailPageLogic: LiveDetailPageLogic
@Provide lastInputedComment: LiveRoomItemBean = {} as LiveRoomItemBean // 上次输入的消息
//播放错误
@State isPlayerError: boolean = false
@State isCanplay: boolean = false
@State toastText: ResourceStr = "这是一个非Wi-Fi环境。请注意流量消耗"
chatRoomController: LiveDetailChatRoomController = new LiveDetailChatRoomController()
@Provide banComment: boolean = true
dialogToast: CustomDialogController = new CustomDialogController({
builder: CustomToast({
... ... @@ -71,7 +75,7 @@ export struct DetailPlayVLivePage {
if(!await onlyWifiLoadVideo()){
this.showToastTip(this.toastText)
}
this.chatRoomController.configDetail(this.contentDetailData)
this.configChatRoom()
}
aboutToDisappear(): void {
... ... @@ -92,6 +96,49 @@ export struct DetailPlayVLivePage {
// WindowModel.shared.setWindowSystemBarProperties({ statusBarContentColor: '#000000', })
}
configChatRoom() {
this.chatRoomController.onHistoryMessage = (liveRoomItemBean: LiveRoomItemBean) => {
const preDisplay = this.contentDetailData.liveInfo.preCommentFlag == 1
if (this.liveViewModel.filterMySelfCommentNoPreDisplay(liveRoomItemBean, preDisplay)) {
return
}
this.lastInputedComment = liveRoomItemBean
}
this.chatRoomController.onLiveMessage = (liveRoomItemBean: LiveRoomItemBean) => {
switch (liveRoomItemBean.optionType) {
case LiveMessageOptType.ZH_ROOM_NUMBER_MSG: {
this.liveRoomDataBean.pv = Number(liveRoomItemBean.pv)
} break
case LiveMessageOptType.ZH_BARRAGE_SWITCH_MSG: {
const openComment = liveRoomItemBean.data == "1"
this.contentDetailData.liveInfo.openComment = openComment ? 1 : 0
} break
case LiveMessageOptType.ZH_PRE_DISPLAY_CHANGE: {
const preCommentFlag = liveRoomItemBean.data == "1"
this.contentDetailData.liveInfo.preCommentFlag = preCommentFlag ? 1 : 0
} break
case LiveMessageOptType.ZH_BARRAGE_BAN_MESSAGE:
case LiveMessageOptType.ZH_BARRAGE_UNBAN_MESSAGE: {
const banComment = liveRoomItemBean.data == "1"
this.banComment = banComment
} break
case LiveMessageOptType.ZH_STOP_LIVE: {
this.liveState = "end"
this.contentDetailData.liveInfo.liveState = "end"
} break
case LiveMessageOptType.ZH_CHANGE_PAD: {
const padObj = JSON.parse(liveRoomItemBean.data ?? "") as Record<string, string | number | boolean>
const showPad = padObj["showPad"] == "1"
this.liveDetailPageLogic.showPad = showPad
} break
default: {
Logger.warn(TAG, "暂未处理类型:" + liveRoomItemBean.optionType)
} break
}
}
this.chatRoomController.configDetail(this.contentDetailData)
}
build() {
Stack({ alignContent: Alignment.Top }) {
... ... @@ -117,7 +164,7 @@ export struct DetailPlayVLivePage {
// 有垫片
if (this.liveDetailPageLogic.padImageUri.length > 0) {
// 配置了垫片资源
Image(this.liveDetailPageLogic.padImageUri).objectFit(ImageFit.Fill).width('100%').height('100%')
Image(this.liveDetailPageLogic.padImageUri).objectFit(ImageFit.Contain).width('100%').height('100%')
} else {
// 没有配置垫片资源
... ...
import { HttpUrlUtils, HttpUtils, ResponseDTO } from 'wdNetwork';
import { HttpBizUtil, HttpUrlUtils, HttpUtils, ResponseDTO } from 'wdNetwork';
import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest';
import { Logger, ToastUtils, EmitterEventId, EmitterUtils, SPHelper } from 'wdKit';
import { ContentDetailDTO, LiveDetailsBean, LiveRoomBean, LiveRoomDataBean,
... ... @@ -6,6 +6,7 @@ import { ContentDetailDTO, LiveDetailsBean, LiveRoomBean, LiveRoomDataBean,
ReserveItemBean, ValueType } from 'wdBean/Index';
import { ContentDetailRequest } from 'wdDetailPlayApi/Index';
import { SpConstants } from 'wdConstant/Index';
import { LiveMessageOptType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean';
const TAG = 'LiveModel'
... ... @@ -113,7 +114,7 @@ export class LiveModel {
params['liveId'] = liveId
params['pageSize'] = pageSize + ''
return new Promise<LiveRoomBean>((success, fail) => {
HttpRequest.post<ResponseDTO<LiveRoomBean>>(
HttpBizUtil.post<ResponseDTO<LiveRoomBean>>(
HttpUrlUtils.getLiveChatListUrl(),
params,
).then((data: ResponseDTO<LiveRoomBean>) => {
... ... @@ -321,7 +322,7 @@ export class LiveModel {
let commentItem: LiveRoomItemBean = {} as LiveRoomItemBean
commentItem.text = comment
commentItem.isWall = 0
commentItem.dataType = "ZH_TEXT_MSG"
commentItem.dataType = LiveMessageOptType.ZH_TEXT_MSG
let params: Record<string, string | number> = {};
params["liveId"] = liveId
... ...
... ... @@ -7,10 +7,12 @@ import {
LiveRoomItemBean,
ValueType
} from 'wdBean/Index'
import { LiveMessageIsHistoryMessage } from 'wdBean/src/main/ets/bean/live/LiveRoomBean'
import { SpConstants } from 'wdConstant'
import { ContentDetailRequest } from 'wdDetailPlayApi/Index'
import { Logger } from 'wdKit/Index'
import { Logger, SPHelper } from 'wdKit/Index'
import { ToastUtils } from 'wdKit/src/main/ets/utils/ToastUtils'
import { ResponseDTO } from 'wdNetwork/Index'
import { HttpUtils, ResponseDTO } from 'wdNetwork/Index'
import { LiveModel } from './LiveModel'
const TAG = "LiveViewModel"
... ... @@ -196,4 +198,37 @@ export class LiveViewModel {
retItem.fullColumnImgUrlDto = item.fullColumnImgUrlDto
return retItem
}
filterMySelfCommentNoPreDisplay(comment: LiveRoomItemBean, openPreDisplay:boolean) {
let mySelf = false
const userId = HttpUtils.getUserId()
const deviceId = HttpUtils.getDeviceId()
if (comment.senderUserId && comment.senderUserId == userId) {
mySelf = true
} else if (comment.deviceId && comment.deviceId == deviceId) {
mySelf = true
}
let optionType = comment.optionType != undefined ? comment.optionType : comment.dataType
if (mySelf
&& openPreDisplay
&& comment.customFormIM === true
&& LiveMessageIsHistoryMessage(optionType)
) {
return true
}
return false
}
isMySelfComment(comment: LiveRoomItemBean) {
let mySelf = false
const userId = HttpUtils.getUserId()
const deviceId = HttpUtils.getDeviceId()
if (comment.senderUserId && comment.senderUserId == userId) {
mySelf = true
} else if (comment.deviceId && comment.deviceId == deviceId) {
mySelf = true
}
return mySelf
}
}
... ...
... ... @@ -53,7 +53,9 @@ export struct TabChatComponent {
this.liveChatList.push(info)
this.pageModel.viewType = ViewType.LOADED;
// this.scroller.scrollEdge(Edge.Bottom)
if (this.pageModel.viewType == ViewType.LOADED) {
this.scroller.scrollEdge(Edge.Bottom)
}
console.log(TAG, '发布评论:', JSON.stringify(this.publishCommentModel.lastCommentModel))
}
}
... ... @@ -63,6 +65,9 @@ export struct TabChatComponent {
lastInputedCommentChanged(info: string) {
Logger.debug(TAG, "2显示评论》》》: " + JSON.stringify(this.lastInputedComment))
this.liveChatList.push(this.liveViewModel.deepCopyLiveRoomItem(this.lastInputedComment))
if (this.pageModel.viewType == ViewType.LOADED) {
this.scroller.scrollEdge(Edge.Bottom)
}
this.pageModel.viewType = ViewType.LOADED;
}
... ...
... ... @@ -3,6 +3,7 @@ import { Logger, StringUtils } from 'wdKit/Index'
// import { Action, LiveRoomItemBean, Params, PhotoListBean } from 'wdBean/Index'
import { WDRouterRule } from 'wdRouter'
import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO'
import { LiveMessageOptType, LiveMessageRole } from 'wdBean/src/main/ets/bean/live/LiveRoomBean'
const TAG = "TabChatItemComponent"
... ... @@ -22,61 +23,19 @@ export struct TabChatItemComponent {
.width(24)
.height(24)
Column() {
if (this.item.dataType == 'ZH_IMAGE_MSG') {
Row() {
Text() {
Span(this.item.senderUserName + ': ')
.fontColor('#666666')
}
.margin({ left: 8 })
.lineHeight(20)
.layoutWeight(1)
.fontSize('14fp')
.fontWeight(400)
}
.alignItems(VerticalAlign.Top)
if (this.item.pictureUrls && this.item.pictureUrls.length > 0) {
Image(this.item.pictureUrls[0])
.width(`100%`)
.objectFit(ImageFit.Contain)
.borderRadius(4)
.margin({
top: 10
})
.onClick(() => {
this.gotoMultipleListImagePage(this.item.pictureUrls[0])
})
}
} else {
Row() {
Text() {
Span(this.item.senderUserName + ': ')
.fontColor('#666666')
Span(this.item.text)
.fontColor('#222222')
}
.margin({ left: 8 })
.lineHeight(20)
.layoutWeight(1)
.fontSize('14fp')
.fontWeight(400)
}
.alignItems(VerticalAlign.Top)
this.messageContentText()
if (this.item.dataType == 'ZH_TEXT_AND_IMAGE_MSG' && this.item.pictureUrls &&
this.item.pictureUrls.length > 0) {
Image(this.item.pictureUrls[0])
.width(`100%`)
.objectFit(ImageFit.Contain)
.borderRadius(4)
.margin({
top: 10
})
.onClick(() => {
this.gotoMultipleListImagePage(this.item.pictureUrls[0])
})
}
if (this.item.pictureUrls && this.item.pictureUrls.length > 0) {
Image(this.item.pictureUrls[0])
.width(this.item.customizeExpression === 1 ? 72 : `100%`)
.objectFit(ImageFit.Contain)
.borderRadius(4)
.margin({
top: 10, bottom: 4
})
.onClick(() => {
this.gotoMultipleListImagePage(this.item.pictureUrls[0])
})
}
}
... ... @@ -96,6 +55,47 @@ export struct TabChatItemComponent {
}
@Builder messageContentText() {
Row() {
Text() {
if (this.item.receiverUserName && this.item.receiverUserName.length > 0) {
/// 回复的消息处理
Span((this.item.senderUserName ?? "游客") + " ").fontColor('#2696FF')
if (this.item.role == LiveMessageRole.host) {
Span(' 主持人 ')
.fontSize(11)
.lineHeight(20)
.textBackgroundStyle({ color: "#70FFC63F", radius: 2 })
Span(' ')
}
if (this.item.role == LiveMessageRole.guest) {
Span(' 嘉宾 ')
.fontSize(11)
.lineHeight(20)
.textBackgroundStyle({ color: "#70FFC63F", radius: 2 })
Span(' ')
}
Span("回复了 ").fontColor('#222222')
Span((this.item.receiverUserName ?? "游客") + ': ').fontColor('#666666')
Span(this.item.text).fontColor('#222222')
} else {
// 普通消息
Span((this.item.senderUserName ?? "游客") + ': ').fontColor('#666666')
Span(this.item.text).fontColor('#222222')
}
}
.margin({ left: 8 })
.lineHeight(20)
.layoutWeight(1)
.fontSize('14fp')
.fontWeight(400)
}
.alignItems(VerticalAlign.Top)
}
/**
* 大图列表页
* @param content
... ...
... ... @@ -10,6 +10,7 @@ import { LiveViewModel } from '../../viewModel/LiveViewModel'
import { Logger } from 'wdKit'
import LoadMoreLayout from 'wdComponent/src/main/ets/components/page/LoadMoreLayout'
import { PeopleShipNoMoreData } from 'wdComponent/src/main/ets/components/reusable/PeopleShipNoMoreData'
import { LiveMessageOptType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean'
const TAG: string = 'TabLiveComponent';
... ... @@ -34,7 +35,29 @@ export struct TabLiveComponent {
lastInputedCommentChanged(info: string) {
Logger.debug(TAG, "1显示评论》》》: " + JSON.stringify(this.lastInputedComment))
this.liveList.push(this.liveViewModel.deepCopyLiveRoomItem(this.lastInputedComment))
switch (this.lastInputedComment.optionType) {
case LiveMessageOptType.ZH_UPDATE_MSG: {
} break
case LiveMessageOptType.ZH_DELETE_MSG: {
} break
case LiveMessageOptType.ZH_TOP_MSG: {
} break
case LiveMessageOptType.ZH_UN_TOP_MSG: {
} break
case LiveMessageOptType.ZH_WALL_MSG: {
} break
}
if (this.liveList.totalCount() === 0) {
this.liveList.push(this.liveViewModel.deepCopyLiveRoomItem(this.lastInputedComment))
} else {
this.liveList.addFirstItem(this.liveViewModel.deepCopyLiveRoomItem(this.lastInputedComment))
}
this.pageModel.viewType = ViewType.LOADED;
}
... ... @@ -190,7 +213,7 @@ export struct TabLiveComponent {
liveRoomItemBeanTemp.senderUserName = '人民日报主持人'
liveRoomItemBeanTemp.pictureUrls = []
liveRoomItemBeanTemp.pictureUrls.push(this.contentDetailData?.fullColumnImgUrls[0]?.url)
liveRoomItemBeanTemp.dataType = 'ZH_TEXT_AND_IMAGE_MSG'
liveRoomItemBeanTemp.dataType = LiveMessageOptType.ZH_TEXT_AND_IMAGE_MSG
let temp = this.contentDetailData?.fullColumnImgUrls[0]
if (temp) {
liveRoomItemBeanTemp.pictureResolutions = []
... ...
import { Action, LiveRoomItemBean, Params, PhotoListBean } from 'wdBean/Index'
import { ExtraDTO } from 'wdBean/src/main/ets/bean/component/extra/ExtraDTO'
import { LiveMessageOptType, LiveMessageRole } from 'wdBean/src/main/ets/bean/live/LiveRoomBean'
import { AudioRowComponent } from 'wdComponent/Index'
import { DateTimeUtils, StringUtils } from 'wdKit/Index'
import { WDRouterRule } from 'wdRouter/Index'
... ... @@ -83,7 +84,7 @@ export struct TabLiveItemComponent {
.textAlign(TextAlign.Start)
//ZH_TEXT_AND_IMAGE_MSG :图文,ZH_TEXT_MSG:文本,ZH_VIDEO_MSG:视频,ZH_AUDIO_MSG:音频
//图文
if (this.item.dataType === 'ZH_TEXT_AND_IMAGE_MSG') {
if (this.item.dataType === LiveMessageOptType.ZH_TEXT_AND_IMAGE_MSG) {
List({ space: this.item.pictureUrls.length == 1 ? 0 : 5 }) {
ForEach(this.item.pictureUrls, (itemSub: string, index: number) => {
ListItem() {
... ... @@ -112,14 +113,14 @@ export struct TabLiveItemComponent {
})
}
//音频
else if (this.item.dataType === 'ZH_AUDIO_MSG') {
else if (this.item.dataType === LiveMessageOptType.ZH_AUDIO_MSG) {
AudioRowComponent({
audioUrl: this.item.audioUrl,
duration: this.item.duration
})
}
//视频
else if (this.item.dataType === 'ZH_VIDEO_MSG') {
else if (this.item.dataType === LiveMessageOptType.ZH_VIDEO_MSG) {
RelativeContainer() {
Image(this.item.transcodeImageUrl)
.width('100%')
... ... @@ -154,6 +155,11 @@ export struct TabLiveItemComponent {
this.gotoVideoPlayPage()
})
}
// 上墙或回复消息
else if (this.item.receiverUserName && this.item.receiverUserName.length > 0) {
this.wallOrReplySubMessage()
}
}
.margin({
left: 8,
... ... @@ -233,4 +239,64 @@ export struct TabLiveItemComponent {
}
return 1
}
// 上墙子消息
@Builder wallOrReplySubMessage() {
Row() {
Image(StringUtils.isEmpty(this.item.receiverAvatarUrl) ? $r('app.media.default_head') : this.item.receiverAvatarUrl)
.borderRadius(90)
.width(24)
.height(24)
Column() {
Row() {
Text() {
Span((this.item.receiverUserName ?? "游客") + ': ').fontColor('#666666')
}.lineHeight(20).fontSize('14fp').fontWeight(400)
if (this.item.isWall == 1) {
Blank().layoutWeight(1)
Text() {
Span(' 上墙 ')
.foregroundColor("#CB0000")
.fontSize(11)
.lineHeight(20)
.textBackgroundStyle({ color: "#70FFC63F", radius: 2 })
}.lineHeight(20).fontSize('14fp').fontWeight(400)
}
}
.alignItems(VerticalAlign.Top)
Text() {
Span(this.item.receiverText ?? "").fontColor('#222222')
}
.margin({top: 8})
.lineHeight(20)
.fontSize('14fp')
.fontWeight(400)
if (this.item.pictureUrls && this.item.pictureUrls.length > 0) {
Image(this.item.pictureUrls[0])
.width(this.item.customizeExpression === 1 ? 72 : `100%`)
.objectFit(ImageFit.Contain)
.borderRadius(4)
.margin({
top: 10, bottom: 4
})
.onClick(() => {
this.gotoMultipleListImagePage(0)
})
}
}
.margin({
left: 8,
right: 8
})
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
}
.alignItems(VerticalAlign.Top)
.padding({ top: 15 })
}
}
\ No newline at end of file
... ...
import { ContentDetailDTO } from 'wdBean/Index';
import { ContentDetailDTO, LiveRoomItemBean } from 'wdBean/Index';
import { Logger, StringUtils } from 'wdKit/Index';
import { PlayerConstants, WDAliPlayerController, WDPlayerRenderLiveView } from 'wdPlayer/Index';
import { PlayUIComponent } from './PlayUIComponent';
... ... @@ -6,6 +6,7 @@ import { PictureLoading } from '../../vertical/PictureLoading';
import { TrackConstants } from 'wdTracking/Index';
import { LiveDetailPageLogic } from '../../../viewModel/LiveDetailPageLogic';
import { LiveEmptyComponent, WDLiveViewDefaultType } from 'wdComponent/Index';
import { LiveMessageOptType } from 'wdBean/src/main/ets/bean/live/LiveRoomBean';
const TAG: string = 'TopPlayComponent'
... ... @@ -23,7 +24,7 @@ export struct TopPlayComponent {
//未开始
@State isWait: boolean = false
//已结束直播
@State isEnd: boolean = false
@Link isEnd: boolean
//播放错误
@State isPlayerError: boolean = false
// loading 控制字段
... ... @@ -38,6 +39,7 @@ export struct TopPlayComponent {
@Consume @Watch('pageShowChange') pageShow: number
@Consume @Watch('pageHideChange') pageHide: number
init: boolean = false
@Prop @Watch("liveIMControlMessageChange") lastLiveControl: LiveRoomItemBean = {} as LiveRoomItemBean // IM 控制消息
pageShowChange() {
this.playerController?.play()
... ... @@ -166,6 +168,27 @@ export struct TopPlayComponent {
// `---0------>` + this.isWait + ' ->' + this.isHideLoading + ' ->' + this.isEnd + ' -->' + this.isVideoSource)
}
liveIMControlMessageChange() {
switch (this.lastLiveControl.optionType) {
case LiveMessageOptType.ZH_STOP_LIVE: {
this.liveDetailPageLogic.showPad = false
this.contentDetailData.liveInfo.liveState = "end"
this.isEnd = true
}
break
case LiveMessageOptType.ZH_START_LIVE: {
// TODO:
}
break
case LiveMessageOptType.ZH_CHANGE_PAD: { // 直播垫片控制
const padObj = JSON.parse(this.lastLiveControl.data ?? "") as Record<string, string | number | boolean>
const showPad = padObj["showPad"] == "1"
this.liveDetailPageLogic.showPad = showPad
}
break
}
}
tryToPlay() {
if (!this.xComponentIsLoaded) {
... ...
import { LiveRoomItemBean } from 'wdBean/Index'
import { LiveMessageRole } from 'wdBean/src/main/ets/bean/live/LiveRoomBean'
import { LengthMetrics } from '@kit.ArkUI'
@Component
export struct ChatItemComponent {
... ... @@ -10,17 +12,23 @@ export struct ChatItemComponent {
build() {
Row() {
Text() {
// if (this.item.senderUserName) {
// Span(' 主持人 ')
// .fontSize(11)
// .lineHeight(20)
// .textBackgroundStyle({ color: '#808562', radius: 2 })
// Span(' ')
// }
if (this.item.role == LiveMessageRole.host) {
Span(' 主持人 ')
.fontSize(11)
.lineHeight(20)
.textBackgroundStyle({ color: "#70FFC63F", radius: 2 })
Span(' ')
}
if (this.item.role == LiveMessageRole.guest) {
Span(' 嘉宾 ')
.fontSize(11)
.lineHeight(20)
.textBackgroundStyle({ color: "#70FFC63F", radius: 2 })
Span(' ')
}
Span(this.item.senderUserName + ': ')
.fontColor('#FFFFC63F')
.padding({ right: 118 })
//
Span(this.item.text)
}
... ...
import { Action, ContentDetailDTO, LiveDetailsBean, LiveRoomDataBean, LiveRoomItemBean } from 'wdBean/Index'
import { LiveCommentComponent } from 'wdComponent/Index'
import { publishCommentModel } from 'wdComponent/src/main/ets/components/comment/model/PublishCommentModel'
import { LiveOperRowListView } from 'wdComponent'
import PageModel from 'wdComponent/src/main/ets/viewmodel/PageModel'
import { DisplayDirection, SpConstants, ViewType } from 'wdConstant/Index'
... ... @@ -25,8 +23,8 @@ export struct PlayerCommentComponent {
@Consume displayDirection: DisplayDirection
@State private pageModel: PageModel = new PageModel()
@State liveChatList: Array<LiveRoomItemBean> = []
@Consume @Watch("lastInputedCommentChagned") lastInputedComment: LiveRoomItemBean
@Consume @Watch('liveDetailsBeanChange') contentDetailData: ContentDetailDTO
@Consume publishCommentModel: publishCommentModel
scroller: Scroller = new Scroller()
async aboutToAppear(): Promise<void> {
... ... @@ -81,6 +79,16 @@ export struct PlayerCommentComponent {
})
}
lastInputedCommentChagned() {
Logger.debug(TAG, "2显示评论》》》: " + JSON.stringify(this.lastInputedComment))
this.liveChatList.push(this.lastInputedComment)
if (this.pageModel.viewType == ViewType.LOADED) {
this.scroller.scrollEdge(Edge.Bottom)
}
this.pageModel.viewType = ViewType.LOADED;
}
build() {
Column() {
Stack({ alignContent: Alignment.BottomStart }) {
... ...
... ... @@ -16,4 +16,6 @@ export { WDAliPlayerController } from "./src/main/ets/controller/WDAliPlayerCont
export { WDListPlayerData, WDAliListPlayerController } from "./src/main/ets/controller/WDAliListPlayerController"
export { AliPlayerRenderView } from "./src/main/ets/pages/AliPlayerRenderView"
\ No newline at end of file
export { AliPlayerRenderView } from "./src/main/ets/pages/AliPlayerRenderView"
export { BackgroundAudioController } from "./src/main/ets/controller/BackgroundAudioController"
\ No newline at end of file
... ...
import { Context, WantAgent, wantAgent } from '@kit.AbilityKit'
import { avSession as AVSessionManager } from '@kit.AVSessionKit'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'
import { BusinessError } from '@kit.BasicServicesKit'
import { Logger } from 'wdKit/Index'
import { PlayerConstants } from '../constants/PlayerConstants'
import { WDPlayerController } from './WDPlayerController'
import { image } from '@kit.ImageKit'
const TAG = "BackgroundAudioController"
export class BackgroundAudioController {
private static bgAudioController: BackgroundAudioController
private constructor() {
}
public static sharedController() {
if (!BackgroundAudioController.bgAudioController) {
BackgroundAudioController.bgAudioController = new BackgroundAudioController()
}
return BackgroundAudioController.bgAudioController
}
public gotContextFunc?: () => Context
public avplayerController?: WDPlayerController
private lastSession?: AVSessionManager.AVSession
private applyedLongTaskPlay: boolean = false
private lastProgress: number = 0.0
private hasSetupProgress: boolean = false
// 开始创建并激活媒体会话
// 创建session
async createSession() {
if (!this.gotContextFunc) { return }
if (this.lastSession == null) {
this.destorySession()
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(this.gotContextFunc(),'SESSION_NAME', type);
this.lastSession = session
}
// 激活接口要在元数据、控制命令注册完成之后再执行
await this.lastSession?.activate();
Logger.debug(TAG, `session create done : sessionId : ${this.lastSession?.sessionId}`);
this.lastProgress = 0
this.hasSetupProgress = false
}
destorySession() {
if (this.lastSession) {
this.lastSession.deactivate();
this.lastSession.destroy();
}
}
//设置播放元数据
setSessionMetaData(assetId: string, title: string, mediaImage: image.PixelMap | string, artist: string) {
Logger.debug(TAG, `SetAVMetadata assetId: ${assetId}}, title: ${title}, mediaImage: ${mediaImage}, artist: ${artist}`);
let metadata: AVSessionManager.AVMetadata = {
assetId: assetId.length > 0 ? assetId : "fake-asset-id",
title: title.length > 0 ? title : " ",
mediaImage: mediaImage,
artist: artist.length > 0 ? artist : "人日日报",
};
this.lastSession?.setAVMetadata(metadata).then(() => {
Logger.debug(TAG, `SetAVMetadata successfully`);
}).catch((err: BusinessError) => {
Logger.error(TAG, `Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
});
}
//设置播放状态
setSessionPlayStatus(playStatus: number) {
let playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY
switch (playStatus){
case PlayerConstants.STATUS_PAUSE: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE
} break
case PlayerConstants.STATUS_START: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY
} break
case PlayerConstants.STATUS_STOP: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_STOP
} break
case PlayerConstants.STATUS_ERROR: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_ERROR
} break
case PlayerConstants.STATUS_COMPLETION: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_COMPLETED
} break
default: {
playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_IDLE
} break
}
let playbackState: AVSessionManager.AVPlaybackState = {
state:playbackStatus,
// isFavorite:false
};
this.lastSession?.setAVPlaybackState(playbackState, (err: BusinessError) => {
if (err) {
Logger.error(TAG, `Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
} else {
Logger.debug(TAG, `SetAVPlaybackState 设置播放状态成功 ` + playStatus);
}
});
}
//设置进度,单位秒
setSessionPlayProgress(progressDuration: number, totalDuration: number) {
// Logger.debug(TAG, `set progress: ` + progressDuration + " duration: " + totalDuration);
if (totalDuration <= 0) {
return
}
let newProgress = progressDuration / totalDuration
if (Math.abs(newProgress - this.lastProgress) < 0.01) {
return
}
this.lastProgress = newProgress
if (this.hasSetupProgress) {
return
}
this.hasSetupProgress = true
Logger.debug(TAG, `set progress: ` + progressDuration + " duration: " + totalDuration);
// 设置状态: 播放状态,进度位置,播放倍速,缓存的时间
let playbackState: AVSessionManager.AVPlaybackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态
position: {
elapsedTime: progressDuration * 1000, // 已经播放的位置,以ms为单位
updateTime: new Date().getTime(), // 应用更新当前位置时的时间戳,以ms为单位
},
duration: totalDuration * 1000,
speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验
bufferedTime: totalDuration * 1000, // 可选,资源缓存的时间,以ms为单位
};
this.lastSession?.setAVPlaybackState(playbackState, (err) => {
if (err) {
Logger.error(TAG, `Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
} else {
Logger.debug(TAG, `SetAVPlaybackState successfully`);
}
});
}
// 置灰或禁用不支持的按钮
stopUseFeatures() {
// 取消指定session下的相关监听
// this.lastSession?.off('playFromAssetId');
// this.lastSession?.off('setSpeed');
// this.lastSession?.off('setLoopMode');
// this.lastSession?.off('toggleFavorite');
// this.lastSession?.off('skipToQueueItem');
// this.lastSession?.off('handleKeyEvent');
// this.lastSession?.off('commonCommand');
// this.lastSession?.off('rewind');
// this.lastSession?.off('fastForward');
}
listenPlayEvents() {
this.lastSession?.on('play', () => {
Logger.debug(TAG, `on play `);
this.avplayerController?.play()
this.hasSetupProgress = false
});
this.lastSession?.on('pause', () => {
Logger.debug(TAG, `on pause `);
this.avplayerController?.pause()
});
this.lastSession?.on('stop', () => {
Logger.debug(TAG, `on stop `);
this.avplayerController?.stop()
});
// this.lastSession?.on('playNext', () => {
// Logger.debug(TAG, `on playNext `);
// });
// this.lastSession?.on('playPrevious', () => {
// Logger.debug(TAG, `on playPrevious `);
// });
this.lastSession?.on('seek', (position: number) => {
Logger.debug(TAG, `on seek , the time is ${JSON.stringify(position)}`);
// 由于应用内seek可能会触发较长的缓冲等待,可以先把状态设置为 Buffering
let playbackState: AVSessionManager.AVPlaybackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // 缓冲状态
};
this.lastSession?.setAVPlaybackState(playbackState, (err) => {
if (err) {
Logger.debug(TAG, `Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
} else {
Logger.debug(TAG, `SetAVPlaybackState seek buffering`);
}
});
// 应用响应seek命令,使用应用内播放器完成seek实现
this.avplayerController?.setSeekTime(position * 0.001, SliderChangeMode.End)
this.hasSetupProgress = false
});
}
// 开启后台长时任务
startContinuousTask() {
if (this.applyedLongTaskPlay) {
return
}
let params: Record<string, string> = {
"title": "开始后台任务",
"content": "内容?",
// "pushLink": pushLink,
// "taskid": message.taskId,
// "messageId": message.messageId,
// "gtTransmitMsgLocalNotify": "1",
}
let wantAgentInfo: wantAgent.WantAgentInfo = {
// 点击通知后,将要执行的动作列表
// 添加需要被拉起应用的bundleName和abilityName
wants: [
{
deviceId: '',
bundleName: "com.peopledailychina.hosactivity",
abilityName: "EntryAbility",
// action: 'com.test.pushaction',
// entities: [],
// parameters:params,
}
],
// 指定点击通知栏消息后的动作是拉起ability
actionType: wantAgent.OperationType.START_ABILITY,
// 使用者自定义的一个私有值
requestCode: 0,
// 点击通知后,动作执行属性
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG],
};
// 通过wantAgent模块下getWantAgent方法获取WantAgent对象
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
if (!this.gotContextFunc) { return }
backgroundTaskManager.startBackgroundRunning(this.gotContextFunc(),
backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,
wantAgentObj).then(() => {
Logger.debug(TAG, `Succeeded in operationing startBackgroundRunning.`);
this.applyedLongTaskPlay = true
}).catch((err: BusinessError) => {
Logger.error(TAG, `Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
});
});
}
stopContinuousTask() {
if (!this.gotContextFunc) { return }
backgroundTaskManager.stopBackgroundRunning(this.gotContextFunc()).then(() => {
Logger.debug(TAG, `Succeeded in operationing stopBackgroundRunning.`);
}).catch((err: BusinessError) => {
Logger.error(TAG, `Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
});
this.applyedLongTaskPlay = false
}
}
\ No newline at end of file
... ...
import media from '@ohos.multimedia.media';
import prompt from '@ohos.promptAction';
import { Logger } from '../utils/Logger';
import { PlayerConstants, AVPlayerStatus, Events } from '../constants/PlayerConstants';
import { BusinessError } from '@ohos.base';
import { TrackingPlay } from 'wdTracking/Index';
import { ParamType } from 'wdTracking/Index';
import { DateTimeUtils } from 'wdKit/Index';
import { DateTimeUtils, Logger } from 'wdKit/Index';
import { BackgroundAudioController } from './BackgroundAudioController';
interface obj {
loop: boolean
}
const TAG = "WDPlayerController"
@Observed
export class WDPlayerController {
private initPromise: Promise<void>;
... ... @@ -41,7 +43,7 @@ export class WDPlayerController {
public xComponentController?: XComponentController
public videoWidth: number = 0
public videoHeight: number = 0
public keepOnBackground = false
... ... @@ -58,20 +60,20 @@ export class WDPlayerController {
*/
private createAVPlayer(): Promise<void> {
return new Promise((resolve, reject) => {
Logger.error("开始创建")
Logger.debug(TAG, "开始创建")
media.createAVPlayer().then((avPlayer) => {
if (avPlayer) {
Logger.error("创建完成1")
Logger.debug(TAG, "创建完成1")
this.avPlayer = avPlayer;
this.bindState();
resolve();
} else {
Logger.error("创建完成0")
Logger.error('[PlayVideoModel] createAvPlayer fail!');
Logger.error(TAG, "创建完成0")
Logger.error(TAG, '[PlayVideoModel] createAvPlayer fail!');
reject();
}
}).catch((error: BusinessError) => {
console.error(`AVPlayer catchCallback, error message:${error.message}`);
Logger.error(TAG, `AVPlayer catchCallback, error message:${error.message}`);
});
;
});
... ... @@ -143,10 +145,10 @@ export class WDPlayerController {
this.avPlayer.release();
this.status = PlayerConstants.STATUS_STOP;
this.watchStatus();
Logger.info('[PlayVideoModel] state released called')
Logger.info(TAG, '[PlayVideoModel] state released called')
break;
default:
Logger.info('[PlayVideoModel] unKnown state: ' + state);
Logger.info(TAG, '[PlayVideoModel] unKnown state: ' + state);
break;
}
});
... ... @@ -155,7 +157,7 @@ export class WDPlayerController {
});
this.avPlayer?.on(Events.ERROR, (error) => {
this.playError(error.message);
console.log('播放错误',JSON.stringify(error))
Logger.error(TAG, '播放错误' + JSON.stringify(error))
TrackingPlay.videoPlayError(error.message, this.pageName, this.pageName, this.pageParam)
})
this.avPlayer?.on('seekDone', (time: number) => {
... ... @@ -186,7 +188,7 @@ export class WDPlayerController {
this.url = url;
//加载时长prepareTime
this.creatStartTime = DateTimeUtils.getTimeStamp()
console.log('开始创建',JSON.stringify(this.creatStartTime))
Logger.debug(TAG, '开始创建' + JSON.stringify(this.creatStartTime))
this.prepareTime = 0
if(pageName){
this.pageName = pageName
... ... @@ -195,7 +197,7 @@ export class WDPlayerController {
this.pageParam = pageParam
}
if (this.avPlayer == null) {
console.log("等待")
Logger.debug(TAG, "等待")
this.initPromise = this.createAVPlayer();
await this.initPromise;
} else {
... ... @@ -209,13 +211,13 @@ export class WDPlayerController {
if (this.avPlayer == null) {
return
}
console.log("开始播放", this.url)
Logger.debug(TAG, "开始播放", this.url)
this.avPlayer.url = this.url;
//加载时长prepareTime
this.creatEndTime = DateTimeUtils.getTimeStamp()
this.prepareTime = 0
this.prepareTime = Math.floor((this.creatEndTime - this.creatStartTime)/1000)
console.log('开始播放2',JSON.stringify(this.prepareTime))
Logger.debug(TAG, '开始播放2',JSON.stringify(this.prepareTime))
}
async release() {
... ... @@ -237,6 +239,7 @@ export class WDPlayerController {
// if (this.avPlayer == null) {
// return
// }
Logger.debug(TAG, "start pause")
this.avPlayer?.pause();
}
... ... @@ -253,7 +256,7 @@ export class WDPlayerController {
async startRenderFrame(cb: Function) {
this.avPlayer?.on('startRenderFrame', () => {
cb && cb();
console.info('startRenderFrame success')
Logger.debug(TAG, 'startRenderFrame success')
})
}
... ... @@ -299,6 +302,7 @@ export class WDPlayerController {
// return
// }
if (this.status === PlayerConstants.STATUS_START) {
Logger.debug(TAG, "start pause 1111")
this.avPlayer?.pause();
} else {
this.avPlayer?.play();
... ... @@ -349,6 +353,11 @@ export class WDPlayerController {
this.currentPlayTime=Math.floor(time / 1000);
let nowSeconds = Math.floor(time / 1000);
let totalSeconds = Math.floor(this.duration / 1000);
if (this.keepOnBackground) {
BackgroundAudioController.sharedController().setSessionPlayProgress(time, this.duration)
}
if (this.onTimeUpdate) {
this.onTimeUpdate(time, this.duration);
}
... ... @@ -397,7 +406,7 @@ export class WDPlayerController {
if (this.onVolumeUpdate) {
this.onVolumeUpdate(this.volume);
}
console.log("volume : " + this.volume)
Logger.debug(TAG, "volume : " + this.volume)
}
onBrightActionUpdate(event: GestureEvent) {
... ... @@ -421,22 +430,27 @@ export class WDPlayerController {
}
watchStatus() {
console.log('watchStatus', this.status)
if (this.keepOnBackground) {
BackgroundAudioController.sharedController().setSessionPlayStatus(this.status)
}
Logger.debug(TAG, 'watchStatus ' + this.status)
if(this.status == PlayerConstants.STATUS_START){
console.log('播放视频')
console.log('播放视频prepareTime',JSON.stringify(this.prepareTime))
console.log('播放视频pageName',JSON.stringify(this.pageName))
console.log('播放视频pageParam',JSON.stringify(this.pageParam))
Logger.debug(TAG, '播放视频')
Logger.debug(TAG, '播放视频prepareTime' + JSON.stringify(this.prepareTime))
Logger.debug(TAG, '播放视频pageName' + JSON.stringify(this.pageName))
Logger.debug(TAG, '播放视频pageParam' + JSON.stringify(this.pageParam))
// 播放埋点
TrackingPlay.videoPositivePlay(Number(this.prepareTime),this.pageName, this.pageName, this.pageParam)
}
if(this.status == PlayerConstants.STATUS_COMPLETION){
let initDuration = Math.floor(Number(this.duration)/1000)
console.log('播放结束')
console.log('播放结束currentPlayTime',JSON.stringify(this.currentPlayTime))
console.log('播放结束initDuration',JSON.stringify(initDuration))
console.log('播放结束pageName',JSON.stringify(this.pageName))
console.log('播放结束pageParam',JSON.stringify(this.pageParam))
Logger.debug(TAG, '播放结束')
Logger.debug(TAG, '播放结束currentPlayTime' + JSON.stringify(this.currentPlayTime))
Logger.debug(TAG, '播放结束initDuration' + JSON.stringify(initDuration))
Logger.debug(TAG, '播放结束pageName' + JSON.stringify(this.pageName))
Logger.debug(TAG, '播放结束pageParam' + JSON.stringify(this.pageParam))
// 播放结束埋点
TrackingPlay.videoPlayEnd(this.currentPlayTime, initDuration, this.currentPlayTime, this.pageName, this.pageName, this.pageParam)
}
... ...
... ... @@ -88,7 +88,8 @@ struct Index {
onPageHide() {
// this.status = PlayerConstants.STATUS_PAUSE;
this.AudioSuspension.playerController.get()?.pause();
console.info('onPageHide');
// this.AudioSuspension.playerController.get()?.pause();
}
build() {
... ...
... ... @@ -22,6 +22,7 @@ import { webview } from '@kit.ArkWeb'
import { NewspaperWidgetCommon } from '../dailynewspaperwidget/common/NewspaperWidgetCommon'
import { LiveRoomManager } from 'wdDetailPlayLive/Index'
import { initGlobalPlayerSettings } from 'wdPlayer/src/main/ets/utils/GlobalSetting'
import { BackgroundAudioController } from 'wdPlayer/Index'
const TAG = "[StartupManager]"
... ... @@ -115,6 +116,8 @@ export class StartupManager {
this.initAuthLogin()
this.initLiveChatRoom()
this.initBackgroundAudioTask()
Logger.debug(TAG, "App 必要初始化完成")
}
... ... @@ -210,6 +213,12 @@ export class StartupManager {
}
}
private initBackgroundAudioTask() {
BackgroundAudioController.sharedController().gotContextFunc = () => {
return StartupManager.sharedInstance().context!
}
}
private initThirdPlatformSDK() {
}
... ...
... ... @@ -24,6 +24,9 @@
"startWindowIcon": "$media:app_icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"backgroundModes": [
"audioPlayback"
],
"skills": [
{
"entities": [
... ... @@ -33,6 +36,8 @@
"action.system.home",
"com.test.pushaction"
],
},
{
"uris": [
{
"scheme": 'rmrbapp',
... ... @@ -40,7 +45,7 @@
'port': '8080',
"path": 'openwith'
}
]
],
}
]
}
... ... @@ -103,6 +108,16 @@
}
},
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
"reason": "$string:permission_background_audio",
"usedScene": {
"abilities": [
"FormAbility"
],
"when": "always"
}
},
{
"name": "ohos.permission.INTERNET"
},
],
... ...
... ... @@ -29,6 +29,10 @@
"value": "开启之后即可用于收录声音进行拍摄视频、语音搜索、语音评论功能,"
},
{
"name": "permission_background_audio",
"value": "开启之后即可用于后台音频播放"
},
{
"name": "dialog_text_title",
"value": "个人隐私保护指引"
},
... ...