Calls: Fix call sounds in iOS (#2216)
This commit is contained in:
parent
cbcfa354e6
commit
6d5625ce0c
@ -5,12 +5,13 @@ import { getActions, withGlobal } from './global';
|
||||
import type { GlobalState } from './global/types';
|
||||
import type { UiLoaderPage } from './components/common/UiLoader';
|
||||
|
||||
import { IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from './util/environment';
|
||||
import { IS_INSTALL_PROMPT_SUPPORTED, IS_MULTITAB_SUPPORTED, PLATFORM_ENV } from './util/environment';
|
||||
import { INACTIVE_MARKER, PAGE_TITLE } from './config';
|
||||
import { selectTabState } from './global/selectors';
|
||||
import { updateSizes } from './util/windowSize';
|
||||
import { addActiveTabChangeListener } from './util/activeTabMonitor';
|
||||
import { hasStoredSession } from './util/sessions';
|
||||
import { setupBeforeInstallPrompt } from './util/installPrompt';
|
||||
import buildClassName from './util/buildClassName';
|
||||
import { parseInitialLocationHash } from './util/routing';
|
||||
import useFlag from './hooks/useFlag';
|
||||
@ -55,6 +56,12 @@ const App: FC<StateProps> = ({
|
||||
const { isMobile } = useAppLayout();
|
||||
const isMobileOs = PLATFORM_ENV === 'iOS' || PLATFORM_ENV === 'Android';
|
||||
|
||||
useEffect(() => {
|
||||
if (IS_INSTALL_PROMPT_SUPPORTED) {
|
||||
setupBeforeInstallPrompt();
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Prevent drop on elements that do not accept it
|
||||
useEffect(() => {
|
||||
const body = document.body;
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
import { IS_IOS, IS_SAFARI } from '../util/environment';
|
||||
import { initializeSoundsForSafari } from '../global/actions/ui/calls';
|
||||
|
||||
export { default as GroupCall } from '../components/calls/group/GroupCall';
|
||||
export { default as ActiveCallHeader } from '../components/calls/ActiveCallHeader';
|
||||
export { default as PhoneCall } from '../components/calls/phone/PhoneCall';
|
||||
export { default as RatePhoneCallModal } from '../components/calls/phone/RatePhoneCallModal';
|
||||
|
||||
if (IS_SAFARI || IS_IOS) {
|
||||
document.addEventListener('click', initializeSoundsForSafari, { once: true });
|
||||
}
|
||||
|
||||
@ -32,6 +32,8 @@ import { waitForTransitionEnd } from '../../util/cssAnimationEndListeners';
|
||||
import { processDeepLink } from '../../util/deeplink';
|
||||
import { parseInitialLocationHash, parseLocationHash } from '../../util/routing';
|
||||
import { fastRaf } from '../../util/schedulers';
|
||||
import { Bundles, loadBundle } from '../../util/moduleLoader';
|
||||
import updateIcon from '../../util/updateIcon';
|
||||
|
||||
import useEffectWithPrevDeps from '../../hooks/useEffectWithPrevDeps';
|
||||
import useBackgroundMode from '../../hooks/useBackgroundMode';
|
||||
@ -43,7 +45,7 @@ import useShowTransition from '../../hooks/useShowTransition';
|
||||
import { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';
|
||||
import useInterval from '../../hooks/useInterval';
|
||||
import useAppLayout from '../../hooks/useAppLayout';
|
||||
import updateIcon from '../../util/updateIcon';
|
||||
import useTimeout from '../../hooks/useTimeout';
|
||||
|
||||
import StickerSetModal from '../common/StickerSetModal.async';
|
||||
import UnreadCount from '../common/UnreadCounter';
|
||||
@ -132,6 +134,7 @@ type StateProps = {
|
||||
};
|
||||
|
||||
const APP_OUTDATED_TIMEOUT_MS = 5 * 60 * 1000; // 5 min
|
||||
const CALL_BUNDLE_LOADING_DELAY_MS = 5000; // 5 sec
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
let DEBUG_isLogged = false;
|
||||
@ -222,6 +225,11 @@ const Main: FC<OwnProps & StateProps> = ({
|
||||
console.log('>>> RENDER MAIN');
|
||||
}
|
||||
|
||||
// Preload Calls bundle to initialize sounds for iOS
|
||||
useTimeout(() => {
|
||||
void loadBundle(Bundles.Calls);
|
||||
}, CALL_BUNDLE_LOADING_DELAY_MS);
|
||||
|
||||
const { isDesktop } = useAppLayout();
|
||||
useEffect(() => {
|
||||
if (!isLeftColumnOpen && !isMiddleColumnOpen && !isDesktop) {
|
||||
|
||||
@ -6,7 +6,7 @@ import { updateChat } from '../../reducers';
|
||||
import { ARE_CALLS_SUPPORTED } from '../../../util/environment';
|
||||
import { notifyAboutCall } from '../../../util/notifications';
|
||||
import { selectGroupCall, selectPhoneCallUser } from '../../selectors/calls';
|
||||
import { checkNavigatorUserMediaPermissions, initializeSoundsForSafari } from '../ui/calls';
|
||||
import { checkNavigatorUserMediaPermissions, initializeSounds } from '../ui/calls';
|
||||
import { onTickEnd } from '../../../util/schedulers';
|
||||
import type { ActionReturnType } from '../../types';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
@ -115,7 +115,7 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => {
|
||||
});
|
||||
});
|
||||
|
||||
void initializeSoundsForSafari();
|
||||
initializeSounds();
|
||||
void checkNavigatorUserMediaPermissions(global, actions, call.isVideo, getCurrentTabId());
|
||||
global = {
|
||||
...global,
|
||||
|
||||
@ -26,16 +26,43 @@ import * as langProvider from '../../../util/langProvider';
|
||||
import { updateTabState } from '../../reducers/tabs';
|
||||
import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
|
||||
// Workaround for Safari not playing audio without user interaction
|
||||
// This is a tiny MP3 file that is silent - retrieved from https://bigsoundbank.com and then modified
|
||||
// eslint-disable-next-line max-len
|
||||
const silentSound = 'data:audio/mpeg;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV';
|
||||
|
||||
let audioElement: HTMLAudioElement | undefined;
|
||||
let audioContext: AudioContext | undefined;
|
||||
|
||||
let sounds: Record<CallSound, HTMLAudioElement>;
|
||||
let initializationPromise: Promise<void> | undefined = Promise.resolve();
|
||||
|
||||
export const initializeSoundsForSafari = () => {
|
||||
if (!initializationPromise) return Promise.resolve();
|
||||
// Workaround: this function is called once on the first user interaction.
|
||||
// After that, it will be possible to play the notification on iOS without problems.
|
||||
// https://rosswintle.uk/2019/01/skirting-the-ios-safari-audio-auto-play-policy-for-ui-sound-effects/
|
||||
export function initializeSoundsForSafari() {
|
||||
initializeSounds();
|
||||
|
||||
return Promise.all(Object.values(sounds).map((sound) => {
|
||||
const prevSrc = sound.src;
|
||||
sound.src = silentSound;
|
||||
sound.muted = true;
|
||||
sound.volume = 0.0001;
|
||||
return sound.play()
|
||||
.then(() => {
|
||||
sound.pause();
|
||||
sound.volume = 1;
|
||||
sound.currentTime = 0;
|
||||
sound.muted = false;
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
sound.src = prevSrc;
|
||||
});
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
export function initializeSounds() {
|
||||
if (sounds) {
|
||||
return;
|
||||
}
|
||||
const joinAudio = new Audio('./voicechat_join.mp3');
|
||||
const connectingAudio = new Audio('./voicechat_connecting.mp3');
|
||||
connectingAudio.loop = true;
|
||||
@ -60,22 +87,7 @@ export const initializeSoundsForSafari = () => {
|
||||
busy: busyAudio,
|
||||
ringing: ringingAudio,
|
||||
};
|
||||
|
||||
initializationPromise = Promise.all(Object.values(sounds).map((sound) => {
|
||||
sound.muted = true;
|
||||
sound.volume = 0.0001;
|
||||
return sound.play().then(() => {
|
||||
sound.pause();
|
||||
sound.volume = 1;
|
||||
sound.currentTime = 0;
|
||||
sound.muted = false;
|
||||
});
|
||||
})).then(() => {
|
||||
initializationPromise = undefined;
|
||||
});
|
||||
|
||||
return initializationPromise;
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchGroupCall<T extends GlobalState>(global: T, groupCall: Partial<ApiGroupCall>) {
|
||||
const result = await callApi('getGroupCall', {
|
||||
@ -258,7 +270,7 @@ addActionHandler('joinGroupCall', async (global, actions, payload): Promise<void
|
||||
|
||||
createAudioElement();
|
||||
|
||||
await initializeSoundsForSafari();
|
||||
initializeSounds();
|
||||
global = getGlobal();
|
||||
void checkNavigatorUserMediaPermissions(global, actions, true, tabId);
|
||||
|
||||
@ -338,11 +350,7 @@ addActionHandler('playGroupCallSound', (global, actions, payload): ActionReturnT
|
||||
safePlay(sounds[sound]);
|
||||
};
|
||||
|
||||
if (initializationPromise) {
|
||||
initializationPromise.then(doPlay);
|
||||
} else {
|
||||
doPlay();
|
||||
}
|
||||
doPlay();
|
||||
});
|
||||
|
||||
addActionHandler('loadMoreGroupCallParticipants', (global): ActionReturnType => {
|
||||
@ -376,7 +384,7 @@ addActionHandler('requestCall', async (global, actions, payload): Promise<void>
|
||||
return;
|
||||
}
|
||||
|
||||
await initializeSoundsForSafari();
|
||||
initializeSounds();
|
||||
global = getGlobal();
|
||||
void checkNavigatorUserMediaPermissions(global, actions, isVideo, tabId);
|
||||
|
||||
|
||||
@ -8,8 +8,7 @@ import {
|
||||
getActions, getGlobal,
|
||||
} from './global';
|
||||
import updateWebmanifest from './util/updateWebmanifest';
|
||||
import { setupBeforeInstallPrompt } from './util/installPrompt';
|
||||
import { IS_INSTALL_PROMPT_SUPPORTED, IS_MULTITAB_SUPPORTED } from './util/environment';
|
||||
import { IS_MULTITAB_SUPPORTED } from './util/environment';
|
||||
import './global/init';
|
||||
|
||||
import { APP_VERSION, DEBUG, MULTITAB_LOCALSTORAGE_KEY } from './config';
|
||||
@ -59,10 +58,6 @@ async function init() {
|
||||
|
||||
updateWebmanifest();
|
||||
|
||||
if (IS_INSTALL_PROMPT_SUPPORTED) {
|
||||
setupBeforeInstallPrompt();
|
||||
}
|
||||
|
||||
TeactDOM.render(
|
||||
<App />,
|
||||
document.getElementById('root')!,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user