V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
qianzhu
V2EX  ›  JavaScript

MediaRecorder 有什么办法在录制过程中动态添加/改变音频轨道吗?

  •  
  •   qianzhu · 156 天前 · 681 次点击
    这是一个创建于 156 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我现在想实现一个需求:在录制前指定是否开启麦克风,在录制期间也可以开关麦克风。录制开始时,录制屏幕 + 选择的设备。

    我的尝试:

    方式一:先创建屏幕录制,然后在需要添加麦克风时 addTrack

    1. 先只创建屏幕录制,recorder
    2. 如果开启了麦克风,recorder.stream.addTrack(${audioTrack})
    3. 如果需要开启麦克风,使用上面同样的方式

    代码大致如下:

    const recorder = new MediaRecorder(
        new MediaStream([
            ...(await getUserScreenStream(this.id)).getVideoTracks()
        ])
    )
    
    
    // add audio track if needed
    if (store.selectedAudioInput) {
    	recorder.stream.addTrack((await getUserAudioStream(store.selectedAudioInput)).getAudioTracks()[0])
    }
    

    这种方式在 addTrack 调用时会自动触发 recorderstop 事件。也就是说如果我还继续想使用这个思路的话不可避免的需要考虑重新开启一个 recorder 然后将原来断的和新的 combine 一下。

    方式二:使用 AudioContext 创建一个 MediaStream ,然后使用 MediaStream 去创建 recorder

    1. 根据 AudioContext 创建 mediaStreamAudioDestinationNode
    2. 根据 mediaStreamAudioDestinationNode.stream 中的音频和屏幕 stream 创建 recorder
    3. 如果开启了麦克风,使用 MediaStreamAudioSourceNode 对象去 connect mediaStreamAudioDestinationNode,从而实现 recorder 音频流的更新。
    4. 如果需要开启麦克风,使用上面同样的方式

    但是这种方式有个问题。如果一开始创建时没有开启麦克风,也就是说没有 connect 音频流时 recorder 不会触发 ondataavailable 事件。也就是说没有正确的被录制。

    而对于要实现的需求,一开始没有打开麦克风是有可能的。

    大致代码如下:

    this.audioContext = new AudioContext()
    this.mediaStreamAudioDestinationNode = new MediaStreamAudioDestinationNode(this.audioContext)
    
    const recorder = new MediaRecorder(
        new MediaStream([
            ...this.mediaStreamAudioDestinationNode.stream.getAudioTracks(),
            ...(await getUserScreenStream(this.id)).getVideoTracks()
        ])
    )
    
    // connect stream
    if (store.selectedAudioInput) {
        const mediaStreamAudioSourceNode = new MediaStreamAudioSourceNode(this.audioContext, {
            mediaStream: await getUserAudioStream(devicesStore.selectedAudioInput)
        })
    
        mediaStreamAudioSourceNode.connect(this.mediaStreamAudioDestinationNode)
    }
    

    所以我的问题是,有没有什么简单的办法可以实现我的需求呢?目前这两种方式只有第一种可行,而在设计上感觉又不太合理。我还有一种想法是,将这两种流分开录制,最后再按照时间来进行合并。但是这样的工作量有点大。大家有什么解决思路或想法吗?

    2 条回复    2023-11-24 13:30:15 +08:00
    chnwillliu
        1
    chnwillliu  
       155 天前 via Android
    换个思路,关闭麦克风音轨音量调成 0 ,打开再恢复行么?不一定要真的把 audioTrack 移除。

    See GainNode
    qianzhu
        2
    qianzhu  
    OP
       155 天前
    @chnwillliu 哇,你好聪明!!非常感谢!我试试看!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2722 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:21 · PVG 19:21 · LAX 04:21 · JFK 07:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.