如何解决Safari 和 createMediaElementSource - 没有声音
我正在修复我已移交的项目中的错误。这是一个 React 应用,由一个主视图 (sound-demo) 和一个子组件 (sound-waves) 组成。
用户可以选择几个不同的 mp3 文件进行播放,并会显示伴随的视觉“声波图”。
然而,问题是该页面在 Chrome 中运行良好,但在 safari 中没有音频播放。使用音频播放器的 currentTime 我可以看到文件确实播放了,但我没有声音也没有图表。
主视图如下所示:
const SoundDemo = (props: SoundDemoProps) => {
const [isPlaying,setIsPlaying] = useState<boolean>(false);
const {
setSelected,selected,actionButtons,soundButtons,ModifierSoundButtons,labels,} = props;
const [selectedSound,setSelectedSound] = useState<SoundButtonType>();
const [ModifierSound,setModifierSound] = useState<ModifierSoundButtonType>(
ModifierSoundButtonType.ON,);
// Refs
const audioRef = useRef(new Audio(''));
audioRef.current.addEventListener("ended",() => {
setIsPlaying(false);
setSelectedSound(undefined);
})
const getSource = (sound?: SoundButtonType) => {
return ModifierSound === ModifierSoundButtonType.ON
? getModifierSound(sound || selectedSound!)
: getNonModifierSound(sound || selectedSound!);
};
const updateSource = (source: string,currentTime?: number) => {
if (audioRef.current) {
audioRef.current.pause();
audioRef.current = new Audio(source);
audioRef.current.addEventListener("loadeddata",() => {
if (currentTime) {
audioRef.current.currentTime = currentTime;
}
audioRef.current.play();
});
}
}
const setModifierSoundOnOff = (type: ModifierSoundButtonType) => {
setModifierSound(type);
}
const playSound = (newSelectedSound: SoundButtonType) => {
if (isPlaying &&
selectedSound &&
newSelectedSound === selectedSound
) {
setSelectedSound(undefined);
setIsPlaying(false);
audioRef.current.pause();
} else {
setIsPlaying(false);
setSelectedSound(newSelectedSound);
const src = getSource(newSelectedSound);
updateSource(src);
setIsPlaying(true);
}
};
useEffect(() => {
if (isPlaying) {
const currentTime: number = audioRef.current.currentTime;
const src = getSource();
updateSource(src,currentTime)
} else {
audioRef.current.pause();
setSelectedSound(undefined);
setIsPlaying(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[ModifierSound])
return (... jsx)
}
还有子组件:
import React,{ useCallback,useEffect,useRef } from "react";
import "./sound-waves.scss";
interface SoundWavesProps {
id: string;
player: any;
isPlaying: boolean;
}
const SoundWaves = (props: SoundWavesProps) => {
const { id,player,isPlaying } = props;
const BAR_PAD: number = 10;
const BAR_WIDTH: number = 4;
const MAX_BARS: number = 60;
const canvasRef: any = useRef(null);
const audioCtx: any = useRef(null);
const analyser: any = useRef(null);
const source: any = useRef(null);
function draw_bars(values: [number]) {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
var len = values.length - ~~(values.length / MAX_BARS) * 4;
var normFac = 255;
var maxValue = normFac;
var istep = ~~(len / MAX_BARS);
var step = canvas.width / MAX_BARS;
var x = BAR_WIDTH;
var height = canvas.height - BAR_PAD * 2;
for (var i = 0; i < len; i += istep) {
var v = values[i] / maxValue;
var h = v * height;
var y = height / 2 - h / 2;
ctx.beginPath();
ctx.shadowColor = "rgba(0,0.5)";
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 4;
ctx.strokeStyle = "rgba(255,255,0.9)";
ctx.linewidth = BAR_WIDTH;
ctx.lineCap = "round";
ctx.moveto(x,y);
ctx.lineto(x,y + h);
ctx.stroke();
x += step;
}
}
const mainloop = useCallback(() => {
const canvas = canvasRef.current;
if (canvas) {
canvas.width = 1024 * 0.84;
canvas.height = 100;
const ctx = canvas.getContext("2d");
const fbc: any = new Uint8Array(analyser.current.frequencyBinCount);
analyser.current.getByteFrequencyData(fbc);
ctx.clearRect(0,canvas.width,canvas.height);
draw_bars(fbc);
requestAnimationFrame(mainloop);
}
},[]);
useEffect(() => {
if (isPlaying && canvasRef.current) {
// @ts-ignore
const AudioContext = window.AudioContext || window.webkitaudiocontext;
audioCtx.current = new AudioContext();
analyser.current = audioCtx.current.createAnalyser();
analyser.current.connect(audioCtx.current.destination);
source.current = audioCtx.current.createMediaElementSource(
player.current
);
source.current.connect(analyser.current);
mainloop();
}
},[isPlaying,mainloop,player]);
const wavesClass: string = isPlaying
? "sound-waves sound-waves--show"
: "sound-waves";
return <canvas ref={canvasRef} id={id} className={wavesClass}></canvas>;
};
export default SoundWaves;
如果我从子组件中的 useEffect 中删除以下几行,我会在 Safari 中获得音频,但显然没有图表:
source.current = audioCtx.current.createMediaElementSource(
player.current
);
source.current.connect(analyser.current);
这是由于 Safari 不喜欢 createMediaElementSource 造成的吗?我是否缺少一些与 Safari 相关的权限并需要用户交互或这里发生了什么?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。