|
@@ -1,7 +1,8 @@
|
|
|
-import { common, Context } from '@kit.AbilityKit'
|
|
|
|
|
|
|
+import { common, Context, wantAgent, Want } from '@kit.AbilityKit'
|
|
|
import { BusinessError } from '@kit.BasicServicesKit'
|
|
import { BusinessError } from '@kit.BasicServicesKit'
|
|
|
import { avSession } from '@kit.AVSessionKit'
|
|
import { avSession } from '@kit.AVSessionKit'
|
|
|
-import { PreferencesUtil } from '@pura/harmony-utils'
|
|
|
|
|
|
|
+import { image } from '@kit.ImageKit'
|
|
|
|
|
+import { FileUtil, ImageUtil, PreferencesUtil, StrUtil } from '@pura/harmony-utils'
|
|
|
import {
|
|
import {
|
|
|
DeviceChangeReason,
|
|
DeviceChangeReason,
|
|
|
InterruptEvent,
|
|
InterruptEvent,
|
|
@@ -16,9 +17,11 @@ import {
|
|
|
} from '../common/IjkPlayerListenerImpls'
|
|
} from '../common/IjkPlayerListenerImpls'
|
|
|
import { PlayStatus } from '../common/PlayStatus'
|
|
import { PlayStatus } from '../common/PlayStatus'
|
|
|
import { MusicCardActionConstants } from '../common/player/MusicCardActionConstants'
|
|
import { MusicCardActionConstants } from '../common/player/MusicCardActionConstants'
|
|
|
|
|
+import { isPlaybackControlPlaying } from '../common/player/PlaybackControlStateHelper'
|
|
|
import { MusicCardManager, MusicCardPlaybackStateOptions } from '../common/player/MusicCardManager'
|
|
import { MusicCardManager, MusicCardPlaybackStateOptions } from '../common/player/MusicCardManager'
|
|
|
import { BackgroundTaskManager } from '../common/util/BackgroundTaskManager'
|
|
import { BackgroundTaskManager } from '../common/util/BackgroundTaskManager'
|
|
|
import Logger from '../common/util/Logger'
|
|
import Logger from '../common/util/Logger'
|
|
|
|
|
+import { imagePathToPixelMap } from '../common/util/CommUtils'
|
|
|
import { setVideoUrlForSong } from '../common/util/RemotePlayerUtil'
|
|
import { setVideoUrlForSong } from '../common/util/RemotePlayerUtil'
|
|
|
import { MusicPlaybackController } from '../controller/MusicPlaybackController'
|
|
import { MusicPlaybackController } from '../controller/MusicPlaybackController'
|
|
|
import { PlaybackRuntime } from '../controller/PlaybackCoordinator'
|
|
import { PlaybackRuntime } from '../controller/PlaybackCoordinator'
|
|
@@ -59,6 +62,7 @@ export class BackgroundAudioPlaybackHost {
|
|
|
private playbackStartVerifyToken: number = 0
|
|
private playbackStartVerifyToken: number = 0
|
|
|
private playbackSession: avSession.AVSession | undefined = undefined
|
|
private playbackSession: avSession.AVSession | undefined = undefined
|
|
|
private creatingPlaybackSession: boolean = false
|
|
private creatingPlaybackSession: boolean = false
|
|
|
|
|
+ private playbackSessionCallbacksRegistered: boolean = false
|
|
|
private snapshotStore: PlaybackSnapshotWriter = new PlaybackSnapshotStore()
|
|
private snapshotStore: PlaybackSnapshotWriter = new PlaybackSnapshotStore()
|
|
|
private readonly runtime: PlaybackRuntime = {
|
|
private readonly runtime: PlaybackRuntime = {
|
|
|
playQueue: async (queue: VideoItem[], startIndex: number, source: string, playType?: number): Promise<void> => {
|
|
playQueue: async (queue: VideoItem[], startIndex: number, source: string, playType?: number): Promise<void> => {
|
|
@@ -73,6 +77,9 @@ export class BackgroundAudioPlaybackHost {
|
|
|
playPrevious: async (): Promise<void> => {
|
|
playPrevious: async (): Promise<void> => {
|
|
|
await this.playPrevious()
|
|
await this.playPrevious()
|
|
|
},
|
|
},
|
|
|
|
|
+ setLoopMode: async (): Promise<void> => {
|
|
|
|
|
+ await this.setLoopMode()
|
|
|
|
|
+ },
|
|
|
seekTo: async (value: string): Promise<void> => {
|
|
seekTo: async (value: string): Promise<void> => {
|
|
|
await this.seekTo(value)
|
|
await this.seekTo(value)
|
|
|
}
|
|
}
|
|
@@ -133,6 +140,29 @@ export class BackgroundAudioPlaybackHost {
|
|
|
await this.handleControlAction(MusicCardActionConstants.ACTION_SEEK_TO, value)
|
|
await this.handleControlAction(MusicCardActionConstants.ACTION_SEEK_TO, value)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ public async setLoopMode(): Promise<void> {
|
|
|
|
|
+ this.restorePersistedQueueIfNeeded()
|
|
|
|
|
+ const nextMode = MusicPlaybackController.resolveNextLoopMode(this.playType)
|
|
|
|
|
+ this.playType = nextMode.playType
|
|
|
|
|
+ PreferencesUtil.putSync('musicPlayType', this.playType)
|
|
|
|
|
+ this.persistCurrentQueue()
|
|
|
|
|
+ this.syncHostStorage(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
|
|
+ this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
|
|
+ this.persistPlaybackSnapshot(this.isPlaying)
|
|
|
|
|
+ Logger.info(TAG, `[MusicCast] setLoopMode playType=${this.playType}, toast=${nextMode.toastText}`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public syncCurrentSongFavoriteState(isFavorite: boolean): void {
|
|
|
|
|
+ this.applyCurrentSongFavoriteState(isFavorite)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public getSpectrumData(): number[] {
|
|
|
|
|
+ if (!this.player) {
|
|
|
|
|
+ return []
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.player.getSpectrumData()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public async handleControlAction(action: string, seekPositionMs: string = ''): Promise<boolean> {
|
|
public async handleControlAction(action: string, seekPositionMs: string = ''): Promise<boolean> {
|
|
|
try {
|
|
try {
|
|
|
Logger.info(TAG,
|
|
Logger.info(TAG,
|
|
@@ -473,7 +503,7 @@ export class BackgroundAudioPlaybackHost {
|
|
|
this.currentSong.lyricContent,
|
|
this.currentSong.lyricContent,
|
|
|
this.currentSong.pixelMapPath
|
|
this.currentSong.pixelMapPath
|
|
|
)
|
|
)
|
|
|
- AppStorage.setOrCreate('progressValue', progressValue)
|
|
|
|
|
|
|
+ this.syncPlaybackDisplayState(progressValue, positionMs, durationMs)
|
|
|
this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
this.persistPlaybackSnapshot(this.isPlaying)
|
|
this.persistPlaybackSnapshot(this.isPlaying)
|
|
|
}
|
|
}
|
|
@@ -500,6 +530,8 @@ export class BackgroundAudioPlaybackHost {
|
|
|
const err = error as BusinessError
|
|
const err = error as BusinessError
|
|
|
Logger.error(TAG, `[MusicCast] playbackSession activate failed code=${err.code}, message=${err.message}`)
|
|
Logger.error(TAG, `[MusicCast] playbackSession activate failed code=${err.code}, message=${err.message}`)
|
|
|
}
|
|
}
|
|
|
|
|
+ await this.setPlaybackSessionLaunchAbility(abilityContext, session)
|
|
|
|
|
+ this.registerPlaybackSessionCallbacks(session)
|
|
|
await this.syncPlaybackSessionMetadata()
|
|
await this.syncPlaybackSessionMetadata()
|
|
|
this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
@@ -510,15 +542,94 @@ export class BackgroundAudioPlaybackHost {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private async setPlaybackSessionLaunchAbility(abilityContext: common.UIAbilityContext,
|
|
|
|
|
+ session: avSession.AVSession): Promise<void> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const want = new Want()
|
|
|
|
|
+ want.bundleName = abilityContext.abilityInfo.bundleName
|
|
|
|
|
+ want.abilityName = abilityContext.abilityInfo.name
|
|
|
|
|
+ const wantAgentInfo: wantAgent.WantAgentInfo = {
|
|
|
|
|
+ wants: [want],
|
|
|
|
|
+ operationType: wantAgent.OperationType.START_ABILITIES,
|
|
|
|
|
+ requestCode: 0,
|
|
|
|
|
+ wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
|
|
|
|
|
+ }
|
|
|
|
|
+ const agent = await wantAgent.getWantAgent(wantAgentInfo)
|
|
|
|
|
+ await session.setLaunchAbility(agent)
|
|
|
|
|
+ Logger.info(TAG, '[MusicCast] playbackSession launchAbility attached')
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ const err = error as BusinessError
|
|
|
|
|
+ Logger.error(TAG, `[MusicCast] playbackSession launchAbility failed code=${err.code}, message=${err.message}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private registerPlaybackSessionCallbacks(session: avSession.AVSession): void {
|
|
|
|
|
+ if (this.playbackSessionCallbacksRegistered) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ session.on('play', () => {
|
|
|
|
|
+ void this.handlePlaybackSessionPlay()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('pause', () => {
|
|
|
|
|
+ this.handlePlaybackSessionPause()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('stop', () => {
|
|
|
|
|
+ this.handlePlaybackSessionStop()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('playNext', () => {
|
|
|
|
|
+ void this.playNext()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('playPrevious', () => {
|
|
|
|
|
+ void this.playPrevious()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('seek', (time: number) => {
|
|
|
|
|
+ void this.seekTo(`${time}`)
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('setLoopMode', (_mode: number) => {
|
|
|
|
|
+ void this.setLoopMode()
|
|
|
|
|
+ })
|
|
|
|
|
+ session.on('toggleFavorite', (_assetId: string) => {
|
|
|
|
|
+ this.toggleCurrentSongFavoriteState()
|
|
|
|
|
+ })
|
|
|
|
|
+ this.playbackSessionCallbacksRegistered = true
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private async handlePlaybackSessionPlay(): Promise<void> {
|
|
|
|
|
+ this.restorePersistedQueueIfNeeded()
|
|
|
|
|
+ if (this.isPrepared && !this.isPlaying) {
|
|
|
|
|
+ this.resume()
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.currentIndex >= 0) {
|
|
|
|
|
+ await this.playIndex(this.currentIndex)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.queue.length > 0) {
|
|
|
|
|
+ await this.playIndex(0)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private handlePlaybackSessionPause(): void {
|
|
|
|
|
+ if (this.isPlaying) {
|
|
|
|
|
+ this.pause()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private handlePlaybackSessionStop(): void {
|
|
|
|
|
+ this.stop()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private async syncPlaybackSessionMetadata(): Promise<void> {
|
|
private async syncPlaybackSessionMetadata(): Promise<void> {
|
|
|
if (!this.playbackSession || !this.currentSong) {
|
|
if (!this.playbackSession || !this.currentSong) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
|
|
+ const mediaImage = await this.resolvePlaybackSessionMediaImage()
|
|
|
let metadata: avSession.AVMetadata = {
|
|
let metadata: avSession.AVMetadata = {
|
|
|
assetId: this.currentSong.filePath ?? this.currentSong.name ?? '',
|
|
assetId: this.currentSong.filePath ?? this.currentSong.name ?? '',
|
|
|
title: this.currentSong.name,
|
|
title: this.currentSong.name,
|
|
|
artist: this.currentSong.artist,
|
|
artist: this.currentSong.artist,
|
|
|
|
|
+ mediaImage: mediaImage,
|
|
|
duration: this.resolveDurationMs()
|
|
duration: this.resolveDurationMs()
|
|
|
}
|
|
}
|
|
|
await this.playbackSession.setAVMetadata(metadata)
|
|
await this.playbackSession.setAVMetadata(metadata)
|
|
@@ -530,6 +641,22 @@ export class BackgroundAudioPlaybackHost {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private async resolvePlaybackSessionMediaImage(): Promise<image.PixelMap | string> {
|
|
|
|
|
+ const coverPath = this.currentSong?.pixelMapPath ?? ''
|
|
|
|
|
+ if (StrUtil.isNotEmpty(coverPath)) {
|
|
|
|
|
+ if (coverPath.startsWith('http://') || coverPath.startsWith('https://')) {
|
|
|
|
|
+ return coverPath
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const localCoverPath = coverPath.startsWith('file://') ? FileUtil.getFilePath(coverPath) : coverPath
|
|
|
|
|
+ return await imagePathToPixelMap(localCoverPath)
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ Logger.warn(TAG, `[MusicCast] cover pixelMap failed path=${coverPath}, message=${(error as Error).message}`)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return await ImageUtil.getPixelMapFromMedia($r('app.media.alt'))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private syncPlaybackSessionState(status: number): void {
|
|
private syncPlaybackSessionState(status: number): void {
|
|
|
if (!this.playbackSession || !this.player) {
|
|
if (!this.playbackSession || !this.player) {
|
|
|
return
|
|
return
|
|
@@ -544,6 +671,8 @@ export class BackgroundAudioPlaybackHost {
|
|
|
}
|
|
}
|
|
|
let playbackState: avSession.AVPlaybackState = {
|
|
let playbackState: avSession.AVPlaybackState = {
|
|
|
state: state,
|
|
state: state,
|
|
|
|
|
+ loopMode: MusicPlaybackController.resolveAvSessionLoopMode(this.playType),
|
|
|
|
|
+ isFavorite: this.currentSong?.isFav === 1,
|
|
|
position: {
|
|
position: {
|
|
|
elapsedTime: Math.max(0, this.player.getCurrentPosition()),
|
|
elapsedTime: Math.max(0, this.player.getCurrentPosition()),
|
|
|
updateTime: Date.now()
|
|
updateTime: Date.now()
|
|
@@ -604,7 +733,12 @@ export class BackgroundAudioPlaybackHost {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private persistPlaybackSnapshot(isPlaying: boolean): void {
|
|
private persistPlaybackSnapshot(isPlaying: boolean): void {
|
|
|
- this.snapshotStore.write(this.buildPlaybackSnapshot(isPlaying))
|
|
|
|
|
|
|
+ const snapshot = this.buildPlaybackSnapshot(isPlaying)
|
|
|
|
|
+ Logger.info(TAG,
|
|
|
|
|
+ `[MiniState] persistPlaybackSnapshot song=${snapshot.currentSongName}, index=${snapshot.currentIndex}, ` +
|
|
|
|
|
+ `isPlaying=${snapshot.isPlaying}, shouldResume=${snapshot.shouldResumeWhenActivated}, ` +
|
|
|
|
|
+ `position=${snapshot.positionMs}, duration=${snapshot.durationMs}`)
|
|
|
|
|
+ this.snapshotStore.write(snapshot)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private buildPlaybackSnapshot(isPlaying: boolean): PlaybackSnapshot {
|
|
private buildPlaybackSnapshot(isPlaying: boolean): PlaybackSnapshot {
|
|
@@ -615,6 +749,7 @@ export class BackgroundAudioPlaybackHost {
|
|
|
id: item.id,
|
|
id: item.id,
|
|
|
type: item.type,
|
|
type: item.type,
|
|
|
name: item.name,
|
|
name: item.name,
|
|
|
|
|
+ isFav: item.isFav,
|
|
|
artist: item.artist,
|
|
artist: item.artist,
|
|
|
album: item.album,
|
|
album: item.album,
|
|
|
duration: item.duration,
|
|
duration: item.duration,
|
|
@@ -671,19 +806,25 @@ export class BackgroundAudioPlaybackHost {
|
|
|
PreferencesUtil.putSync('LastMusicInfo', this.currentSong)
|
|
PreferencesUtil.putSync('LastMusicInfo', this.currentSong)
|
|
|
PreferencesUtil.putSync('LastMusicList', this.queue)
|
|
PreferencesUtil.putSync('LastMusicList', this.queue)
|
|
|
PreferencesUtil.putSync('LastPlayModeType', this.playType)
|
|
PreferencesUtil.putSync('LastPlayModeType', this.playType)
|
|
|
|
|
+ PreferencesUtil.putSync('musicPlayType', this.playType)
|
|
|
Logger.info(TAG,
|
|
Logger.info(TAG,
|
|
|
`[MusicCast] persist queueLength=${this.queue.length}, currentIndex=${this.currentIndex}, ` +
|
|
`[MusicCast] persist queueLength=${this.queue.length}, currentIndex=${this.currentIndex}, ` +
|
|
|
`currentSong=${this.currentSong?.name ?? ''}, path=${this.currentSong?.filePath ?? ''}, playType=${this.playType}`)
|
|
`currentSong=${this.currentSong?.name ?? ''}, path=${this.currentSong?.filePath ?? ''}, playType=${this.playType}`)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private syncHostStorage(status: PlayStatus): void {
|
|
private syncHostStorage(status: PlayStatus): void {
|
|
|
|
|
+ const isPlaying = isPlaybackControlPlaying(status)
|
|
|
|
|
+ const positionMs = this.player ? Math.max(0, this.player.getCurrentPosition()) : 0
|
|
|
|
|
+ const durationMs = this.resolveDurationMs()
|
|
|
|
|
+ const progressValue = resolvePlaybackSnapshotProgressValue(positionMs, durationMs, 100)
|
|
|
AppStorage.setOrCreate('CONTROL_PlayStatus', status)
|
|
AppStorage.setOrCreate('CONTROL_PlayStatus', status)
|
|
|
|
|
+ AppStorage.setOrCreate('isPlaying', isPlaying)
|
|
|
|
|
+ AppStorage.setOrCreate('animationState', isPlaying ? AnimationStatus.Running : AnimationStatus.Paused)
|
|
|
|
|
+ AppStorage.setOrCreate('musicPlayType', this.playType)
|
|
|
AppStorage.setOrCreate('songList', this.queue)
|
|
AppStorage.setOrCreate('songList', this.queue)
|
|
|
AppStorage.setOrCreate('currIndex', this.currentIndex)
|
|
AppStorage.setOrCreate('currIndex', this.currentIndex)
|
|
|
AppStorage.setOrCreate('currentSong', this.currentSong)
|
|
AppStorage.setOrCreate('currentSong', this.currentSong)
|
|
|
- AppStorage.setOrCreate('progressValue',
|
|
|
|
|
- resolvePlaybackSnapshotProgressValue(this.player ? Math.max(0, this.player.getCurrentPosition()) : 0,
|
|
|
|
|
- this.resolveDurationMs(), 100))
|
|
|
|
|
|
|
+ this.syncPlaybackDisplayState(progressValue, positionMs, durationMs)
|
|
|
AppStorage.setOrCreate('cover', this.currentSong?.pixelMapPath ?? '')
|
|
AppStorage.setOrCreate('cover', this.currentSong?.pixelMapPath ?? '')
|
|
|
AppStorage.setOrCreate('currentSongName', this.currentSong?.name ?? '')
|
|
AppStorage.setOrCreate('currentSongName', this.currentSong?.name ?? '')
|
|
|
AppStorage.setOrCreate('currentSongArtist', this.currentSong?.artist ?? '')
|
|
AppStorage.setOrCreate('currentSongArtist', this.currentSong?.artist ?? '')
|
|
@@ -691,4 +832,32 @@ export class BackgroundAudioPlaybackHost {
|
|
|
`[MusicCast] syncHostStorage status=${status}, currentSong=${this.currentSong?.name ?? ''}, ` +
|
|
`[MusicCast] syncHostStorage status=${status}, currentSong=${this.currentSong?.name ?? ''}, ` +
|
|
|
`cover=${this.currentSong?.pixelMapPath ?? ''}`)
|
|
`cover=${this.currentSong?.pixelMapPath ?? ''}`)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ private syncPlaybackDisplayState(progressValue: number, positionMs: number, durationMs: number): void {
|
|
|
|
|
+ AppStorage.setOrCreate('progressValue', progressValue)
|
|
|
|
|
+ AppStorage.setOrCreate('playbackPositionMs', positionMs)
|
|
|
|
|
+ AppStorage.setOrCreate('playbackDurationMs', durationMs)
|
|
|
|
|
+ AppStorage.setOrCreate('playbackIsFavorite', this.currentSong?.isFav === 1)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private toggleCurrentSongFavoriteState(): void {
|
|
|
|
|
+ const nextFavorite = this.currentSong?.isFav !== 1
|
|
|
|
|
+ this.applyCurrentSongFavoriteState(nextFavorite)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private applyCurrentSongFavoriteState(isFavorite: boolean): void {
|
|
|
|
|
+ if (!this.currentSong) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ const nextFavorite = isFavorite ? 1 : 0
|
|
|
|
|
+ this.currentSong.isFav = nextFavorite
|
|
|
|
|
+ if (this.currentIndex >= 0 && this.currentIndex < this.queue.length) {
|
|
|
|
|
+ this.queue[this.currentIndex].isFav = nextFavorite
|
|
|
|
|
+ }
|
|
|
|
|
+ this.persistCurrentQueue()
|
|
|
|
|
+ this.syncHostStorage(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
|
|
+ this.syncPlaybackSessionState(this.isPlaying ? PlayStatus.PLAY : PlayStatus.PAUSE)
|
|
|
|
|
+ this.persistPlaybackSnapshot(this.isPlaying)
|
|
|
|
|
+ Logger.info(TAG, `[MusicCast] favorite updated song=${this.currentSong.name}, isFavorite=${isFavorite}`)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|