[ad_1]
I am getting the next error on IOS when i attempt to play a audio file.
Unhandled Runtime Error
NotAllowedError: The request shouldn’t be allowed by the consumer agent or the platform within the present context, presumably as a result of the consumer denied permission.
Name Stack
play
[native code]
dispatchEvent
[native code]
Right here is the code of the customized participant:
export interface IAudioPlayer {
src: string;
onPlay?: () => void;
}
export const AudioPlayer: FC<IAudioPlayer> = (props) => {
const { src, onPlay } = props;
const audioRef = useRef<HTMLAudioElement>(null);
const [base64Src, setBase64Src] = useState<string | undefined>(undefined);
const [{ status, playing, muted, currentTime }, dispatch] = useReducer<typeof audioReducer, null>(
audioReducer,
null,
() => ({
standing: "idle",
enjoying: false,
muted: false,
currentTime: getTimeCodeFromNum(0),
}),
);
const translate = useTranslations();
const pressToPlay = translate((t) => t.media.pressToPlayLabel, "[Press to play]");
const bufferingMessage = translate((t) => t.media.bufferingMessage, "[Buffering...]");
const togglePlaying = async () => {
swap (standing) {
case "idle": {
dispatch({ sort: "FETCHING" });
const audio = await fetchAudio(src);
setBase64Src(audio);
break;
}
case "canPlay": {
dispatch({ sort: "TOGGLE_PLAYING" });
break;
}
default:
break;
}
};
useEffect(() => {
const audioElement = audioRef.present;
if (audioElement && enjoying === true) {
const stopPlaying = () => dispatch({ sort: "TOGGLE_PLAYING", overridePlaying: false });
audioElement.addEventListener("ended", stopPlaying);
const interval = setInterval(
() => dispatch({ sort: "UPDATE_CURRENT_TIME", currentTime: audioElement.currentTime }),
500,
);
return () => {
audioElement.removeEventListener("ended", stopPlaying);
clearInterval(interval);
};
}
}, [audioRef, playing]);
useEffect(() => {
if (standing === "canPlay") {
if (enjoying) {
audioRef.present?.play();
onPlay?.();
} else {
audioRef.present?.pause();
}
}
}, [status, playing, onPlay]);
useEffect(() => {
dispatch({ sort: "RESET" });
}, [src]);
return (
<div className="flex flex-row justify-center items-center wager rounded-full border border-theme-blue-500 py-2 px-4">
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
<audio
src={base64Src ?? undefined}
ref={audioRef}
muted={muted}
onLoadedMetadata={() => dispatch({ sort: "CAN_PLAY" })}
/>
<button
sort="button"
onClick={togglePlaying}
disabled={standing === "buffering"}
className="transition duration-300 ease-in-out remodel hover:scale-105 h-40px w-40px bg-theme-blue-700 text-white rounded-full focus:outline-none disabled:opacity-50"
>
<SvgIcon className="block w-35px h-35px m-auto" iconName={enjoying ? "pause" : "play"} />
</button>
<div className="flex items-center justify-center px-4 min-w-0 lg:min-w-170px">
{standing === "canPlay" && `${currentTime} / ${getTimeCodeFromNum(audioRef.present?.period)}`}
{standing === "buffering" && bufferingMessage}
{standing === "idle" && pressToPlay}
</div>
<button
sort="button"
onClick={() => dispatch({ sort: "TOGGLE_MUTED" })}
className="transition duration-300 ease-in-out remodel hover:scale-105 h-30px w-30px bg-theme-blue-700 text-white rounded-full focus:outline-none"
>
<SvgIcon className="block w-20px h-20px m-auto" iconName={muted ? "volume-off" : "volume-up"} />
</button>
</div>
);
};
interface IAudioReducerState "buffering"
sort IAudioReducerAction =
| { sort: "CAN_PLAY" }
| { sort: "TOGGLE_PLAYING"; overridePlaying?: boolean }
| { sort: "TOGGLE_MUTED" }
| { sort: "UPDATE_CURRENT_TIME"; currentTime?: quantity }
| { sort: "FETCHING" }
| { sort: "RESET" };
const audioReducer: Reducer<IAudioReducerState, IAudioReducerAction> = (prevState, motion) => {
swap (motion.sort) {
case "CAN_PLAY": {
return {
...prevState,
standing: "canPlay",
enjoying: true,
};
}
case "FETCHING": {
return {
...prevState,
standing: "buffering",
};
}
case "TOGGLE_PLAYING":
return {
...prevState,
enjoying: motion.overridePlaying ?? !prevState.enjoying,
};
case "TOGGLE_MUTED": {
return {
...prevState,
muted: !prevState.muted,
};
}
case "UPDATE_CURRENT_TIME": {
return {
...prevState,
currentTime: getTimeCodeFromNum(motion.currentTime),
};
}
case "RESET": {
return {
standing: "idle",
enjoying: false,
muted: false,
currentTime: getTimeCodeFromNum(0),
};
}
default:
return prevState;
}
};
export const fetchAudio = async (src: string): Promise<string> => {
const audioBlob = await get("/" + src);
const reader = new FileReader();
return new Promise(async (resolve) => {
const blob = await audioBlob.blob();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.end result as string);
});
};
perform getTimeCodeFromNum(period: quantity | undefined): string {
if (period === null || period === undefined) return "";
let seconds = parseInt(period.toString(), 10);
let minutes = parseInt((period / 60).toString(), 10);
seconds -= minutes * 60;
const hours = parseInt((minutes / 60).toString(), 10);
minutes -= hours * 60;
if (hours === 0) {
return `${minutes}:${String(seconds % 60).padStart(2, "0")}`;
}
return `${String(hours).padStart(2, "0")}:${minutes}:${String(seconds % 60).padStart(2, "0")}`;
}
[ad_2]
