如何使用 opentok 流式传输音频文件?

How to stream audio file with opentok?

在 opentok 中,使用 OT.initPublisher,您只能将 deviceId 传递给 audioSource。有人知道流式传输音频文件的方法吗?

例如,我是这样做的:

navigator.getUserMedia({audio: true, video: false},
function(stream) {
    var context = new AudioContext();
    var microphone = context.createMediaStreamSource(stream);
    var backgroundMusic = context.createMediaElementSource(document.getElementById("song"));
    var mixedOutput = context.createMediaStreamDestination();
    microphone.connect(mixedOutput);
    backgroundMusic.connect(mixedOutput);
},
handleError);

像这样,我可以有一个带有声音和音乐的流,但是如何将这个流发送给发布者?有可能还是有其他方法可以做到这一点?

更新: 现在有一个官方方法可以做到这一点,使用提供给 OT.initPublishervideoSourceaudioSource 属性,拜托请参阅文档:https://tokbox.com/developer/sdks/js/reference/OT.html#initPublisher

这是一个如何将 canvas 元素流式传输为视频轨道的示例:https://github.com/opentok/opentok-web-samples/tree/master/Publish-Canvas

您可以应用相同的技术来流式传输音轨。


旧答案:

官方支持的 API 目前无法实现,但有办法做到。

请参阅 TokBox 博客 post 关于相机滤镜:https://tokbox.com/blog/camera-filters-in-opentok-for-web/

为了在流到达 OpenTok JS SDK 之前修改流,我们使用 mockGetUserMedia 函数拦截流:

https://github.com/aullman/opentok-camera-filters/blob/master/src/mock-get-user-media.js

您可以调用带有混音功能的 mockGetUserMedia。像这样:

mockGetUserMedia(function(originalStream) {
  var context = new AudioContext();
  var microphone = context.createMediaStreamSource(originalStream);
  var backgroundMusic = context.createMediaElementSource(document.getElementById("song"));
  var mixedOutput = context.createMediaStreamDestination();
  microphone.connect(mixedOutput);
  backgroundMusic.connect(mixedOutput);

  var stream = mixedOutput.stream;
  originalStream.getVideoTracks().map(function(track) {
    stream.addTrack(track);
  });
  return stream;
});

注意:我还没有测试过这个功能,但它应该会引导你朝着正确的方向前进。请记住,此技术容易出错,并且不受 TokBox 官方支持。

我们目前正在开发一项新功能,该功能将启用此用例,但我无法给出它何时可用的估计时间。

感谢您的帮助,但从今天早上开始我们无法正常工作。

所以我们用这段代码创建了一个不同的文件,该代码在我们的 html 中的 opentok 库之前实现:

function mockGetUserMedia(mockOnStreamAvailable) {
  var oldGetUserMedia = void 0;
  if (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
    oldGetUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
    navigator.webkitGetUserMedia = navigator.getUserMedia = navigator.mozGetUserMedia = function getUserMedia(constraints, onStreamAvailable, onStreamAvailableError, onAccessDialogOpened, onAccessDialogClosed, onAccessDenied) {
      return oldGetUserMedia.call(navigator, constraints, function (stream) {
        onStreamAvailable(mockOnStreamAvailable(stream));
      }, onStreamAvailableError, onAccessDialogOpened, onAccessDialogClosed, onAccessDenied);
    };
  } else {
    console.warn('Could not find getUserMedia function to mock out');
  }
};

mockGetUserMedia(function(stream) {
    var context = new AudioContext();
    var bgMusic = context.createMediaElementSource(document.getElementById("song"));
    var microphone = context.createMediaStreamSource(stream);
    var destination = context.createMediaStreamDestination();
    bgMusic.connect(destination);
    microphone.connect(destination);
    var mixedStream = destination.stream;
    stream.getVideoTracks().map(function(track) {
       mixedStream.addTrack(track);
    });
    return mixedStream;
});

在我们的 angular 中,我们初始化会话,创建发布者并发布它但得到错误:

Uncaught DOMException: Failed to execute 'createMediaElementSource' on 'BaseAudioContext': HTMLMediaElement already connected previously to a different MediaElementSourceNode.

这个错误,我认为是抛出的,因为函数执行了两次。 js什么时候加载,什么时候发布。

我不确定如何使用这个 mockGetUserMedia 函数,你知道我们的代码有什么问题吗?

编辑

我们让它在一些 if 条件下工作。非常感谢你,非常感谢。