Explorar o código

修复播放页面 切换播放模式无效果

onecold hai 4 meses
pai
achega
eef98030b7

+ 11 - 0
entry/src/main/ets/controller/MusicPlaybackController.ets

@@ -186,6 +186,17 @@ export class MusicPlaybackController {
     return 2
   }
 
+  /**
+   * 判断 AVSession 的 setLoopMode 回调是否是由应用内部刚上报的同值模式触发。
+   *
+   * @param reportedMode 应用最近一次主动上报给 AVSession 的循环模式。
+   * @param incomingMode AVSession 回调带回的循环模式。
+   * @returns 若为内部同值回流则返回 true。
+   */
+  public static shouldIgnoreInternalLoopModeEvent(reportedMode: number, incomingMode: number): boolean {
+    return reportedMode >= 0 && reportedMode === incomingMode
+  }
+
   /**
    * 根据输入参数计算安全的跳转进度,并处理 CUE 偏移与远程歌曲限制。
    *

+ 31 - 1
entry/src/main/ets/view/LocalMusic.ets

@@ -127,7 +127,7 @@ import { deviceInfo } from '@kit.BasicServicesKit';
 import '../common/network/RemoteCacheRegistry';
 import { shouldWrapLocalMusicMenuInScroll } from '../common/util/LocalMusicMenuScrollHelper';
 import { ServerLogUtil } from '../common/util/ServerLogUtil';
-import { MusicPlaybackController } from '../controller/MusicPlaybackController';
+import { MusicPlaybackController, MusicPlaybackControllerActions } from '../controller/MusicPlaybackController';
 import { PlaybackCoordinator, PlaybackRuntime } from '../controller/PlaybackCoordinator'
 import { PlaybackStateBridge } from '../controller/PlaybackStateBridge'
 import { lyricService, SongData } from '../common/service/LyricService';
@@ -503,6 +503,24 @@ export struct LocalMusic {
   private playbackController: MusicPlaybackController = MusicPlaybackController.getInstance()
   private playbackCoordinator: PlaybackCoordinator = PlaybackCoordinator.getInstance()
   private playbackStateBridge: PlaybackStateBridge = PlaybackStateBridge.getInstance()
+  private pendingInternalLoopModeReport: number = -1
+  private readonly playbackControllerActions: MusicPlaybackControllerActions = {
+    playOrPause: async () => {
+      await this.playOrPause()
+    },
+    playNext: async () => {
+      await this.playNext()
+    },
+    playPrevious: async () => {
+      await this.playPrevious()
+    },
+    setLoopMode: () => {
+      this.setLoopMode()
+    },
+    seekTo: async (value: string, source?: string) => {
+      await this.seekTo(value, source ?? 'controller')
+    }
+  }
   private playbackRuntime: PlaybackRuntime = {
     playQueue: async (queue: VideoItem[], startIndex: number, source: string, playType?: number) => {
       const safeIndex = queue.length <= 0 ? -1 : Math.max(0, Math.min(startIndex, queue.length - 1))
@@ -1126,6 +1144,7 @@ export struct LocalMusic {
   // 组件生命周期
   aboutToAppear() {
     this.playbackCoordinator.setRuntime(this.playbackRuntime)
+    this.playbackController.setActions(this.playbackControllerActions)
     this.consumePendingMusicCardAction()
     this.consumePendingMusicCardOpenRequest()
 
@@ -2337,6 +2356,8 @@ export struct LocalMusic {
   aboutToDisappear() {
     console.info('LifeCycleComponent aboutToDisappear');
     this.playbackCoordinator.clearRuntime(this.playbackRuntime)
+    this.playbackController.clearActions(this.playbackControllerActions)
+    this.pendingInternalLoopModeReport = -1
     if (this.alphaBetHideTimer) {
       clearTimeout(this.alphaBetHideTimer);
       this.alphaBetHideTimer = 0;
@@ -18805,6 +18826,11 @@ export struct LocalMusic {
 
   private sessionSetLoopModeCallback = (mode: number) => {
     if (this.mIjkMediaPlayer != null) {
+      if (MusicPlaybackController.shouldIgnoreInternalLoopModeEvent(this.pendingInternalLoopModeReport, mode)) {
+        this.pendingInternalLoopModeReport = -1
+        return
+      }
+      this.pendingInternalLoopModeReport = -1
       ToastUtil.showToast('当前播放模式:' + mode)
       Logger.info('onecold 当前播放模式= ' + mode)
       const resolvedMode = MusicPlaybackController.resolveSessionLoopMode(mode)
@@ -18812,12 +18838,14 @@ export struct LocalMusic {
       ToastUtil.showToast(resolvedMode.toastText)
       PreferencesUtil.putSync('musicPlayType', this.playType)
       // 应用收到设置循环模式的指令后,应用自定下一个模式,切换完毕后通过AVPlaybackState上报切换后的LoopMode。
+      this.pendingInternalLoopModeReport = resolvedMode.reportedLoopMode
       let playBackState: avSession.AVPlaybackState = {
         loopMode: resolvedMode.reportedLoopMode,
       };
       this.avSessionController.getAvSession()?.setAVPlaybackState(playBackState).then(() => {
         console.info(`set setLoopMode AVPlaybackState successfully`);
       }).catch((err: BusinessError) => {
+        this.pendingInternalLoopModeReport = -1
         console.error(`Failed to setLoopMode set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
       });
 
@@ -18829,6 +18857,7 @@ export struct LocalMusic {
       return;
     }
     const mLoopMode = MusicPlaybackController.resolveAvSessionLoopMode(this.playType)
+    this.pendingInternalLoopModeReport = mLoopMode
     // 应用启动时/内部切换循环模式,需要把应用内的当前的循环模式设置给AVSession。
     let playBState: avSession.AVPlaybackState = {
       loopMode: mLoopMode,
@@ -18837,6 +18866,7 @@ export struct LocalMusic {
     this.avSessionController.getAvSession()?.setAVPlaybackState(playBState).then(() => {
       console.info(`set setLoopMode AVPlaybackState successfully`);
     }).catch((err: BusinessError) => {
+      this.pendingInternalLoopModeReport = -1
       console.error(`Failed to setLoopMode set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
     });
   }

+ 6 - 0
entry/src/ohosTest/ets/test/MusicPlaybackController.test.ets

@@ -179,6 +179,12 @@ export default function musicPlaybackControllerTest() {
       expect(MusicPlaybackController.resolveAvSessionLoopMode(4)).assertEqual(4)
     })
 
+    it('shouldIgnoreInternalLoopModeEventOnlyWhenReportedModeMatches', 0, () => {
+      expect(MusicPlaybackController.shouldIgnoreInternalLoopModeEvent(2, 2)).assertTrue()
+      expect(MusicPlaybackController.shouldIgnoreInternalLoopModeEvent(2, 1)).assertFalse()
+      expect(MusicPlaybackController.shouldIgnoreInternalLoopModeEvent(-1, 2)).assertFalse()
+    })
+
     it('resolveSeekPositionClampsByDuration', 0, () => {
       const result = MusicPlaybackController.resolveSeekPosition({
         requestedValue: '5000',