import { media } from '@kit.MediaKit'
import { MusicInfo } from '../bean/MusicInfo'
import { AvSessionManager } from './AvSessionManager'
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'
import { wantAgent } from '@kit.AbilityKit'
import { LogUtils } from './LogUtils'
import hilog from '@ohos.hilog'
import { MusicUtils } from './MusicUtils'
import { Event_Hub_Duration_Updata, Event_Hub_Video_Time_Updata } from './Constants'
import { emitter } from '@kit.BasicServicesKit'
export class AvPlayerManager{
public static player:media.AVPlayer|null=null
static currentMusic:MusicInfo=new MusicInfo()
static musics:MusicInfo[]=MusicUtils.getMusics()
static id:string='-1'
static isPlaying:boolean=false
static async init(){
if (!AvPlayerManager.player) {
AvPlayerManager.player=await media.createAVPlayer()
}
AvPlayerManager.player.on('stateChange',(state)=>{
switch (state){
case 'initialized':
AvPlayerManager.player?.prepare()
break
case 'prepared':
AvPlayerManager.player?.play()
AvPlayerManager.isPlaying=true
break
case 'completed':
AvPlayerManager.nextMusic()
LogUtils.e('completed')
break
}
})
AvPlayerManager.player.on('durationUpdate',(duration)=>{
AvPlayerManager.currentMusic.duration=duration
AvSessionManager.sendAvMetaData(AvPlayerManager.currentMusic)
emitter.emit(Event_Hub_Duration_Updata,{data:duration})
})
AvPlayerManager.player.on('timeUpdate',(time)=>{
AvPlayerManager.currentMusic.time=time
emitter.emit(Event_Hub_Video_Time_Updata,{data:time})
})
AvPlayerManager.player.on('error',(time)=>{
})
}
static play(song:MusicInfo){
AvPlayerManager.startBackgroundTask()
AvPlayerManager.player!.url=song.url
}
/**
* 样式调试
* */
static playRaw(){
// AvPlayerManager.startBackgroundTask()
// let mp3=getContext().createModuleContext('entry').resourceManager.getRawFdSync('like.MP3')
let mp3=getContext().createModuleContext('basic').resourceManager.getRawFdSync('like.mp3')
let avFileDescriptor: media.AVFileDescriptor =
{ fd: mp3.fd, offset: mp3.offset, length: mp3.length };
AvPlayerManager.player!.fdSrc=avFileDescriptor
}
/**
* 可用
* */
static async playRawWithName(name:string,id:string){
// AvPlayerManager.startBackgroundTask()
if (AvPlayerManager.id!='-1'){
if (id===AvPlayerManager.id) {
return
}
await AvPlayerManager.player?.reset()
}
let mp3=await getContext().createModuleContext('basic').resourceManager.getRawFd(name+'.mp3')
AvPlayerManager.id=id
AvPlayerManager.currentMusic.name=name
let avFileDescriptor: media.AVFileDescriptor =
{ fd: mp3.fd, offset: mp3.offset, length: mp3.length };
AvPlayerManager.player!.fdSrc=avFileDescriptor
}
static playUrl(song:string){
// AvPlayerManager.startBackgroundTask()
AvPlayerManager.player!.url=song
}
static pause(){
AvPlayerManager.player?.pause()
}
static continue(){
AvPlayerManager.player?.play()
}
static seekProgress(time:number){
AvPlayerManager.player?.seek(time)
}
static async upMusic(){
let position=AvPlayerManager.getCurrentPosition(AvPlayerManager.id)
if (position>0) {
position--
}else {
position=AvPlayerManager.musics.length-1
}
let music=AvPlayerManager.musics[position]
await AvPlayerManager.playRawWithName(music.name,music.id)
}
/**
* 自动下一个
* */
static async nextMusic(){
let position=AvPlayerManager.getCurrentPosition(AvPlayerManager.id)
if (position + 1 < AvPlayerManager.musics.length) {
position=position+1
}else {
position=0
}
let music=AvPlayerManager.musics[position]
await AvPlayerManager.playRawWithName(music.name,music.id)
}
static getCurrentMusic(){
for (let i = 0; i < AvPlayerManager.musics.length; i++) {
if (AvPlayerManager.musics[i].id===AvPlayerManager.id) {
return AvPlayerManager.musics[i]
}
}
return AvPlayerManager.musics[0]
}
static getMusicWithId(id:string){
for (let i = 0; i < AvPlayerManager.musics.length; i++) {
if (AvPlayerManager.musics[i].id===id) {
return AvPlayerManager.musics[i]
}
}
return null
}
static getCurrentPosition(id:string){
for (let i = 0; i < AvPlayerManager.musics.length; i++) {
if (AvPlayerManager.musics[i].id===id) {
return i
}
}
return 0
}
// 开启后台长时间任务,,播放的时候调用
static async startBackgroundTask(){
// 如果已经存在,就表示开启了后台任务
if (AvSessionManager.session.sessionId){
return
}
// want的信息,作用:当点击播控中心的时候,会跳转到app中来
let wantAgentInfo: wantAgent.WantAgentInfo = {
wants: [
{
bundleName: 'com.zhangjian.myapplication',//包名
abilityName: 'EntryAbility' }
],
operationType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
}
let want=await wantAgent.getWantAgent(wantAgentInfo)
// 申请长时间任务
await backgroundTaskManager.startBackgroundRunning(getContext(),
backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK,
want
)
}
}
音乐播放主界面:
import {
AvPlayerManager,
Event_Hub_Duration_Updata,
Event_Hub_Video_Time_Updata,
MusicInfo
} from '@zjian/basic'
import { Animator, AnimatorResult, router } from '@kit.ArkUI'
import { LogUtils } from '@zjian/basic/src/main/ets/utils/LogUtils'
import { emitter } from '@kit.BasicServicesKit'
@Component
export struct MusicDetailPage {
@State item: MusicInfo = new MusicInfo()
@State imgWidth: number = 2000
@State isPlay: boolean = true
@State angle: number = 0
@State duration: string = '00:00'
@State currentTime: string = '00:00'
@State durationProgress: number = 0
@State currentProgress: number = 0
@State isNext: boolean = false
animatorResult: AnimatorResult = Animator.create({
duration: 1000 * 30,
easing: "linear",
delay: 0,
fill: "none",
direction: "normal",
iterations: -1,
begin: 0,
end: 360
})
managerDuration(dur:number){
this.durationProgress = dur
if (dur > 0) {
if (this.isNext) {
this.animatorResult.finish()
this.animatorResult.play()
let music = AvPlayerManager.getCurrentMusic()
this.item = music
this.isNext = false
}
dur = dur / 1000
let second = Math.floor(dur / 60).toString().padStart(2, '0')
let min = Math.floor(dur % 60).toString().padStart(2, '0')
this.duration = second + ':' + min
}
}
aboutToAppear(): void {
this.managerDuration(this.item.duration)
this.animatorResult.play()
this.animatorResult.onFrame = (val) => {
this.angle = val
}
// 继续播放进入以后,就不会读到duration的信息
emitter.on(Event_Hub_Duration_Updata, (duration)=>{
let dur:number=Number(duration.data)
this.managerDuration(dur)
})
emitter.on(Event_Hub_Video_Time_Updata, (data)=>{
let time=Number(data.data)
if (time === this.durationProgress) {
this.isNext = true
}
this.currentProgress = time
if (time > 0) {
time = time / 1000
let second = Math.floor(time / 60).toString().padStart(2, '0')
let min = Math.floor(time % 60).toString().padStart(2, '0')
this.currentTime = second + ':' + min
}
})
}
aboutToDisappear(): void {
emitter.off(Event_Hub_Duration_Updata)
emitter.off(Event_Hub_Video_Time_Updata)
}
build() {
Column() {
Row() {
Row() {
Image($rawfile('ic_back.png'))
.height(25).aspectRatio(1)
}.height(35).aspectRatio(1)
.justifyContent(FlexAlign.Start)
.onClick(() => {
router.back()
})
Text().layoutWeight(1)
Row({ space: 10 }) {
Text('推荐').fontColor($r('app.color.grey')).fontSize(18)
Image('').backgroundColor(Color.Grey).height(8).width(2).borderRadius(2)
Text('歌曲').fontColor(Color.White).fontSize(18)
Image('').backgroundColor(Color.Grey).height(8).width(2).borderRadius(2)
Text('歌词').fontColor($r('app.color.grey')).fontSize(18)
}
Text().layoutWeight(1)
Image($rawfile('ic_share_white.png')).height(30).aspectRatio(1)
}
.margin({
top: 10
})
.width('100%')
Row() {
Image(this.item.image)
.width('100%')
.aspectRatio(1)
.borderRadius((this.imgWidth))
.backgroundImageSize(ImageSize.Cover)
.shadow({
radius: 30,
color: Color.Black
})
.rotate({
angle: this.angle
})
}
.width('100%')
.aspectRatio(1)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
// .padding(10)
.margin({
top: 20
})
Text(this.item.name)
.fontColor(Color.White)
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({
top: 20
})
Row() {
Text('林俊杰 专辑:' + this.item.artisc)
.fontColor($r('app.color.grey'))
.fontSize(17)
Text('VIP')
.fontSize(11)
.fontColor($r('app.color.grey'))
.border({
width: 1,
color: Color.Grey,
})
.borderRadius(2)
.padding({
left: 2,
right: 2
})
.margin({
left: 10
})
}
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.margin({
top: 20
})
Slider({
min: 0,
max: this.durationProgress,
value: this.currentProgress,
step: 1,
style: SliderStyle.OutSet
})
.blockColor(Color.White)//进度条的控制色值
.selectedColor(Color.White)//进度条的左边色值
.trackColor($r('app.color.grey'))//进度条的右边色值
.trackThickness(2)//进度条控制按钮的长度
.onChange((value, model) => {
LogUtils.e('onChange value:'+model.toString())
if (model === SliderChangeMode.End) {
// AvPlayerManager.seekProgress(value)
}
})
.margin({
top: 125
})
Row() {
Text(this.currentTime)
.fontColor($r('app.color.grey'))
.fontSize(12)
.fontWeight(FontWeight.Bold)
Text(this.duration + '')
.fontColor($r('app.color.grey'))
.fontSize(12)
.fontWeight(FontWeight.Bold)
}
.width('100%').justifyContent(FlexAlign.SpaceBetween)
Column() {
Row() {
Image($rawfile('ic_loop.png'))
.width(30).aspectRatio(1)
Image($rawfile('ic_up.png'))
.width(30).aspectRatio(1)
.onClick(() => {
this.isNext = true
AvPlayerManager.upMusic()
})
Image(this.isPlay ? $rawfile('ic_play.png') : $rawfile('ic_pause.png'))
.width(60).aspectRatio(1)
.onClick(() => {
if (this.isPlay) {
this.animatorResult.pause()
AvPlayerManager.pause()
} else {
this.animatorResult.play()
AvPlayerManager.continue()
}
this.isPlay = !this.isPlay
})
Image($rawfile('ic_up.png')).rotate({
angle: 180
})
.width(30).aspectRatio(1)
.onClick(() => {
this.isNext = true
AvPlayerManager.nextMusic()
})
Image($rawfile('ic_music.png'))
.width(30).aspectRatio(1)
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}.margin({
top: 10
})
.width('100%')
.justifyContent(FlexAlign.Center)
}
.alignItems(HorizontalAlign.Start)
.backgroundColor($r('app.color.black01'))
.width('100%')
.height('100%')
.padding({
right: 30,
left: 30
})
}
}