feature/IO-3377-Add-Notification-Tone-For-Messaging - Finalize
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
// src/utils/soundManager.js
|
||||
// Handles audio init, autoplay unlock, and queued plays.
|
||||
// When a tab successfully unlocks audio, it CLAIMS LEADERSHIP immediately for that bodyshop.
|
||||
|
||||
import { claimLeadershipNow } from "./singleTabAudioLeader";
|
||||
|
||||
let baseAudio = null;
|
||||
let unlocked = false;
|
||||
let queuedPlays = 0;
|
||||
@@ -5,8 +11,8 @@ let installingUnlockHandlers = false;
|
||||
|
||||
/**
|
||||
* Initialize the new-message sound.
|
||||
* @param url
|
||||
* @param volume
|
||||
* @param {string} url
|
||||
* @param {number} volume
|
||||
*/
|
||||
export function initNewMessageSound(url, volume = 0.7) {
|
||||
baseAudio = new Audio(url);
|
||||
@@ -14,27 +20,35 @@ export function initNewMessageSound(url, volume = 0.7) {
|
||||
baseAudio.volume = volume;
|
||||
}
|
||||
|
||||
/** Has this tab unlocked audio? (optional helper) */
|
||||
export function isAudioUnlocked() {
|
||||
return unlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks audio if not already unlocked.
|
||||
* @returns {Promise<void>}
|
||||
* On success, this tab immediately becomes the sound LEADER for the given bodyshop.
|
||||
*/
|
||||
export async function unlockAudio() {
|
||||
export async function unlockAudio(bodyshopId) {
|
||||
if (unlocked) return;
|
||||
try {
|
||||
// Chrome/Safari: playing any media (even muted) after a gesture unlocks audio.
|
||||
const a = new Audio();
|
||||
a.muted = true;
|
||||
await a.play().catch(() => {
|
||||
//
|
||||
// ignore
|
||||
});
|
||||
unlocked = true;
|
||||
|
||||
// Immediately become the leader because THIS tab can actually play sound.
|
||||
claimLeadershipNow(bodyshopId);
|
||||
|
||||
// Flush exactly one queued ding (avoid spamming if many queued while locked)
|
||||
if (queuedPlays > 0 && baseAudio) {
|
||||
queuedPlays = 0;
|
||||
const b = baseAudio.cloneNode(true);
|
||||
b.play().catch(() => {
|
||||
//
|
||||
// ignore
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
@@ -42,31 +56,26 @@ export async function unlockAudio() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs listeners to unlock audio on first gesture.
|
||||
*/
|
||||
function addUnlockListeners() {
|
||||
/** Installs listeners to unlock audio on first gesture. */
|
||||
function addUnlockListeners(bodyshopId) {
|
||||
if (installingUnlockHandlers) return;
|
||||
installingUnlockHandlers = true;
|
||||
const handler = () => unlockAudio();
|
||||
const handler = () => unlockAudio(bodyshopId);
|
||||
window.addEventListener("click", handler, { once: true, passive: true });
|
||||
window.addEventListener("touchstart", handler, { once: true, passive: true });
|
||||
window.addEventListener("keydown", handler, { once: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes listeners to unlock audio on first gesture.
|
||||
*/
|
||||
/** Removes listeners to unlock audio on first gesture. */
|
||||
function removeUnlockListeners() {
|
||||
// No need to remove explicitly with {once:true}, but keep this if you change it later
|
||||
// With {once:true} they self-remove; we only reset the flag.
|
||||
installingUnlockHandlers = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the new-message ding. If blocked, queue one and wait for first gesture.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function playNewMessageSound() {
|
||||
export async function playNewMessageSound(bodyshopId) {
|
||||
if (!baseAudio) return;
|
||||
try {
|
||||
const a = baseAudio.cloneNode(true);
|
||||
@@ -75,14 +84,14 @@ export async function playNewMessageSound() {
|
||||
// Most common: NotAllowedError due to missing prior gesture
|
||||
if (err?.name === "NotAllowedError") {
|
||||
queuedPlays = Math.min(queuedPlays + 1, 1); // cap at 1
|
||||
addUnlockListeners();
|
||||
addUnlockListeners(bodyshopId);
|
||||
|
||||
// Let the app know we need user interaction (optional UI prompt)
|
||||
window.dispatchEvent(new CustomEvent("sound-needs-unlock"));
|
||||
return;
|
||||
}
|
||||
// Other errors can be logged
|
||||
|
||||
|
||||
console.error("Audio play error:", err);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user