MediaPositionState 显示不正确的 currentTime

Posted

技术标签:

【中文标题】MediaPositionState 显示不正确的 currentTime【英文标题】:MediaPositionState shows incorrect currentTime 【发布时间】:2021-01-03 11:39:43 【问题描述】:

所以,这就是问题所在。我在我的反应项目中使用音频 html5 元素。 问题的典型流程是: 这首歌正在播放。 用户在某个时间按下暂停(假设时间是 1.20)。 用户锁定手机。 几分钟后,用户解锁他的手机,按下“播放”按钮,会发生什么: mediaPositionState 将当前时间计算为先前(1.20)加上音频的当前时间,而不是仅计算当前时间。 即使更换歌曲,这个额外的 1.20 也会保留。 我尝试在下面的 useEffect 中控制它

useEffect(() => 
    const audioEl = audioRef.current;
    if (audioEl) 
      audioEl.addEventListener('timeupdate', updateTime);
      audioEl.addEventListener('loadeddata', updatePositionState);
    
    return () => 
      if (audioEl) 
        audioEl.removeEventListener('timeupdate', updateTime);
        audioEl.removeEventListener('loadeddata', updateTime);
        updatePositionState();
      
    ;
  , []);

但它只有在用户专注于音频时才能正常工作。

我还有以下代码:

  function updatePositionState() 
    if (navigator.mediaSession?.setPositionState) 
      navigator.mediaSession.setPositionState(
        duration: audioRef.current?.duration ?? 0.0,
        position: audioRef.current?.currentTime ?? 0.0,
      );
    
  
  const createMediaSession = (state: AudiostateType) => 
    if (navigator.mediaSession) 
      navigator.mediaSession.metadata = new MediaMetadata(
        title: state.currentSongName,
        artist: state.currentArtistName,
        album: state.currentAlbumName,
        artwork: [
          
            sizes: '300x300',
            src: `http://storage.musicstream.app/cover/$state.currentAlbumCoverId`,
          ,
        ],
      );
      navigator.mediaSession.setActionHandler('play', function () 
        dispatch( type: 'resume' );
        updatePositionState();
      );
      navigator.mediaSession.setActionHandler('pause', function () 
        dispatch( type: 'pause' );
        updatePositionState();
      );
      navigator.mediaSession.setActionHandler('seekto', function (details) 
        dispatch( type: 'manual_update_time', time: details.seekTime );
        updatePositionState();
      );
      navigator.mediaSession.setActionHandler('previoustrack', () => 
        return 0;
      );
      navigator.mediaSession.setActionHandler('nexttrack', () => 
        return 0;
      );
    
  ;

我不知道如何正常描述这个问题,让我们假设当用户刷出 MediaSession 通知时,mediaposition 搞砸了。 如果你问,我会提供更多代码。 我还提供了屏幕截图(尽管我试图强制出现类似的问题:它将时间显示为曲目的结尾)。

当前歌曲时间

暂停时当前歌曲时间还可以

播放时当前歌曲时间混乱

按要求添加updateTime函数 它只是用于更新 react.Context 中的状态

const updateTime = () => 
    if (audioRef.current) 
      dispatch( type: 'update_time', time: audioRef.current.currentTime );
    
  ;

另外,完整的 reducer 看起来像这样(我认为这不会有帮助):

function audioReducer(state: AudioStateType, action: Action): AudioStateType 
    switch (action.type) 
      case 'fetch_and_play': 
        play(action.songData?.currentSongId).then(() => 
          dispatch(
            type: 'play',
            songData: 
              ...action.songData,
              length: audioRef.current?.duration,
            ,
          );
        );
        return state;
      
      case 'play': 
        createMediaSession( ...state, ...action.songData );
        return  ...state, ...action.songData ;
      
      case 'pause': 
        pause();
        return  ...state, songIsPaused: true ;
      
      case 'resume': 
        resume();
        return  ...state, songIsPaused: false ;
      
      case 'update_time': 
        return  ...state, currentTime: action.time ;
      
      case 'manual_update_time': 
        if (audioRef.current) 
          audioRef.current.currentTime = action.time;
          return  ...state, currentTime: action.time ;
         else 
          return state;
        
      
      default: 
        return state;
      
    
  

我制作了一个代码框,您可以在其中看到我的问题。 https://codesandbox.io/s/wizardly-wiles-87qi1?file=/src/App.js 为了真正了解请使用安卓手机

【问题讨论】:

可以分享updateTime函数吗? @b3hr4d,添加到问题块 Reducer 应该是纯函数,你应该在 reducer 之前使用 action,以便调度和其他人员。 我明白你的意思,但你能提供一个至少 1 个案例的例子吗?对于我在case 块中所做的事情,我应该有一个单独的功能吗?而且,它会影响 MediaPosition 吗?还是只是一个建议?? 好吧,我举个例子作为答案。我认为它可以解决很多问题。 【参考方案1】:

reducer 应该是纯函数,在 reducer 之前使用 action 用于 dispatch 和其他人员:

Action.ts

const fetchAndPlay = (currentSongId) => 
   play(currentSongId).then(() => 
        createMediaSession( ...state, ...action.songData );
        dispatch(
          type: 'play',
          //just pass data u need to show or you want rerender them
          length: audioRef.current?.duration,
      );
    );

Reducer.ts

function audioReducer(state: AudioStateType, action: Action): AudioStateType 
switch (action.type) 
  case 'play': 
       return  ...state, length:action.length, playing: true;
  ...

在你的组件中调用这个动作:

fetchAndPlay(songId)

【讨论】:

我不确定留下一个简单的函数并在不同的组件中到处调用它是一个好主意,除非它是一个钩子,但是为这个小逻辑创建一个钩子是不必要的。此外,由于play 函数中发生的异步操作,我使它变得如此复杂,在*** 上看到了类似的方法。我敢肯定这不会处理 mediaPosition,因为我用道具做起来更难看,结果是一样的。 你在使用 redux 吗?

以上是关于MediaPositionState 显示不正确的 currentTime的主要内容,如果未能解决你的问题,请参考以下文章

密码输入总是显示密码不正确

scrollView 分页显示不正确

Xcode 调试器显示不正确的变量值

UITableCell 显示不正确的内容

FPDF获取“不正确的输出目标”,但错误代码显示正确的目标

标签显示不正确