Audio Player: Fix resuming playback (#6542)
This commit is contained in:
parent
61ec53ac2b
commit
9a9e8d03aa
@ -10,6 +10,7 @@ import type { IconName } from '../../../types/icons';
|
|||||||
|
|
||||||
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
|
import { PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION } from '../../../config';
|
||||||
import {
|
import {
|
||||||
|
getMediaFormat,
|
||||||
getMessageContent, isMessageLocal,
|
getMessageContent, isMessageLocal,
|
||||||
} from '../../../global/helpers';
|
} from '../../../global/helpers';
|
||||||
import { getPeerTitle } from '../../../global/helpers/peers';
|
import { getPeerTitle } from '../../../global/helpers/peers';
|
||||||
@ -20,7 +21,6 @@ import { selectMessageMediaDuration } from '../../../global/selectors/media';
|
|||||||
import { makeTrackId } from '../../../util/audioPlayer';
|
import { makeTrackId } from '../../../util/audioPlayer';
|
||||||
import { IS_IOS, IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
import { IS_IOS, IS_TOUCH_ENV } from '../../../util/browser/windowEnvironment';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import * as mediaLoader from '../../../util/mediaLoader';
|
|
||||||
import { clearMediaSession } from '../../../util/mediaSession';
|
import { clearMediaSession } from '../../../util/mediaSession';
|
||||||
import renderText from '../../common/helpers/renderText';
|
import renderText from '../../common/helpers/renderText';
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ import useAudioPlayer from '../../../hooks/useAudioPlayer';
|
|||||||
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
import useContextMenuHandlers from '../../../hooks/useContextMenuHandlers';
|
||||||
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../../hooks/useCurrentOrPrev';
|
||||||
import useLastCallback from '../../../hooks/useLastCallback';
|
import useLastCallback from '../../../hooks/useLastCallback';
|
||||||
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useMessageMediaMetadata from '../../../hooks/useMessageMediaMetadata';
|
import useMessageMediaMetadata from '../../../hooks/useMessageMediaMetadata';
|
||||||
import useOldLang from '../../../hooks/useOldLang';
|
import useOldLang from '../../../hooks/useOldLang';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
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 shouldRenderPlaybackButton = isVoice || (audio?.duration || 0) > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION;
|
||||||
const senderName = sender ? getPeerTitle(lang, sender) : undefined;
|
const senderName = sender ? getPeerTitle(lang, sender) : undefined;
|
||||||
|
|
||||||
|
const playableMedia = voice || video || audio;
|
||||||
const mediaHash = useMessageMediaHash(renderingMessage, 'inline');
|
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 mediaMetadata = useMessageMediaMetadata(renderingMessage, sender, chat);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -424,8 +427,9 @@ export default withGlobal<OwnProps>(
|
|||||||
const sender = message && selectSender(global, message);
|
const sender = message && selectSender(global, message);
|
||||||
const chat = message && selectChat(global, message.chatId);
|
const chat = message && selectChat(global, message.chatId);
|
||||||
const {
|
const {
|
||||||
volume, playbackRate, isMuted, isPlaybackRateActive, timestamp,
|
playbackRate, isMuted, isPlaybackRateActive, timestamp,
|
||||||
} = selectTabState(global).audioPlayer;
|
} = selectTabState(global).audioPlayer;
|
||||||
|
const { volume } = global.audioPlayer;
|
||||||
|
|
||||||
const mediaDuration = message ? selectMessageMediaDuration(global, message) : undefined;
|
const mediaDuration = message ? selectMessageMediaDuration(global, message) : undefined;
|
||||||
|
|
||||||
|
|||||||
@ -183,7 +183,7 @@ addActionHandler('replyToNextMessage', (global, actions, payload): ActionReturnT
|
|||||||
|
|
||||||
addActionHandler('openAudioPlayer', (global, actions, payload): ActionReturnType => {
|
addActionHandler('openAudioPlayer', (global, actions, payload): ActionReturnType => {
|
||||||
const {
|
const {
|
||||||
chatId, threadId, messageId, origin, volume, playbackRate, isMuted, timestamp,
|
chatId, threadId, messageId, origin, playbackRate, isMuted, timestamp,
|
||||||
tabId = getCurrentTabId(),
|
tabId = getCurrentTabId(),
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
@ -195,7 +195,6 @@ addActionHandler('openAudioPlayer', (global, actions, payload): ActionReturnType
|
|||||||
messageId,
|
messageId,
|
||||||
timestamp,
|
timestamp,
|
||||||
origin: origin ?? tabState.audioPlayer.origin,
|
origin: origin ?? tabState.audioPlayer.origin,
|
||||||
volume: volume ?? tabState.audioPlayer.volume,
|
|
||||||
playbackRate: playbackRate || tabState.audioPlayer.playbackRate || global.audioPlayer.lastPlaybackRate,
|
playbackRate: playbackRate || tabState.audioPlayer.playbackRate || global.audioPlayer.lastPlaybackRate,
|
||||||
isPlaybackRateActive: (tabState.audioPlayer.isPlaybackRateActive === undefined
|
isPlaybackRateActive: (tabState.audioPlayer.isPlaybackRateActive === undefined
|
||||||
? global.audioPlayer.isLastPlaybackRateActive
|
? global.audioPlayer.isLastPlaybackRateActive
|
||||||
@ -210,13 +209,20 @@ addActionHandler('setAudioPlayerVolume', (global, actions, payload): ActionRetur
|
|||||||
volume, tabId = getCurrentTabId(),
|
volume, tabId = getCurrentTabId(),
|
||||||
} = payload;
|
} = payload;
|
||||||
|
|
||||||
return updateTabState(global, {
|
global = updateTabState(global, {
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
...selectTabState(global, tabId).audioPlayer,
|
...selectTabState(global, tabId).audioPlayer,
|
||||||
volume,
|
|
||||||
isMuted: false,
|
isMuted: false,
|
||||||
},
|
},
|
||||||
}, tabId);
|
}, tabId);
|
||||||
|
global = {
|
||||||
|
...global,
|
||||||
|
audioPlayer: {
|
||||||
|
...global.audioPlayer,
|
||||||
|
volume,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return global;
|
||||||
});
|
});
|
||||||
|
|
||||||
addActionHandler('setAudioPlayerPlaybackRate', (global, actions, payload): ActionReturnType => {
|
addActionHandler('setAudioPlayerPlaybackRate', (global, actions, payload): ActionReturnType => {
|
||||||
@ -273,7 +279,6 @@ addActionHandler('closeAudioPlayer', (global, actions, payload): ActionReturnTyp
|
|||||||
const tabState = selectTabState(global, tabId);
|
const tabState = selectTabState(global, tabId);
|
||||||
return updateTabState(global, {
|
return updateTabState(global, {
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
volume: tabState.audioPlayer.volume,
|
|
||||||
playbackRate: tabState.audioPlayer.playbackRate,
|
playbackRate: tabState.audioPlayer.playbackRate,
|
||||||
isPlaybackRateActive: tabState.audioPlayer.isPlaybackRateActive,
|
isPlaybackRateActive: tabState.audioPlayer.isPlaybackRateActive,
|
||||||
isMuted: tabState.audioPlayer.isMuted,
|
isMuted: tabState.audioPlayer.isMuted,
|
||||||
|
|||||||
@ -367,6 +367,10 @@ function unsafeMigrateCache(cached: GlobalState, initialState: GlobalState) {
|
|||||||
cached.auth = initialState.auth;
|
cached.auth = initialState.auth;
|
||||||
cached.auth.rememberMe = untypedCached.rememberMe;
|
cached.auth.rememberMe = untypedCached.rememberMe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cached.audioPlayer.volume === undefined) {
|
||||||
|
cached.audioPlayer.volume = initialState.audioPlayer.volume;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCache(force?: boolean) {
|
function updateCache(force?: boolean) {
|
||||||
|
|||||||
@ -106,6 +106,7 @@ export const INITIAL_GLOBAL_STATE: GlobalState = {
|
|||||||
appConfig: DEFAULT_APP_CONFIG,
|
appConfig: DEFAULT_APP_CONFIG,
|
||||||
|
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
|
volume: DEFAULT_VOLUME,
|
||||||
lastPlaybackRate: DEFAULT_PLAYBACK_RATE,
|
lastPlaybackRate: DEFAULT_PLAYBACK_RATE,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -426,7 +427,6 @@ export const INITIAL_TAB_STATE: TabState = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
volume: DEFAULT_VOLUME,
|
|
||||||
playbackRate: DEFAULT_PLAYBACK_RATE,
|
playbackRate: DEFAULT_PLAYBACK_RATE,
|
||||||
isMuted: false,
|
isMuted: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -105,6 +105,7 @@ export type GlobalState = {
|
|||||||
botFreezeAppealId?: string;
|
botFreezeAppealId?: string;
|
||||||
|
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
|
volume: number;
|
||||||
lastPlaybackRate: number;
|
lastPlaybackRate: number;
|
||||||
isLastPlaybackRateActive?: boolean;
|
isLastPlaybackRateActive?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -378,7 +378,6 @@ export type TabState = {
|
|||||||
messageId?: number;
|
messageId?: number;
|
||||||
threadId?: ThreadId;
|
threadId?: ThreadId;
|
||||||
origin?: AudioOrigin;
|
origin?: AudioOrigin;
|
||||||
volume: number;
|
|
||||||
playbackRate: number;
|
playbackRate: number;
|
||||||
isPlaybackRateActive?: boolean;
|
isPlaybackRateActive?: boolean;
|
||||||
timestamp?: number;
|
timestamp?: number;
|
||||||
|
|||||||
@ -65,17 +65,21 @@ const useAudioPlayer = (
|
|||||||
const {
|
const {
|
||||||
setVolume, setPlaybackRate, toggleMuted, proxy,
|
setVolume, setPlaybackRate, toggleMuted, proxy,
|
||||||
} = controllerRef.current!;
|
} = controllerRef.current!;
|
||||||
|
const global = getGlobal();
|
||||||
|
|
||||||
setIsPlaying(true);
|
setIsPlaying(true);
|
||||||
if (trackType !== 'oneTimeVoice') {
|
if (trackType !== 'oneTimeVoice') {
|
||||||
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
||||||
}
|
}
|
||||||
setPlaybackState('playing');
|
setPlaybackState('playing');
|
||||||
const { audioPlayer } = selectTabState(getGlobal());
|
|
||||||
setVolume(audioPlayer.volume);
|
const { audioPlayer: tabAudioPlayerState } = selectTabState(global);
|
||||||
toggleMuted(Boolean(audioPlayer.isMuted));
|
const { audioPlayer: globalAudioPlayerState } = global;
|
||||||
|
setVolume(globalAudioPlayerState.volume);
|
||||||
|
toggleMuted(Boolean(tabAudioPlayerState.isMuted));
|
||||||
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
|
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
|
||||||
if (trackType === 'voice' || duration > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION) {
|
if (trackType === 'voice' || duration > PLAYBACK_RATE_FOR_AUDIO_MIN_DURATION) {
|
||||||
setPlaybackRate(audioPlayer.playbackRate);
|
setPlaybackRate(tabAudioPlayerState.playbackRate);
|
||||||
}
|
}
|
||||||
setPositionState({
|
setPositionState({
|
||||||
duration: proxy.duration || 0,
|
duration: proxy.duration || 0,
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import type { ApiMessage } from '../api/types';
|
|||||||
import type { MessageKey } from './keys/messageKey';
|
import type { MessageKey } from './keys/messageKey';
|
||||||
import { AudioOrigin, GlobalSearchContent } from '../types';
|
import { AudioOrigin, GlobalSearchContent } from '../types';
|
||||||
|
|
||||||
import { requestNextMutation } from '../lib/fasterdom/fasterdom';
|
|
||||||
import { selectCurrentMessageList, selectTabState } from '../global/selectors';
|
import { selectCurrentMessageList, selectTabState } from '../global/selectors';
|
||||||
import { IS_SAFARI } from './browser/windowEnvironment';
|
import { IS_SAFARI } from './browser/windowEnvironment';
|
||||||
import { getMessageServerKey, parseMessageKey } from './keys/messageKey';
|
import { getMessageServerKey, parseMessageKey } from './keys/messageKey';
|
||||||
@ -179,14 +178,15 @@ export function register(
|
|||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if (currentTrackId === trackId) {
|
if (currentTrackId === trackId) {
|
||||||
// Hack, reset `src` to remove default media session notification
|
|
||||||
const prevSrc = audio.src;
|
const prevSrc = audio.src;
|
||||||
audio.pause();
|
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 = '';
|
||||||
audio.src = prevSrc;
|
audio.src = prevSrc;
|
||||||
});
|
}, { once: true });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user