无法限制WebRTC P2P多人接收带宽

Unable to limit WebRTC P2P Multi-participant Receiving Bandwidth

我正在尝试通过使用此示例结合我现有的多人视频通话代码来更改 WebRTC P2P 视频通话的动态带宽:

示例https://webrtc.github.io/samples/src/content/peerconnection/bandwidth/

当我通过 Chrome、

查看 WebRTC 内部结构时

bitsReceivedPerSecond for send (ssrc) (video) 已降低到所选带宽。但是,bitsReceivedPerSecond for recv (ssrc) (video) 仍然保持不变。我可以知道如何使带宽更改同时应用于发送和接收吗?

下面是我的代码,如果你能帮助指出我的错误就太好了,在此先感谢。

2018 年 12 月 14 日更新: 在代码中添加了接收者的第一个选项

问题: 未捕获类型错误:receiver.getParameters 不是函数

const bandwidthSelector = document.querySelector('select#bandwidth');

bandwidthSelector.disabled = false;

// renegotiate bandwidth on the fly.
bandwidthSelector.onchange = () => {
  bandwidthSelector.disabled = true;
  const bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex].value;

  // In Chrome, use RTCRtpSender.setParameters to change bandwidth without
  // (local) renegotiation. Note that this will be within the envelope of
  // the initial maximum bandwidth negotiated via SDP.
  if ((adapter.browserDetails.browser === 'chrome' ||
       (adapter.browserDetails.browser === 'firefox' &&
        adapter.browserDetails.version >= 64)) &&
      'RTCRtpSender' in window &&
      'setParameters' in window.RTCRtpSender.prototype) {

        $.each(peers, function( index, value ) {
            const sender = value.getSenders()[0];
            const parameters = sender.getParameters();
            if (!parameters.encodings) {
              parameters.encodings = [{}];
            }
            if (bandwidth === 'unlimited') {
              delete parameters.encodings[0].maxBitrate;
            } else {
              parameters.encodings[0].maxBitrate = bandwidth * 1000;
            }
            sender.setParameters(parameters)
            .then(() => {
              bandwidthSelector.disabled = false;
            })
            .catch(e => console.error(e));

            /* 1st Option - Start */
            const receiver = value.getReceivers()[0];
            const recParameters = receiver.getParameters();

            if (!recParameters.encodings) {
              recParameters.encodings = [{}];
            }
            if (bandwidth === 'unlimited') {
              delete recParameters.encodings[0].maxBitrate;
            } else {
              recParameters.encodings[0].maxBitrate = bandwidth * 1000;
            }
            receiver.setParameters(recParameters)
            .then(() => {
              bandwidthSelector.disabled = false;
            })
            .catch(e => console.error(e));

            /* 1st Option - End */

            return;

        });             
  }

  // Fallback to the SDP munging with local renegotiation way of limiting
  // the bandwidth.
  function onSetSessionDescriptionError(error) {
      console.log('Failed to set session description: ' + error.toString());
    }
};

function updateBandwidthRestriction(sdp, bandwidth) {
  let modifier = 'AS';
  if (adapter.browserDetails.browser === 'firefox') {
    bandwidth = (bandwidth >>> 0) * 1000;
    modifier = 'TIAS';
  }
  if (sdp.indexOf('b=' + modifier + ':') === -1) {
    // insert b= after c= line.
    sdp = sdp.replace(/c=IN (.*)\r\n/, 'c=IN \r\nb=' + modifier + ':' + bandwidth + '\r\n');
  } else {
    sdp = sdp.replace(new RegExp('b=' + modifier + ':.*\r\n'), 'b=' + modifier + ':' + bandwidth + '\r\n');
  }
  return sdp;
}

function removeBandwidthRestriction(sdp) {
  return sdp.replace(/b=AS:.*\r\n/, '').replace(/b=TIAS:.*\r\n/, '');
}

2018 年 12 月 14 日更新: 第二个选项 createOffer

