首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >scriptNode.onaudioprocess被否决了,还有别的选择吗?

scriptNode.onaudioprocess被否决了,还有别的选择吗?
EN

Stack Overflow用户
提问于 2020-12-25 10:27:15
回答 2查看 5.4K关注 0票数 4

我想在说话的时候得到音频缓冲区,我做了这个方法来检测它,但是我收到消息这个音频进程上的方法是不推荐的,并且不会被触发,是否有任何替代它的例子。

代码语言:javascript
运行
复制
audioContext = new AudioContext({ sampleRate: 16000 });
scriptNode = (audioContext.createScriptProcessor || audioContext.createJavaScriptNode).call(audioContext, 1024, 1, 1);
scriptNode.onaudioprocess = function (audioEvent) {
  if (recording) {
    input = audioEvent.inputBuffer.getChannelData(0);
    // convert float audio data to 16-bit PCM
    var buffer = new ArrayBuffer(input.length * 2);
    var output = new DataView(buffer);
    for (var i = 0, offset = 0; i < input.length; i++, offset += 2) {
      var s = Math.max(-1, Math.min(1, input[i]));
      output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
    }
    ws.send(buffer);
  }
};
EN

回答 2

Stack Overflow用户

发布于 2020-12-25 12:58:57

使用MediaStream记录APIMediaDevices.getUserMedia()方法,您可以从麦克风和流中将音频传输到录音机中。然后,每当Blob事件在记录器上触发时,记录器就可以通过WebSockets发送ondataavailable对象。

下面的函数创建一个流并将其传递给一个MediaRecorder实例。该实例将记录您的麦克风音频,并能够将其发送到您的WebSocket。返回MediaRecorder实例以控制记录器。

代码语言:javascript
运行
复制
async function streamMicrophoneAudioToSocket(ws) {
  let stream;
  const constraints = { video: false, audio: true };

  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
  } catch (error) {
    throw new Error(`
      MediaDevices.getUserMedia() threw an error. 
      Stream did not open.
      ${error.name} - 
      ${error.message}
    `);
  }

  const recorder = new MediaRecorder(stream);

  recorder.addEventListener('dataavailable', ({ data }) => {
    ws.send(data);
  });

  recorder.start();
  return recorder;
});

这样,您还可以通过调用记录器上的方法来停止录制。

代码语言:javascript
运行
复制
(async () => {
  const ws = new WebSocket('ws://yoururl.com');
  const recorder = await streamMicrophoneAudioToSocket(ws);

  document.addEventListener('click', event => {
    recorder.stop();
  });
}());
票数 3
EN

Stack Overflow用户

发布于 2021-10-11 09:55:18

Sidenote:虽然我早些时候的回答确实帮助了一些人,但它并没有提供替代事件与ScriptProcessorNode接口的方法。这是答案,应该为任择议定书的问题提供一个替代方案。

答案应该是使用音频工作区 with使我们能够创建自定义音频处理节点,这些节点可以像普通的AudioNode那样实现。

Web的AudioWorkletNode接口表示用户定义的AudioNode的基类,它可以连接到音频路由图以及其他节点。它有一个关联的AudioWorkletProcessor,它在Web呈现线程中执行实际的音频处理。

它通过扩展AudioWorkletProcessor类和提供强制的process方法来工作。process方法公开静态parameterDescriptors getter中的inputsoutputsparameters集。

在这里,您可以插入与onaudioprocess回调相同的逻辑。但你必须做些修改才能正常工作。

使用worklets的一个缺点是,您必须将此脚本作为来自worklets接口的文件。这意味着任何依赖项,如ws变量,都需要在稍后阶段注入。我们可以扩展类以将任何值或依赖项添加到worklet的实例中。

注意: process需要返回布尔值来让浏览器知道音频节点是否应该保持活动。

代码语言:javascript
运行
复制
registerProcessor('buffer-detector', class extends AudioWorkletProcessor {
  process (inputs, outputs, parameters) {
    if (this.socket === null) {
      return false;
    }

    if (this._isRecording === true) {
      const [input] = inputs;
      const buffer = new ArrayBuffer(input.length * 2);
      const output = new DataView(buffer);

      for (let i = 0, offset = 0; i < input.length; i++, offset += 2) {
        const s = Math.max(-1, Math.min(1, input[i]));
        output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
      }

      this.socket.send(buffer);
    }

    return true;
  }

  static get parameterDescriptors() {
    return [{
      name: 'Buffer Detector',
    }]
  }

  constructor() {
    super();
    this._socket = null;
    this._isRecording = false;
  }

  get socket() {
    return this._socket;
  }

  set socket(value) {
    if (value instanceof WebSocket) {
      this._socket = value;
    }
  }

  get recording() {
    return this._isRecording;
  }

  set recording(value) {
    if ('boolean' === typeof value) {
      this._isRecording = value;
    }
  }
});

现在,我们所要做的就是在脚本中包含worklet,并创建节点的实例。我们可以使用存在于addModule属性上的BaseAudioContext.audioWorklet方法来实现这一点。

重要:只添加模块在安全(HTTPS)上下文中工作。

成功添加模块后,使用AudioWorkletNode构造函数创建新节点。分配WebSocket实例,设置记录标志,您就可以开始了。

代码语言:javascript
运行
复制
const ws = new WebSocket('ws://...');
const audioContext = new AudioContext();
const source = new MediaStreamAudioSourceNode(audioContext, {
  mediaStream: stream // Your stream here.
});

// In an async context
await audioContext.audioWorklet.addModule('buffer-detector.js');

// Create our custom node.
const bufferDetectorNode = new AudioWorkletNode(audioContext, 'buffer-detector');

// Assign the socket and the recording state.
bufferDetectorNode.socket = ws;
bufferDetectorNode.recording = true;

// Connect the node.
source.connect(bufferDetectorNode);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65447236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档