微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Safari 和 createMediaElementSource - 没有声音

如何解决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 举报,一经查实,本站将立刻删除。