更改 WebRTC 流中的播放延迟

2023-12-21

我正在尝试将实时 MediaStream(最终来自摄像机)从对等点 A 投射到对等点 B,并且我希望对等点 B 实时接收实时流,然后以增加的延迟重播它。不幸的是,不可能简单地暂停流并继续播放,因为它会跳转到实时时刻。

所以我发现我可以使用 MediaRecorder + SourceBuffer 重新观看直播。记录流并将缓冲区附加到 MSE (SourceBuffer) 并在 5 秒后播放。 这在本地设备(流)上有效。但是当我尝试在接收器 MediaStream 上使用 Media Recorder (来自pc.onaddstream) 看起来它获取了一些数据并且能够将缓冲区附加到 sourceBuffer 中。但它不会重播。有时我只得到一帧。

const [pc1, pc2] = localPeerConnectionLoop()
const canvasStream = canvas.captureStream(200)

videoA.srcObject = canvasStream
videoA.play()

// Note: using two MediaRecorder at the same time seem problematic
// But this one works
// stream2mediaSorce(canvasStream, videoB)
// setTimeout(videoB.play.bind(videoB), 5000)

pc1.addTransceiver(canvasStream.getTracks()[0], {
  streams: [ canvasStream ]
})

pc2.onaddstream = (evt) => {
  videoC.srcObject = evt.stream
  videoC.play()

  // Note: using two MediaRecorder at the same time seem problematic
  // THIS DOSE NOT WORK
  stream2mediaSorce(evt.stream, videoD)
  setTimeout(() => videoD.play(), 2000)
}

/**
 * Turn a MediaStream into a SourceBuffer
 * 
 * @param  {MediaStream}      stream   Live Stream to record
 * @param  {HTMLVideoElement} videoElm Video element to play the recorded video in
 * @return {undefined}
 */
function stream2mediaSorce (stream, videoElm) {
  const RECORDER_MIME_TYPE = 'video/webm;codecs=vp9'
  const recorder = new MediaRecorder(stream, { mimeType : RECORDER_MIME_TYPE })

  const mediaSource = new MediaSource()
  videoElm.src = URL.createObjectURL(mediaSource)
  mediaSource.onsourceopen = (e) => {
    sourceBuffer = mediaSource.addSourceBuffer(RECORDER_MIME_TYPE);

    const fr = new FileReader()
    fr.onerror = console.log
    fr.onload = ({ target }) => {
      console.log(target.result)
      sourceBuffer.appendBuffer(target.result)
    }
    recorder.ondataavailable = ({ data }) => {
      console.log(data)
      fr.readAsArrayBuffer(data)
    }
    setInterval(recorder.requestData.bind(recorder), 1000)
  }

  console.log('Recorder created')
  recorder.start() 
}

你知道为什么它不能播放视频吗?

我创建了一个fiddle https://jsfiddle.net/ofy8w1jn/5/有了所有必要的代码来尝试,javascript选项卡与上面的代码相同,(html大部分是不相关的,不需要更改)

有些人尝试减少延迟,但我实际上想将延迟增加到大约 10 秒,以便重新观看您在高尔夫挥杆或其他操作中做错的事情,如果可能的话,完全避免使用 MediaRecorder

EDIT:我在一些 RTC 扩展中发现了名为“playout-delay”的东西

允许发送者控制从捕获到渲染时间的最小和最大延迟

  • https://webrtc.org/experiments/rtp-hdrext/playout-delay/ https://webrtc.org/experiments/rtp-hdrext/playout-delay/

我该如何使用它? 它对我有什么帮助吗?


更新,有一个新功能可以启用此功能,称为playoutDelayHint.

我们希望为 JavaScript 应用程序提供一种方法来设置他们想要渲染音频或视频数据的速度的首选项。对于专注于实时体验的应用程序来说,尽可能快可能是有益的。对于其他人来说,额外的数据缓冲可能会在出现网络问题时提供更顺畅的体验。

Refs:
https://discourse.wicg.io/t/hint-attribute-in-webrtc-to-influence-underlying-audio-video-buffering/4038 https://discourse.wicg.io/t/hint-attribute-in-webrtc-to-influence-underlying-audio-video-buffering/4038

https://bugs.chromium.org/p/webrtc/issues/detail?id=10287 https://bugs.chromium.org/p/webrtc/issues/detail?id=10287

