如何从C ++插件中的'MediaStream'对象读取音频数据


70

经过流血和眼泪,我终于设法建立了一个Node C ++附加组件,并将一个Web平台标准MediaStream对象永久地推入其C ++方法之一。为了在不同的V8和Node.js版本之间实现兼容性,我将原生抽象用于Node.js(nan)

插件

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

addon.js

setStream(new MediaStream());

对于它的价值,它可以正常工作(即,它不会消除渲染器进程的视线),并且我可以验证MediaStream对象的存在,例如,通过从C ++方法返回其构造函数名称:

插件

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

当从JavaScript通过调用时setStream,这将返回字符串MediaStream,因此该对象肯定在那里。我还可以返回mediaStream对象本身,并且一切都会正常运行,因此确实是我需要的对象。

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


赏金更新

我知道,如果我自己编译Electron和/或Chromium,这样做会更容易/可行,但我不想参与该维护工作。

我想知道是否可以不这样做,就我的研究而言,我深信我需要两件事来完成此任务:

  1. 相关的头文件,我相信会公开应该足够了
  2. 铬/闪烁库文件(?),用于解析外部符号,类似于node.dylib文件

而且,正如我所说,我相信自己可以自己编译Chrome / blink,然后获得这个lib文件,但这将为Electron带来麻烦。考虑到这一点,我相信这个问题最终可以归结为C ++链接问题。还有其他方法可以做我想要的吗?

编辑

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

编辑2

AudioWorklets在Electron中已经存在了一段时间,与ScriptProcessorNode(或更糟糕的是,AnalyzerNode)不同,具有低延迟并且对于实时C ++支持的音频处理来说非常可靠。

在我的应用程序(AudioNodes)中,我已经为实验性的VST插件主机原型(很可能是第一个Web Audio API)实现了这种方法。

如果有人想继续写一个基于AudioWorklet的答案,我会很乐意接受,但要提防:这是一个非常先进的领域,而且洞洞很深,即使在非常简单,通用的应用程序之前也要克服无数障碍传递原型(特别是因为当前在Electron中需要原子同步的缓冲跨线程音频处理才能实现此目的,因为https://github.com/electron/electron/issues/22503-尽管获取本机将C ++插件添加到一个音频渲染器线程(更不用说同时使用多个线程)可能同样具有挑战性。


3
我没收到你的问题。但是您可以检查以下两个:github.com/common-tater/wkwebview-getusermedia-shim/blob/master / ... ... realtimeweekly.co
nullqube

@nullqube我一直在为这个任务签出WebRTC,但似乎无法流传输未压缩的原始音频。如果可能,我可以简单地启动一个新的Electron窗口进程,在那里传输音频,在该单独的窗口进程中执行基于ScriptProcessorNode的处理,然后流回。但是,总会有大量的有损压缩硬编码到WebRTC中,并且延迟非常长。
John Weisz

这有帮助吗?discuss.atom.io/t/...
nullqube

您是否尝试WebWorker过在JavaScript方面将您的工作转移到“后台线程”中,然后从中调用C ++部分?
user9335240 '18 -10-14

3
仅使用V8 API不可能做到这一点。如果您能够了解电子版或铬版的Blink引擎版本,则可以将AudioDestinationConsumer添加到媒体流中音轨之一的源中。 cs.chromium.org/chromium/src/third_party/blink/renderer/… 我目前尚未测试过,但是几个月后,我会并发布更详细的答案:)
WolverinDEV

Answers:


2

MediaStream标头是Blink渲染器模块的一部分,对于我来说,如何从nan插件中检索它并不是很明显。

因此,让我们来看一下您拥有的,即v8 :: Object。我相信v8 :: Object可以提供您所需的所有功能,它具有:

  • GetPropertyNames()
  • 获取(上下文,索引)
  • 设置(上下文,键,值)
  • 有(上下文,键)

除非您确实需要严格定义的接口,否则为什么不完全避免该问题,而仅使用现有的动态类型?

为了专门获取音频数据,您需要在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()();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.