问题:无法设置会话描述:InvalidStateError:无法在'RTCPeerConnection'上执行'setRemoteDescription':无法设置远程应答sdp:调用错误状态:kStable

const bandwidthSelector = document.querySelector('select#bandwidth');

bandwidthSelector.disabled = false;

// renegotiate bandwidth on the fly.
bandwidthSelector.onchange = () => {
  bandwidthSelector.disabled = true;
  const bandwidth = bandwidthSelector.options[bandwidthSelector.selectedIndex].value;

  // In Chrome, use RTCRtpSender.setParameters to change bandwidth without
  // (local) renegotiation. Note that this will be within the envelope of
  // the initial maximum bandwidth negotiated via SDP.
  if ((adapter.browserDetails.browser === 'chrome' ||
       (adapter.browserDetails.browser === 'firefox' &&
        adapter.browserDetails.version >= 64)) &&
      'RTCRtpSender' in window &&
      'setParameters' in window.RTCRtpSender.prototype) {

        $.each(peers, function( index, value ) {
            const sender = value.getSenders()[0];
            const parameters = sender.getParameters();
            if (!parameters.encodings) {
              parameters.encodings = [{}];
            }
            if (bandwidth === 'unlimited') {
              delete parameters.encodings[0].maxBitrate;
            } else {
              parameters.encodings[0].maxBitrate = bandwidth * 1000;
            }
            sender.setParameters(parameters)
            .then(() => {
              bandwidthSelector.disabled = false;
            })
            .catch(e => console.error(e));

            /* 2nd option - Start */
            value.createOffer(
                    function (local_description) {
                        console.log("Local offer description is: ", local_description);
                        value.setLocalDescription(local_description,
                            function () {
                                signaling_socket.emit('relaySessionDescription', {
                                    'peer_id': index,
                                    'session_description': local_description
                                });
                                console.log("Offer setLocalDescription succeeded");
                            },
                            function () {
                                Alert("Offer setLocalDescription failed!");
                            }
                        );
                    },
                    function (error) {
                        console.log("Error sending offer: ", error);
                    }).then(() => {
                  const desc = {
                    type: value.remoteDescription.type,
                    sdp: bandwidth === 'unlimited'
                      ? removeBandwidthRestriction(value.remoteDescription.sdp)
                      : updateBandwidthRestriction(value.remoteDescription.sdp, bandwidth)
                  };
                  console.log('Applying bandwidth restriction to setRemoteDescription:\n' +
                    desc.sdp);
                  return value.setRemoteDescription(desc);
                })
                .then(() => {
                  bandwidthSelector.disabled = false;
                })
                .catch(onSetSessionDescriptionError);

            /* 2nd option - End */

            return;

        });             
  }

  // Fallback to the SDP munging with local renegotiation way of limiting
  // the bandwidth.
  function onSetSessionDescriptionError(error) {
      console.log('Failed to set session description: ' + error.toString());
    }
};

function updateBandwidthRestriction(sdp, bandwidth) {
  let modifier = 'AS';
  if (adapter.browserDetails.browser === 'firefox') {
    bandwidth = (bandwidth >>> 0) * 1000;
    modifier = 'TIAS';
  }
  if (sdp.indexOf('b=' + modifier + ':') === -1) {
    // insert b= after c= line.
    sdp = sdp.replace(/c=IN (.*)\r\n/, 'c=IN \r\nb=' + modifier + ':' + bandwidth + '\r\n');
  } else {
    sdp = sdp.replace(new RegExp('b=' + modifier + ':.*\r\n'), 'b=' + modifier + ':' + bandwidth + '\r\n');
  }
  return sdp;
}

function removeBandwidthRestriction(sdp) {
  return sdp.replace(/b=AS:.*\r\n/, '').replace(/b=TIAS:.*\r\n/, '');
}

RTCRtpSender 只控制发送带宽。如果要限制接收带宽,要么使用b=AS / b=TIAS方式,要么让receiver使用setParameters.