Demo: https://jsfiddle.net/rvekxns5/ https://jsfiddle.net/rvekxns5/doe 我只能在浏览器中设置最长 10 秒,但更多的是由 UA 供应商利用可用资源尽最大努力

import('https://jimmy.warting.se/packages/dummycontent/canvas-clock.js')
.then(({AnalogClock}) => {
  const {canvas} = new AnalogClock(100)
  document.querySelector('canvas').replaceWith(canvas)
  
  const [pc1, pc2] = localPeerConnectionLoop()
  const canvasStream = canvas.captureStream(200)

  videoA.srcObject = canvasStream
  videoA.play()

  pc1.addTransceiver(canvasStream.getTracks()[0], {
    streams: [ canvasStream ]
  })

  pc2.onaddstream = (evt) => {
    videoC.srcObject = evt.stream
    videoC.play()
  }

  $dur.onchange = () => {
    pc2.getReceivers()[0].playoutDelayHint = $dur.valueAsNumber
  }
})
<!-- all the irrelevant part, that you don't need to know anything about -->
<h3 style="border-bottom: 1px solid">Original canvas</h3>
<canvas id="canvas" width="100" height="100"></canvas>
<script>
function localPeerConnectionLoop(cfg = {sdpSemantics: 'unified-plan'}) {
  const setD = (d, a, b) => Promise.all([a.setLocalDescription(d), b.setRemoteDescription(d)]);
  return [0, 1].map(() => new RTCPeerConnection(cfg)).map((pc, i, pcs) => Object.assign(pc, {
    onicecandidate: e => e.candidate && pcs[i ^ 1].addIceCandidate(e.candidate),
    onnegotiationneeded: async e => {
      try {
        await setD(await pc.createOffer(), pc, pcs[i ^ 1]);
        await setD(await pcs[i ^ 1].createAnswer(), pcs[i ^ 1], pc);
      } catch (e) {
        console.log(e);
      }
    }
  }));
}
</script>
<h3 style="border-bottom: 1px solid">Local peer (PC1)</h3>
<video id="videoA" muted width="100" height="100"></video>

