如何在C++插件中从“MediaStream”对象中读取音频数据

69

经过艰苦努力,我终于成功地建立了一个 Node C++ 插件,并将 web 平台标准的 MediaStream 对象放入其中一个 C++ 方法中。为了在不同的 V8 和 Node.js 版本之间保持兼容性,我正在使用 Native Abstractions for Node.js (nan)

addon.cc

NAN_METHOD(SetStream)
{
    Nan::HandleScope scope;
    v8::Local<v8::Object> mediaStream = info[0]->ToObject();
}

插件.js

setStream(new MediaStream());

就我所知,这段代码是正确的(即它不会立即摧毁渲染进程),并且我可以验证MediaStream对象的存在,例如通过从C++方法返回其构造函数名称:

addon.cc

info.GetReturnValue().Set(mediaStream->GetConstructorName());

当通过setStream从JavaScript调用时,它将返回字符串MediaStream,因此该对象肯定存在。我也可以返回mediaStream对象本身,一切都将正常工作,所以这确实是我需要的对象。

那么,我如何从C++中读取此MediaStream对象的音频数据(即音频样本)? 顺便说一下,实际的数据读取(和处理)将在一个单独的std :: thread中完成。


Bounty Update

我明白如果我编译Electron和/或Chromium,则可能会更容易/可能,但我宁愿不涉足维护地狱。

我想知道是否有可能在不这样做的情况下完成,就我所知,我相信我需要以下两件事才能完成:

  1. 相关的头文件,我相信blink public应该足够。
  2. 一个chromium / blink库文件(?),类似于node.dylib文件,用于解析外部符号

此外,正如我所说,我相信我可以编译chromium / blink,然后我将拥有这个lib文件,但是这将是Electron的维护地狱。考虑到这一点,我认为这个问题最终归结为C ++链接问题。是否有其他方法可以做到我要寻找的内容?

Edit

ScriptProcessorNode在我的情况下不是选项,因为它的性能使其在生产中几乎无法使用。这将需要在ui / main线程上处理音频样本,这绝对是疯狂的。

Edit 2

AudioWorklets在Electron中已经可用了一段时间,与ScriptProcessorNode(或更糟的AnalyzerNode)不同,它是低延迟的,并且非常可靠,可用于真正的C ++支持音频处理,即使在实时环境中也是如此。

如果有人想编写基于AudioWorklet的答案,我将非常乐意接受,但请注意:这是一个非常高级的领域,是一个非常深的兔子洞,在甚至简单的通用通过原型之前有无数的障碍要克服(特别是因为当前在Electron中,需要原子同步,缓冲区跨线程音频处理才能完成,因为https://github.com/electron/electron/issues/22503,尽管将本机C ++附加组件引入一个音频渲染器线程,更不用说同时在多个线程中,可能同样具有挑战性)。


3
我不太明白你的问题。但是你可以查看这两个链接:https://github.com/common-tater/wkwebview-getusermedia-shim/blob/master/WKWebViewGetUserMediaShim/WKWebViewGetUserMediaShim.m 和 http://realtimeweekly.co/how-to-use-webrtc-in-your-ios-projects-part-ii/。 - nullqube
@nullqube 我一直在研究WebRTC来完成这个任务,但似乎无法流式传输原始的未压缩音频。如果可能的话,我可以简单地启动一个新的Electron窗口进程,在那里流式传输音频,在该单独的窗口进程中进行基于ScriptProcessorNode的处理,然后再流回来。但是WebRTC中总是有大量的有损压缩“硬编码”,以及非常高的延迟。 - John Weisz
这有帮助吗?https://discuss.atom.io/t/multiple-streaming-recording-in-media-recorder/54239 - nullqube
3
仅通过V8 API是不可能实现的。如果您能够知道Electron或Chromium版本中Blink引擎的版本,则可以将AudioDestinationConsumer添加到媒体流中一个音轨的源。链接为:https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/mediastream/media_stream_source.h?sq=package:chromium&g=0&l=123。我目前还没有测试过,但几个月后我会测试并发布更详细的答案 :) - WolverinDEV
你说这是一个连接器问题/维护地狱-我不太明白-你能详细说明一下为什么吗? - darune
显示剩余5条评论
1个回答

1
媒体流标题是 Blink 的 渲染模块 的一部分,我不确定如何从 nan 插件中检索它。
因此,让我们看看您拥有什么,即一个 v8::Object。我相信 v8::Object 公开了您需要的所有功能,它具有:
  • GetPropertyNames()
  • Get(context, index)
  • Set(context, key, value)
  • Has(context, key)
除非您真正需要严格定义的接口,否则为什么不完全避免问题并只使用您已经拥有的动态类型?
要特别获取音频数据,您需要在 v8::Object 上调用 getAudioTracks(),它可能看起来像这样?
注意:我认为您不需要上下文,v8似乎对其为空感到满意:v8/src/api/api.cc 应该看起来像这样,再加上一些类型在v8中的输入和输出。

v8::MaybeLocal<v8::Value> get_audio_tracks = mediaStream->Get("getAudioTracks");
// Maybe needs to be v8::Object or array?
if (!get_audio_tracks.IsEmpty()) {
    v8::Local<v8::Value> audio_tracks = get_audio_tracks.ToLocalChecked()();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接