0

我第一次尝试使用 WebAudio API 和 React。

我的想法是构建一个简单的按钮,一旦点击,就会开始或停止声音。

使用以下代码,我总是收到错误“无法在‘AudioNode’上执行‘断开’:给定的目的地未连接。”

我该如何解决?谢谢!

import { useState } from 'react';

function App() {
  const [ dataPlaying, setDataPlaying ] = useState(false) 

  const AudioContext = window.AudioContext || window.webkitAudioContext
  const audioContext = new AudioContext()

  let osc = audioContext.createOscillator()
    osc.type = 'sine'
    osc.frequency.value = 880

  const createOscillator = () => {
    if (dataPlaying === false) {
      osc.start()
      osc.connect(audioContext.destination)
      setDataPlaying(true)
    } else {
      osc.disconnect(audioContext.destination)
      setDataPlaying(false)
    }
  }
    
  return (
    <div className="App">
      <button 
        onClick={() => createOscillator() }
        data-playing={ dataPlaying }>
        <span>Play/Pause</span>
      </button>  
    </div>
  );
}

export default App;
4

1 回答 1

2

这是我解决连接错误的尝试。

  1. 创建AudioContext组件的外部。
  2. 使用useRef挂钩来存储音频上下文以在重新渲染中持续存在。
  3. 使用useEffect挂钩来实例化振荡器并管理 audo 上下文连接。
  4. 使用启动/停止切换器来暂停或恢复上下文,而不是与其连接/断开连接。

更新代码

import React, { useEffect, useRef, useState } from "react";

const AudioContext = window.AudioContext || window.webkitAudioContext;

export default function App() {
  const [dataPlaying, setDataPlaying] = useState(false);
  const audioContextRef = useRef();

  useEffect(() => {
    const audioContext = new AudioContext();
    const osc = audioContext.createOscillator();
    osc.type = "sine";
    osc.frequency.value = 880;

    // Connect and start
    osc.connect(audioContext.destination);
    osc.start();

    // Store context and start suspended
    audioContextRef.current = audioContext;
    audioContext.suspend();

    // Effect cleanup function to disconnect
    return () => osc.disconnect(audioContext.destination);
  }, []);

  const toggleOscillator = () => {
    if (dataPlaying) {
      audioContextRef.current.suspend();
    } else {
      audioContextRef.current.resume();
    }
    setDataPlaying((play) => !play);
  };

  return (
    <div className="App">
      <button onClick={toggleOscillator} data-playing={dataPlaying}>
        <span>{dataPlaying ? "Pause" : "Play"}</span>
      </button>
    </div>
  );
}

编辑振荡器内置反应挂钩不会停止

于 2020-11-02T21:15:25.213 回答