Audio Player: Fix resuming playback (#6542)

This commit is contained in:
zubiden 2025-12-22 22:54:08 +01:00 committed by Alexander Zinchuk
parent 61ec53ac2b
commit 9a9e8d03aa
8 changed files with 36 additions and 19 deletions

View File

@ -10,6 +10,7 @@ import type { IconName } from '../../../types/icons';
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
import {
getMediaFormat,
getMessageContent, isMessageLocal,
} from '../../../global/helpers';
import { getPeerTitle } from '../../../global/helpers/peers';
@ -20,7 +21,6 @@ import { selectMessageMediaDuration } from '../../../global/selectors/media';
import { makeTrackId } from '../../../util/audioPlayer';
import { IS_IOS, IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
import buildClassName from '../../../util/buildClassName';
import * as mediaLoader from '../../../util/mediaLoader';
import { clearMediaSession } from '../../../util/mediaSession';
import renderText from '../../common/helpers/renderText';
@ -30,6 +30,7 @@ import useAudioPlayer from '../../../hooks/useAudioPlayer';
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
import useLastCallback from '../../../hooks/useLastCallback';
import useMedia from '../../../hooks/useMedia';
import useMessageMediaMetadata from '../../../hooks/useMessageMediaMetadata';
import useOldLang from '../../../hooks/useOldLang';
import useShowTransition from '../../../hooks/useShowTransition';
@ -109,8 +110,10 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
const shouldRenderPlaybackButton = isVoice || (audio?.duration || 0) > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION;
const senderName = sender ? getPeerTitle(lang, sender) : undefined;
const playableMedia = voice || video || audio;
const mediaHash = useMessageMediaHash(renderingMessage, 'inline');
const mediaData = mediaHash && mediaLoader.getFromMemory(mediaHash);
const mediaFormat = playableMedia && getMediaFormat(playableMedia, 'inline');
const mediaData = useMedia(mediaHash, false, mediaFormat);
const mediaMetadata = useMessageMediaMetadata(renderingMessage, sender, chat);
const {
@ -424,8 +427,9 @@ export default withGlobal<OwnProps>(
const sender = message && selectSender(global, message);
const chat = message && selectChat(global, message.chatId);
const {
volume, playbackRate, isMuted, isPlaybackRateActive, timestamp,
playbackRate, isMuted, isPlaybackRateActive, timestamp,
} = selectTabState(global).audioPlayer;
const { volume } = global.audioPlayer;
const mediaDuration = message ? selectMessageMediaDuration(global, message) : undefined;

View File

@ -183,7 +183,7 @@ addActionHandler('replyToNextMessage', (global, actions, payload): ActionReturnT
addActionHandler('openAudioPlayer', (global, actions, payload): ActionReturnType => {
const {
chatId, threadId, messageId, origin, volume, playbackRate, isMuted, timestamp,
chatId, threadId, messageId, origin, playbackRate, isMuted, timestamp,
tabId = getCurrentTabId(),
} = payload;
@ -195,7 +195,6 @@ addActionHandler('openAudioPlayer', (global, actions, payload): ActionReturnType
messageId,
timestamp,
origin: origin ?? tabState.audioPlayer.origin,
volume: volume ?? tabState.audioPlayer.volume,
playbackRate: playbackRate || tabState.audioPlayer.playbackRate || global.audioPlayer.lastPlaybackRate,
isPlaybackRateActive: (tabState.audioPlayer.isPlaybackRateActive === undefined
? global.audioPlayer.isLastPlaybackRateActive
@ -210,13 +209,20 @@ addActionHandler('setAudioPlayerVolume', (global, actions, payload): ActionRetur
volume, tabId = getCurrentTabId(),
} = payload;
return updateTabState(global, {
global = updateTabState(global, {
audioPlayer: {
...selectTabState(global, tabId).audioPlayer,
volume,
isMuted: false,
},
}, tabId);
global = {
...global,
audioPlayer: {
...global.audioPlayer,
volume,
},
};
return global;
});
addActionHandler('setAudioPlayerPlaybackRate', (global, actions, payload): ActionReturnType => {
@ -273,7 +279,6 @@ addActionHandler('closeAudioPlayer', (global, actions, payload): ActionReturnTyp
const tabState = selectTabState(global, tabId);
return updateTabState(global, {
audioPlayer: {
volume: tabState.audioPlayer.volume,
playbackRate: tabState.audioPlayer.playbackRate,
isPlaybackRateActive: tabState.audioPlayer.isPlaybackRateActive,
isMuted: tabState.audioPlayer.isMuted,

View File

@ -367,6 +367,10 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
cached.auth = initialState.auth;
cached.auth.rememberMe = untypedCached.rememberMe;
}
if (cached.audioPlayer.volume === undefined) {
cached.audioPlayer.volume = initialState.audioPlayer.volume;
}
}
function updateCache(force?: boolean) {

View File

@ -106,6 +106,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
appConfig: DEFAULT_APP_CONFIG,
audioPlayer: {
volume: DEFAULT_VOLUME,
lastPlaybackRate: DEFAULT_PLAYBACK_RATE,
},
@ -426,7 +427,6 @@ export const INITIAL_TAB_STATE: TabState = {
},
audioPlayer: {
volume: DEFAULT_VOLUME,
playbackRate: DEFAULT_PLAYBACK_RATE,
isMuted: false,
},

View File

@ -105,6 +105,7 @@ export type GlobalState = {
botFreezeAppealId?: string;
audioPlayer: {
volume: number;
lastPlaybackRate: number;
isLastPlaybackRateActive?: boolean;
};

View File

@ -378,7 +378,6 @@ export type TabState = {
messageId?: number;
threadId?: ThreadId;
origin?: AudioOrigin;
volume: number;
playbackRate: number;
isPlaybackRateActive?: boolean;
timestamp?: number;

View File

@ -65,17 +65,21 @@ const useAudioPlayer = (
const {
setVolume, setPlaybackRate, toggleMuted, proxy,
} = controllerRef.current!;
const global = getGlobal();
setIsPlaying(true);
if (trackType !== 'oneTimeVoice') {
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
}
setPlaybackState('playing');
const { audioPlayer } = selectTabState(getGlobal());
setVolume(audioPlayer.volume);
toggleMuted(Boolean(audioPlayer.isMuted));
const { audioPlayer: tabAudioPlayerState } = selectTabState(global);
const { audioPlayer: globalAudioPlayerState } = global;
setVolume(globalAudioPlayerState.volume);
toggleMuted(Boolean(tabAudioPlayerState.isMuted));
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
if (trackType === 'voice' || duration > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION) {
setPlaybackRate(audioPlayer.playbackRate);
setPlaybackRate(tabAudioPlayerState.playbackRate);
}
setPositionState({
duration: proxy.duration || 0,

View File

@ -4,7 +4,6 @@ import type { ApiMessage } from '../api/types';
import type { MessageKey } from './keys/messageKey';
import { AudioOrigin, GlobalSearchContent } from '../types';
import { requestNextMutation } from '../lib/fasterdom/fasterdom';
import { selectCurrentMessageList, selectTabState } from '../global/selectors';
import { IS_SAFARI } from './browser/windowEnvironment';
import { getMessageServerKey, parseMessageKey } from './keys/messageKey';
@ -179,14 +178,15 @@ export function register(
stop() {
if (currentTrackId === trackId) {
// Hack, reset `src` to remove default media session notification
const prevSrc = audio.src;
audio.pause();
// `onPause` not called otherwise, but required to sync UI
requestNextMutation(() => {
// `onPause` is required to reset UI state
audio.addEventListener('pause', () => {
// Hack, reset `src` to remove default media session notification
audio.src = '';
audio.src = prevSrc;
});
}, { once: true });
}
},