それで、ここに問題があります。反応プロジェクトで audio 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 });
}
};
また、完全なレデューサーは次のようになります (役に立たないと思います)。
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 真に理解するには、Android フォンを使用してください