BackgroundAudioController.ets 9.78 KB
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
  }

}