Showing
4 changed files
with
95 additions
and
24 deletions
| @@ -45,11 +45,10 @@ export class AudioSuspensionModel { | @@ -45,11 +45,10 @@ export class AudioSuspensionModel { | ||
| 45 | this.playerController.get().keepOnBackground = true | 45 | this.playerController.get().keepOnBackground = true |
| 46 | BackgroundAudioController.sharedController().avplayerController = this.playerController.get() | 46 | BackgroundAudioController.sharedController().avplayerController = this.playerController.get() |
| 47 | await BackgroundAudioController.sharedController().createSession() | 47 | await BackgroundAudioController.sharedController().createSession() |
| 48 | - BackgroundAudioController.sharedController().startContinuousTask() | ||
| 49 | - let id = $r('app.media.newspaper_default').id | ||
| 50 | - BackgroundAudioController.sharedController().setSessionMetaData(srcContentId ?? "", srcTitle, 'file://', srcSource ?? "") | ||
| 51 | - BackgroundAudioController.sharedController().stopUseFeatures() | 48 | + // BackgroundAudioController.sharedController().startContinuousTask() |
| 52 | BackgroundAudioController.sharedController().listenPlayEvents() | 49 | BackgroundAudioController.sharedController().listenPlayEvents() |
| 50 | + await BackgroundAudioController.sharedController().setSessionMetaData(srcContentId ?? "", srcTitle, $r("app.media.system_audio_icon_bk_center"), srcSource ?? "") | ||
| 51 | + BackgroundAudioController.sharedController().stopUseFeatures() | ||
| 53 | 52 | ||
| 54 | if (this.url === url) { | 53 | if (this.url === url) { |
| 55 | this.isMinimize = AppStorage.link<boolean>('isMinimize') | 54 | this.isMinimize = AppStorage.link<boolean>('isMinimize') |
sight_harmony/features/wdComponent/src/main/resources/base/media/system_audio_icon_bk_center.png
0 → 100644
117 KB
| @@ -2,10 +2,11 @@ import { Context, WantAgent, wantAgent } from '@kit.AbilityKit' | @@ -2,10 +2,11 @@ import { Context, WantAgent, wantAgent } from '@kit.AbilityKit' | ||
| 2 | import { avSession as AVSessionManager } from '@kit.AVSessionKit' | 2 | import { avSession as AVSessionManager } from '@kit.AVSessionKit' |
| 3 | import { backgroundTaskManager } from '@kit.BackgroundTasksKit' | 3 | import { backgroundTaskManager } from '@kit.BackgroundTasksKit' |
| 4 | import { BusinessError } from '@kit.BasicServicesKit' | 4 | import { BusinessError } from '@kit.BasicServicesKit' |
| 5 | -import { Logger } from 'wdKit/Index' | ||
| 6 | -import { PlayerConstants } from '../constants/PlayerConstants' | 5 | +import { DateTimeUtils, EmitterEventId, EmitterUtils, Logger } from 'wdKit/Index' |
| 6 | +import { Events, PlayerConstants } from '../constants/PlayerConstants' | ||
| 7 | import { WDPlayerController } from './WDPlayerController' | 7 | import { WDPlayerController } from './WDPlayerController' |
| 8 | import { image } from '@kit.ImageKit' | 8 | import { image } from '@kit.ImageKit' |
| 9 | +import { JSON } from '@kit.ArkTS' | ||
| 9 | 10 | ||
| 10 | const TAG = "BackgroundAudioController" | 11 | const TAG = "BackgroundAudioController" |
| 11 | 12 | ||
| @@ -13,6 +14,9 @@ export class BackgroundAudioController { | @@ -13,6 +14,9 @@ export class BackgroundAudioController { | ||
| 13 | 14 | ||
| 14 | private static bgAudioController: BackgroundAudioController | 15 | private static bgAudioController: BackgroundAudioController |
| 15 | private constructor() { | 16 | private constructor() { |
| 17 | + EmitterUtils.receiveEvent(EmitterEventId.APP_ENTER_BACKGROUD, () => { | ||
| 18 | + this.startContinuousTask() | ||
| 19 | + }) | ||
| 16 | } | 20 | } |
| 17 | public static sharedController() { | 21 | public static sharedController() { |
| 18 | if (!BackgroundAudioController.bgAudioController) { | 22 | if (!BackgroundAudioController.bgAudioController) { |
| @@ -24,9 +28,17 @@ export class BackgroundAudioController { | @@ -24,9 +28,17 @@ export class BackgroundAudioController { | ||
| 24 | public gotContextFunc?: () => Context | 28 | public gotContextFunc?: () => Context |
| 25 | public avplayerController?: WDPlayerController | 29 | public avplayerController?: WDPlayerController |
| 26 | private lastSession?: AVSessionManager.AVSession | 30 | private lastSession?: AVSessionManager.AVSession |
| 31 | + | ||
| 27 | private applyedLongTaskPlay: boolean = false | 32 | private applyedLongTaskPlay: boolean = false |
| 33 | + | ||
| 28 | private lastProgress: number = 0.0 | 34 | private lastProgress: number = 0.0 |
| 29 | private hasSetupProgress: boolean = false | 35 | private hasSetupProgress: boolean = false |
| 36 | + private playing: boolean = false | ||
| 37 | + private lastItemAssetId?: string | ||
| 38 | + private lastItemTitle?: string | ||
| 39 | + private lastItemMediaImage?: Resource | ||
| 40 | + private lastItemArtist?: string | ||
| 41 | + private lastItemTotalDuration: number = 0 | ||
| 30 | 42 | ||
| 31 | // 开始创建并激活媒体会话 | 43 | // 开始创建并激活媒体会话 |
| 32 | // 创建session | 44 | // 创建session |
| @@ -56,23 +68,53 @@ export class BackgroundAudioController { | @@ -56,23 +68,53 @@ export class BackgroundAudioController { | ||
| 56 | } | 68 | } |
| 57 | 69 | ||
| 58 | //设置播放元数据 | 70 | //设置播放元数据 |
| 59 | - setSessionMetaData(assetId: string, title: string, mediaImage: image.PixelMap | string, artist: string) { | ||
| 60 | - Logger.debug(TAG, `SetAVMetadata assetId: ${assetId}}, title: ${title}, mediaImage: ${mediaImage}, artist: ${artist}`); | 71 | + async setSessionMetaData(assetId: string, title: string, mediaImage: Resource, artist: string) { |
| 72 | + this.lastItemAssetId = assetId | ||
| 73 | + this.lastItemTitle = title | ||
| 74 | + this.lastItemMediaImage = mediaImage | ||
| 75 | + this.lastItemArtist = artist | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + async setSessionMetaDataWithDuration(assetId: string, title: string, mediaImage: Resource, artist: string, duration: number) { | ||
| 79 | + Logger.debug(TAG, `SetAVMetadata assetId: ${assetId}}, title: ${title}, mediaImage: ${mediaImage}, artist: ${artist}, duration: ${duration}`); | ||
| 80 | + | ||
| 81 | + if (!this.gotContextFunc) { return } | ||
| 82 | + let pixelMapImage:image.PixelMap | null = null | ||
| 83 | + try { | ||
| 84 | + const data:Uint8Array = await this.gotContextFunc().resourceManager.getMediaContent(mediaImage) | ||
| 85 | + pixelMapImage = await image.createPixelMap(data.buffer as ArrayBuffer, { | ||
| 86 | + editable: false, | ||
| 87 | + alphaType: image.AlphaType.UNKNOWN, | ||
| 88 | + srcPixelFormat: image.PixelMapFormat.RGB_888, | ||
| 89 | + size: { width:300, height:300 } | ||
| 90 | + }) | ||
| 91 | + } catch (e) { | ||
| 92 | + Logger.error(TAG, `SetAVMetadata ` + JSON.stringify(e)); | ||
| 93 | + } finally { | ||
| 94 | + // Logger.debug(TAG, `SetAVMetadata ` + JSON.stringify(pixelMapImage)); | ||
| 61 | let metadata: AVSessionManager.AVMetadata = { | 95 | let metadata: AVSessionManager.AVMetadata = { |
| 62 | assetId: assetId.length > 0 ? assetId : "fake-asset-id", | 96 | assetId: assetId.length > 0 ? assetId : "fake-asset-id", |
| 63 | title: title.length > 0 ? title : " ", | 97 | title: title.length > 0 ? title : " ", |
| 64 | - mediaImage: mediaImage, | 98 | + mediaImage: pixelMapImage ?? ("file://" + mediaImage.id), |
| 65 | artist: artist.length > 0 ? artist : "人日日报", | 99 | artist: artist.length > 0 ? artist : "人日日报", |
| 100 | + duration: duration | ||
| 66 | }; | 101 | }; |
| 67 | - this.lastSession?.setAVMetadata(metadata).then(() => { | 102 | + |
| 103 | + try { | ||
| 104 | + await this.lastSession?.setAVMetadata(metadata) | ||
| 68 | Logger.debug(TAG, `SetAVMetadata successfully`); | 105 | Logger.debug(TAG, `SetAVMetadata successfully`); |
| 69 | - }).catch((err: BusinessError) => { | 106 | + } catch (err) { |
| 70 | Logger.error(TAG, `Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); | 107 | Logger.error(TAG, `Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); |
| 71 | - }); | 108 | + } finally { |
| 109 | + pixelMapImage?.release() | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 72 | } | 113 | } |
| 73 | 114 | ||
| 74 | //设置播放状态 | 115 | //设置播放状态 |
| 75 | setSessionPlayStatus(playStatus: number) { | 116 | setSessionPlayStatus(playStatus: number) { |
| 117 | + let needUpdateProgress = false | ||
| 76 | let playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY | 118 | let playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY |
| 77 | switch (playStatus){ | 119 | switch (playStatus){ |
| 78 | case PlayerConstants.STATUS_PAUSE: { | 120 | case PlayerConstants.STATUS_PAUSE: { |
| @@ -80,6 +122,7 @@ export class BackgroundAudioController { | @@ -80,6 +122,7 @@ export class BackgroundAudioController { | ||
| 80 | } break | 122 | } break |
| 81 | case PlayerConstants.STATUS_START: { | 123 | case PlayerConstants.STATUS_START: { |
| 82 | playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY | 124 | playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY |
| 125 | + needUpdateProgress = true | ||
| 83 | } break | 126 | } break |
| 84 | case PlayerConstants.STATUS_STOP: { | 127 | case PlayerConstants.STATUS_STOP: { |
| 85 | playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_STOP | 128 | playbackStatus = AVSessionManager.PlaybackState.PLAYBACK_STATE_STOP |
| @@ -103,13 +146,15 @@ export class BackgroundAudioController { | @@ -103,13 +146,15 @@ export class BackgroundAudioController { | ||
| 103 | Logger.error(TAG, `Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); | 146 | Logger.error(TAG, `Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); |
| 104 | } else { | 147 | } else { |
| 105 | Logger.debug(TAG, `SetAVPlaybackState 设置播放状态成功 ` + playStatus); | 148 | Logger.debug(TAG, `SetAVPlaybackState 设置播放状态成功 ` + playStatus); |
| 149 | + if (needUpdateProgress) { | ||
| 150 | + this.hasSetupProgress = false | ||
| 151 | + } | ||
| 106 | } | 152 | } |
| 107 | }); | 153 | }); |
| 108 | } | 154 | } |
| 109 | 155 | ||
| 110 | - //设置进度,单位秒 | ||
| 111 | - setSessionPlayProgress(progressDuration: number, totalDuration: number) { | ||
| 112 | - // Logger.debug(TAG, `set progress: ` + progressDuration + " duration: " + totalDuration); | 156 | + //设置进度,单位ms |
| 157 | + async setSessionPlayProgress(progressDuration: number, totalDuration: number) { | ||
| 113 | if (totalDuration <= 0) { | 158 | if (totalDuration <= 0) { |
| 114 | return | 159 | return |
| 115 | } | 160 | } |
| @@ -117,25 +162,38 @@ export class BackgroundAudioController { | @@ -117,25 +162,38 @@ export class BackgroundAudioController { | ||
| 117 | if (Math.abs(newProgress - this.lastProgress) < 0.01) { | 162 | if (Math.abs(newProgress - this.lastProgress) < 0.01) { |
| 118 | return | 163 | return |
| 119 | } | 164 | } |
| 165 | + // Logger.debug(TAG, `set progress: ` + progressDuration + " duration: " + totalDuration); | ||
| 120 | this.lastProgress = newProgress | 166 | this.lastProgress = newProgress |
| 121 | 167 | ||
| 168 | + if (this.lastItemAssetId) { | ||
| 169 | + this.lastItemTotalDuration = totalDuration | ||
| 170 | + await this.setSessionMetaDataWithDuration( | ||
| 171 | + this.lastItemAssetId ?? "", | ||
| 172 | + this.lastItemTitle ?? "", | ||
| 173 | + this.lastItemMediaImage!, | ||
| 174 | + this.lastItemArtist ?? "", | ||
| 175 | + totalDuration | ||
| 176 | + ) | ||
| 177 | + this.lastItemAssetId = undefined | ||
| 178 | + } | ||
| 179 | + | ||
| 122 | if (this.hasSetupProgress) { | 180 | if (this.hasSetupProgress) { |
| 123 | return | 181 | return |
| 124 | } | 182 | } |
| 125 | this.hasSetupProgress = true | 183 | this.hasSetupProgress = true |
| 126 | - | ||
| 127 | - Logger.debug(TAG, `set progress: ` + progressDuration + " duration: " + totalDuration); | 184 | + Logger.debug(TAG, `set progress: ` + DateTimeUtils.secondToTime(progressDuration / 1000) |
| 185 | + + " duration: " + DateTimeUtils.secondToTime(totalDuration / 1000)); | ||
| 128 | 186 | ||
| 129 | // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间 | 187 | // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间 |
| 130 | let playbackState: AVSessionManager.AVPlaybackState = { | 188 | let playbackState: AVSessionManager.AVPlaybackState = { |
| 131 | state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态 | 189 | state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态 |
| 132 | position: { | 190 | position: { |
| 133 | - elapsedTime: progressDuration * 1000, // 已经播放的位置,以ms为单位 | 191 | + elapsedTime: progressDuration, // 已经播放的位置,以ms为单位 |
| 134 | updateTime: new Date().getTime(), // 应用更新当前位置时的时间戳,以ms为单位 | 192 | updateTime: new Date().getTime(), // 应用更新当前位置时的时间戳,以ms为单位 |
| 135 | }, | 193 | }, |
| 136 | - duration: totalDuration * 1000, | ||
| 137 | - speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验 | ||
| 138 | - bufferedTime: totalDuration * 1000, // 可选,资源缓存的时间,以ms为单位 | 194 | + // duration: totalDuration, |
| 195 | + // speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验 | ||
| 196 | + // bufferedTime: totalDuration, // 可选,资源缓存的时间,以ms为单位 | ||
| 139 | }; | 197 | }; |
| 140 | this.lastSession?.setAVPlaybackState(playbackState, (err) => { | 198 | this.lastSession?.setAVPlaybackState(playbackState, (err) => { |
| 141 | if (err) { | 199 | if (err) { |
| @@ -181,8 +239,12 @@ export class BackgroundAudioController { | @@ -181,8 +239,12 @@ export class BackgroundAudioController { | ||
| 181 | // Logger.debug(TAG, `on playPrevious `); | 239 | // Logger.debug(TAG, `on playPrevious `); |
| 182 | // }); | 240 | // }); |
| 183 | this.lastSession?.on('seek', (position: number) => { | 241 | this.lastSession?.on('seek', (position: number) => { |
| 184 | - Logger.debug(TAG, `on seek , the time is ${JSON.stringify(position)}`); | 242 | + Logger.debug(TAG, `on seek , the time is ${position}`); |
| 243 | + if (this.lastItemTotalDuration == 0) { | ||
| 244 | + return | ||
| 245 | + } | ||
| 185 | 246 | ||
| 247 | + this.hasSetupProgress = true | ||
| 186 | // 由于应用内seek可能会触发较长的缓冲等待,可以先把状态设置为 Buffering | 248 | // 由于应用内seek可能会触发较长的缓冲等待,可以先把状态设置为 Buffering |
| 187 | let playbackState: AVSessionManager.AVPlaybackState = { | 249 | let playbackState: AVSessionManager.AVPlaybackState = { |
| 188 | state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // 缓冲状态 | 250 | state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // 缓冲状态 |
| @@ -193,11 +255,13 @@ export class BackgroundAudioController { | @@ -193,11 +255,13 @@ export class BackgroundAudioController { | ||
| 193 | } else { | 255 | } else { |
| 194 | Logger.debug(TAG, `SetAVPlaybackState seek buffering`); | 256 | Logger.debug(TAG, `SetAVPlaybackState seek buffering`); |
| 195 | } | 257 | } |
| 196 | - }); | ||
| 197 | 258 | ||
| 198 | // 应用响应seek命令,使用应用内播放器完成seek实现 | 259 | // 应用响应seek命令,使用应用内播放器完成seek实现 |
| 199 | - this.avplayerController?.setSeekTime(position * 0.001, SliderChangeMode.End) | 260 | + this.avplayerController?.setSeekMicroSecondsTime(position) |
| 261 | + setTimeout(() => { | ||
| 200 | this.hasSetupProgress = false | 262 | this.hasSetupProgress = false |
| 263 | + }, 1000) | ||
| 264 | + }); | ||
| 201 | }); | 265 | }); |
| 202 | } | 266 | } |
| 203 | 267 | ||
| @@ -239,6 +303,7 @@ export class BackgroundAudioController { | @@ -239,6 +303,7 @@ export class BackgroundAudioController { | ||
| 239 | // 通过wantAgent模块下getWantAgent方法获取WantAgent对象 | 303 | // 通过wantAgent模块下getWantAgent方法获取WantAgent对象 |
| 240 | wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { | 304 | wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { |
| 241 | if (!this.gotContextFunc) { return } | 305 | if (!this.gotContextFunc) { return } |
| 306 | + this.lastSession?.setLaunchAbility(wantAgentObj) | ||
| 242 | backgroundTaskManager.startBackgroundRunning(this.gotContextFunc(), | 307 | backgroundTaskManager.startBackgroundRunning(this.gotContextFunc(), |
| 243 | backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, | 308 | backgroundTaskManager.BackgroundMode.AUDIO_PLAYBACK, |
| 244 | wantAgentObj).then(() => { | 309 | wantAgentObj).then(() => { |
| @@ -336,6 +336,13 @@ export class WDPlayerController { | @@ -336,6 +336,13 @@ export class WDPlayerController { | ||
| 336 | this.avPlayer?.seek(this.seekTime); | 336 | this.avPlayer?.seek(this.seekTime); |
| 337 | } | 337 | } |
| 338 | } | 338 | } |
| 339 | + async setSeekMicroSecondsTime(value: number) { | ||
| 340 | + // 防止seek报错 | ||
| 341 | + if (this.avPlayer && PlayerConstants.OPERATE_STATE.indexOf(this.avPlayer?.state) === -1) { | ||
| 342 | + return; | ||
| 343 | + } | ||
| 344 | + this.avPlayer?.seek(value); | ||
| 345 | + } | ||
| 339 | 346 | ||
| 340 | setBright() { | 347 | setBright() { |
| 341 | // globalThis.windowClass.setWindowBrightness(this.playerThis.bright) | 348 | // globalThis.windowClass.setWindowBrightness(this.playerThis.bright) |
-
Please register or login to post a comment