<h3 style="border-bottom: 1px solid">Remote peer (PC2)</h3>
<video id="videoC" muted width="100" height="100"></video>
<label> Change playoutDelayHint
<input type="number" value="1" id="$dur">
</label>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更改 WebRTC 流中的播放延迟 的相关文章

  • 如何在同一页面上使用AJAX处理多个表单

    我有一个表单 当我单击 提交 时 它就被提交了 然后该表单隐藏 操作页面的结果显示在 div 中 classname dig 它工作正常 但是当我添加另一个表单时 它停止正常工作并且所有表单同时提交 我如何更改我的代码 done click
  • TypeError: props.render 不是一个函数(React hook 形式)

    我将方法作为我用react hook form制作的形式的道具传递 当从react hook form添加控制器时 它给了我 TypeError props render不是一个函数 我在网上找不到任何解决方案 因此感谢任何帮助 impor
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • 我想检查 $('#td1').text() === "x" 是否?

    我想检查innerHtml是否有X或O 所以我不能再次添加任何其他东西 但它不起作用 添加检查代码后它就停止了 我在这里尝试做一个简单的XO游戏来更熟悉javascript和jquery 我也不确定是否可以用 jQuery 做到这一点
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 检查 JavaScript 字符串是否为 URL

    JavaScript 有没有办法检查字符串是否是 URL 正则表达式被排除在外 因为 URL 很可能是这样写的stackoverflow 也就是说它可能没有 com www or http 如果你想检查一个字符串是否是有效的 HTTP UR
  • JavaScript 重定向到新窗口

    我有以下代码 它根据下拉列表的值重定向到页面 我如何使其在新窗口中打开 function goto form var index form select selectedIndex if form select options index
  • Jquery/Javascript 上传和下载文件,无需后端

    是否可以在没有后端服务器的情况下在 JavaScript 函数中下载和上传文件 我需要导出和导入由 JavaScript 函数生成的 XML 我想创建按钮 保存 xml 来保存文件 但我不知道是否可行 另一方面 我希望将 XML 文件直接上
  • 使用 KnockoutJs 映射插件进行递归模板化

    我正在尝试使用以下方法在树上进行递归模板化ko映射 插入 http knockoutjs com documentation plugins mapping html 但我无法渲染它 除非我定义separate每个级别的模板 在以下情况下
  • Babel 7 Jest Core JS“TypeError:wks不是函数”

    将我的项目升级到 Babel 7 后 通过 Jest 运行测试会抛出以下错误 测试在 Babel 6 中运行没有任何问题 但在 Babel 7 中失败并出现以下错误 TypeError wks is not a function at Ob
  • 如何使输入字段和提交按钮变灰

    我想变灰这两件事 http doorsplit heroku com 歌曲输入字段和提交按钮 直到用户输入艺术家 有没有一种简单的方法可以通过 JQuery 来做到这一点 艺术家输入字段的id是 request artist 你可以这样做
  • 提交表单并重定向页面

    我在 SO 上看到了很多与此相关的其他问题 但没有一个对我有用 我正在尝试提交POST表单 然后将用户重定向到另一个页面 但我无法同时实现这两种情况 我可以获取重定向或帖子 但不能同时获取两者 这是我现在所拥有的
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • HTML 离线应用程序缓存,列出下载的文件

    作为我正在构建的离线 Web 应用程序的加载屏幕的一部分 使用缓存清单 http developer apple com library safari documentation iPhone Conceptual SafariJSData
  • 如何获取给定 DOM 元素的所有定义的 CSS 选择器?

    如何使用 jQuery 获取给定 DOM 元素的所有定义的 CSS 选择器 定义后 我的意思是在应用于任何样式表的所有 CSS 选择器document 在某种程度上 这类似于 FireBug 实现的功能 其中显示所选 DOM 元素的所有应用
  • Javascript转换时区问题

    我在转换当前时区的日期时间时遇到问题 我从服务器收到此日期字符串 格式为 2015 10 09T08 00 00 这是中部时间 但是当我使用 GMT 5 中的 new Date strDate 转换此日期时间时 它返回给我的信息如下 这是不
  • 条件在反应本机生产中失败,但在开发中有效

    我创建了一个反应本机应用程序 我需要通过它进行比较 如果属实 就会执行死刑 问题是 该条件适用于 React Native 开发模式 而不适用于 React Native 生产版本 我使用 firebase 作为数据库 也使用 redux
  • Javascript 纪元时间(以天为单位)

    我需要以天为单位的纪元时间 迄今为止 我已经看到过有关如何翻译它的帖子 但几天后就没有了 我对纪元时间很不好 我怎么能得到这个 我需要以天为单位的纪元时间 我将解释为您想要自纪元以来的天数 纪元本身是第 0 天 或第 1 天的开始 无论您如
  • 如何在 pg-promise 中设置模式

    我正在搜索的文档pg 承诺 https github com vitaly t pg promise特别是在创建客户端时 但我无法找到设置连接中使用的默认架构的选项 它始终使用public架构 我该如何设置 通常 为数据库或角色设置默认架构
  • 使用 Ajax 请求作为源数据的 Jquery 自动完成搜索

    我想做的事 我想使用 jquery 自动完成函数创建一个输入文本字段 该函数从跨域curl 请求获取源数据 结果应该与此示例完全相同 CSS 在这里并不重要 http abload de img jquerydblf5 png http a

随机推荐

  • 在 Java 中强制释放大缓存对象

    我使用一个大型 数百万 条目哈希图来缓存算法所需的值 键是两个对象的组合作为一个长 由于它不断增长 因为映射中的键发生变化 因此不再需要旧的键 因此能够强制擦除其中包含的所有数据并在执行期间重新开始会很好 有没有一种方法可以有效地做到这一点
  • 是否有元组的 zipWith 类似物?

    初步说明 这是SeanD 删除的问题 https stackoverflow com q 50020370 2751851 就像有一样zipWith对于列表 GHCi gt zipWith 1 2 3 4 4 6 感觉应该有一些类似于元组的
  • 如何在 lambda 中进行 sql 连接?

    有时 我会偶然发现这个问题 我使用了 lambda 连接的子集 鉴于我可以使用任何 LINQ 扩展 我应该如何实现以下连接 为了简单起见 表定义为 CREATE TABLE dbo TableA Key INT IDENTITY 1 1 N
  • 可可中的客户端到客户端消息传递?

    嗯 现在我尝试在两个客户端之间而不是客户端到服务器之间进行消息传递 因此 如果我没记错的话 我们无法单独启动服务 但如何查看是单独设置还是两者都连接到同一服务 我的启动服务的代码 void startService Start listen
  • 解析错误:语法错误,意外的 T_STRING 59 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 请修复这段
  • 使用 pywin32 获取 GUIThreadInfo()

    我正在尝试遵循这个答案 https stackoverflow com a 11901591 5510469我已经到了 a 应该打电话的地步 GetGUIThreadInfo 但我找不到pywin32 文档 http timgolden m
  • 读取解决方案 sln 的所有 csproj 项目的引用列表(以编程方式)

    我有解决方案 sln 其中有许多 csproj 项目 有人知道如何以编程方式读取 VS2008 的 sln 文件中所有 csproj 项目的引用列表吗 csproj 文件只是 XML 文件 为此 您可以使用 NET 框架中的 XDocume
  • setTimeout() 的 JavaScript 执行顺序

    假设我有以下代码 function testA setTimeout testB 1000 doLong function testB doSomething function doLong takes a few seconds to d
  • CMP 证书请求

    我使用下面的代码将 CMP 证书请求发送到端点 public static void main String args try System out println In final BigInteger certReqId BigInte
  • 如何使用flexbox调整div的宽度以适应内容

    我想适应 flexrowdiv 的宽度到内容 但我无法使用 flex 设置它 HTML div class fullwidth div class sidebar p sidebar p p sidebar p p sidebar p p
  • Android 使用数据绑定库动态包含布局

    我正在使用带有数据绑定库的 Android 应用程序的 MVVM 框架 我有一些可重用的组件 应该包含所有活动 FE工具栏 菜单 浮动操作按钮 我想创建一个通用活动 它将实现所有这些可重用功能 然后每个活动类都将从这个通用活动继承 我还有
  • 如何获得工具栏上的“向上”按钮?

    这是一个简短的问题 我试图强制操作栏 由工具栏使用 使用 LTR 对齐方式 我已经成功地使布局本身使用 LTR 但没有使用 向上 按钮 正如我所做的那样 here https stackoverflow com q 22602453 878
  • 如何在 Apache 2.4.18 服务器中实现没有 ssl 的 http2

    我制作了一个使用 HTTP 2 协议的网站 该网站在 Apache 2 4 18 HTTP 服务器上运行 目前我已经使网站启用了 SSL 因为我在某处读到 HTTP 2 默认情况下需要 SSL 我可能不需要确保我的网站安全 所以我不想花钱购
  • Javascript 设置左侧样式不起作用

    xpos xpos 1 document getElementById img style left xpos 我无法将 xpos 值分配给 JavaScript 中的 left 属性 尝试向其中添加一个单位 否则 由于 CSS 无效 浏览
  • Flutter中如何根据AppBar内容在运行时动态改变AppBar高度?

    我正在尝试实施一个颤动标记 https flutterawesome com a textfield flutter package with tagging functionality 在 的里面AppBar 我设法添加了标记TextFi
  • Git 恢复已发布的提交,同时保持未来合并的能力?

    我们有两个同时存在的分支 如下所示 A B C D H gt Branch A E F G gt Branch B 问题是我们决定暂时不想将分支 B 合并到分支 A 这是一个错误 因此 我们 在分支 A 上 恢复了合并提交 git chec
  • Qt4 QSettings保存枚举值(例如Qt::CheckState)

    我想在 QSetting 中保存 QCheckBok 的状态 我可以将其值转换为 int 但也许存在更简单和正确的方法来做到这一点 这是我的代码 QSetting setting Qt CheckState checkState check
  • 递归算法的时间复杂度

    如何计算递归算法的时间复杂度 int pow1 int x int n if n 0 return 1 else return x pow1 x n 1 int pow2 int x int n if n 0 return 1 else i
  • MVC5 中的 WWWROOT

    如何使用静态文件在 ASP NET MVC5 中实现相同的行为 就像在 aspnet core 上一样app UseDefaultFiles app UseStaticFiles 我的意思是通过根目录从某个文件夹提供静态文件 例如 wwwr
  • 更改 WebRTC 流中的播放延迟

    我正在尝试将实时 MediaStream 最终来自摄像机 从对等点 A 投射到对等点 B 并且我希望对等点 B 实时接收实时流 然后以增加的延迟重播它 不幸的是 不可能简单地暂停流并继续播放 因为它会跳转到实时时刻 所以我发现我可以使用 M