From 28dfdf1c99e9f4d87c84a343aa47cfd8f0d62a06 Mon Sep 17 00:00:00 2001
From: Filippo <36960428+fibann@users.noreply.github.com>
Date: Thu, 24 Oct 2019 11:57:51 +0100
Subject: [PATCH] Expose PeerConnectionInterface::SetBitrate (#109)
Expose webrtc::PeerConnectionInterface::SetBitrate() to allow the user to set
the minimum and maximum bitrates used for the RTP tracks, as well as the
starting value. This enables in particular changing the default video value of
300 kpbs to something higher in local scenarios where the bandwidth is expected
to be high, to enable higher quality video right from the start of the video
track recording.
---
examples/TestAppUwp/MainPage.xaml.cs | 14 ++++++---
.../src/interop/interop_api.cpp | 21 ++++++++++++++
.../src/interop/interop_api.h | 15 ++++++++++
.../src/pch.h | 1 +
.../Interop/PeerConnectionInterop.cs | 4 +++
.../PeerConnection.cs | 29 +++++++++++++++----
6 files changed, 75 insertions(+), 9 deletions(-)
diff --git a/examples/TestAppUwp/MainPage.xaml.cs b/examples/TestAppUwp/MainPage.xaml.cs
index 364fccd8f..c114b7f81 100644
--- a/examples/TestAppUwp/MainPage.xaml.cs
+++ b/examples/TestAppUwp/MainPage.xaml.cs
@@ -705,7 +705,7 @@ private Task RunOnWorkerThread(Action handler)
/// The width of the video in pixels.
/// The height of the video in pixels.
/// The newly created video source.
- private MediaStreamSource CreateVideoStreamSource(uint width, uint height)
+ private MediaStreamSource CreateVideoStreamSource(uint width, uint height, uint framerate)
{
if (width == 0)
{
@@ -720,7 +720,7 @@ private MediaStreamSource CreateVideoStreamSource(uint width, uint height)
// https://docs.microsoft.com/en-us/windows/desktop/medfound/video-subtype-guids
var videoProperties = VideoEncodingProperties.CreateUncompressed(MediaEncodingSubtypes.Iyuv, width, height);
var videoStreamDesc = new VideoStreamDescriptor(videoProperties);
- videoStreamDesc.EncodingProperties.FrameRate.Numerator = 30;
+ videoStreamDesc.EncodingProperties.FrameRate.Numerator = framerate;
videoStreamDesc.EncodingProperties.FrameRate.Denominator = 1;
videoStreamDesc.EncodingProperties.Bitrate = (30 * width * height * 8 * 8 / 12); // 30-fps 8bits/byte NV12=12bpp
var videoStreamSource = new MediaStreamSource(videoStreamDesc);
@@ -975,8 +975,10 @@ private void Peer_RemoteI420FrameReady(I420AVideoFrame frame)
_isRemoteVideoPlaying = true;
uint width = frame.width;
uint height = frame.height;
+ // We don't know the remote video framerate yet, so use a default.
+ uint framerate = 30;
RunOnMainThread(() => {
- remoteVideoSource = CreateVideoStreamSource(width, height);
+ remoteVideoSource = CreateVideoStreamSource(width, height, framerate);
remoteVideoPlayer.Source = MediaSource.CreateFromMediaStreamSource(remoteVideoSource);
remoteVideoPlayer.Play();
});
@@ -1129,7 +1131,7 @@ private async void StartLocalMediaClicked(object sender, RoutedEventArgs e)
localMediaSource?.Reset();
localVideo.SetMediaPlayer(null);
localVideoSource = null;
- localVideoSource = CreateVideoStreamSource(width, height);
+ localVideoSource = CreateVideoStreamSource(width, height, (uint)framerate);
localMediaSource = MediaSource.CreateFromMediaStreamSource(localVideoSource);
localVideoPlayer.Source = localMediaSource;
localVideo.SetMediaPlayer(localVideoPlayer);
@@ -1143,6 +1145,10 @@ private async void StartLocalMediaClicked(object sender, RoutedEventArgs e)
try
{
+ // The default start bitrate is quite low (300 kbps); use a higher value to get
+ // better quality on local network.
+ _peerConnection.SetBitrate(startBitrateBps: (uint)(width * height * framerate / 20));
+
// Add the local audio track captured from the local microphone
await _peerConnection.AddLocalAudioTrackAsync();
diff --git a/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.cpp b/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.cpp
index ac97ce87c..351197c67 100644
--- a/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.cpp
+++ b/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.cpp
@@ -1196,6 +1196,27 @@ mrsPeerConnectionCreateAnswer(PeerConnectionHandle peerHandle) noexcept {
return MRS_E_INVALID_PEER_HANDLE;
}
+MRS_API mrsResult MRS_CALL mrsPeerConnectionSetBitrate(
+ PeerConnectionHandle peer_handle,
+ int min_bitrate_bps,
+ int start_bitrate_bps,
+ int max_bitrate_bps) noexcept {
+ if (auto peer = static_cast(peer_handle)) {
+ webrtc::BitrateSettings settings;
+ if (min_bitrate_bps >= 0) {
+ settings.min_bitrate_bps = min_bitrate_bps;
+ }
+ if (start_bitrate_bps >= 0) {
+ settings.start_bitrate_bps = start_bitrate_bps;
+ }
+ if (max_bitrate_bps >= 0) {
+ settings.max_bitrate_bps = max_bitrate_bps;
+ }
+ return peer->GetImpl()->SetBitrate(settings).ok() ? MRS_SUCCESS : MRS_E_UNKNOWN;
+ }
+ return MRS_E_INVALID_PEER_HANDLE;
+}
+
mrsResult MRS_CALL
mrsPeerConnectionSetRemoteDescription(PeerConnectionHandle peerHandle,
const char* type,
diff --git a/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.h b/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.h
index 8b3cd1b8f..129d86976 100644
--- a/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.h
+++ b/libs/Microsoft.MixedReality.WebRTC.Native/src/interop/interop_api.h
@@ -601,6 +601,21 @@ mrsPeerConnectionCreateOffer(PeerConnectionHandle peerHandle) noexcept;
MRS_API mrsResult MRS_CALL
mrsPeerConnectionCreateAnswer(PeerConnectionHandle peerHandle) noexcept;
+/// Set the bitrate allocated to all RTP streams sent by this connection.
+/// Other limitations might affect these limits and are respected (for example
+/// "b=AS" in SDP).
+///
+/// Setting |start_bitrate_bps| will reset the current bitrate estimate to the
+/// provided value.
+///
+/// The values are in bits per second.
+/// If any of the arguments has a negative value, it will be ignored.
+MRS_API mrsResult MRS_CALL
+mrsPeerConnectionSetBitrate(PeerConnectionHandle peer_handle,
+ int min_bitrate_bps,
+ int start_bitrate_bps,
+ int max_bitrate_bps) noexcept;
+
/// Set a remote description received from a remote peer via the signaling
/// service.
MRS_API mrsResult MRS_CALL
diff --git a/libs/Microsoft.MixedReality.WebRTC.Native/src/pch.h b/libs/Microsoft.MixedReality.WebRTC.Native/src/pch.h
index 927ed8d17..d49586013 100644
--- a/libs/Microsoft.MixedReality.WebRTC.Native/src/pch.h
+++ b/libs/Microsoft.MixedReality.WebRTC.Native/src/pch.h
@@ -46,6 +46,7 @@
#include "api/mediaconstraintsinterface.h"
#include "api/mediastreaminterface.h"
#include "api/peerconnectioninterface.h"
+#include "api/transport/bitrate_settings.h"
#include "api/video/i420_buffer.h"
#include "api/videosourceproxy.h"
#include "media/engine/internaldecoderfactory.h"
diff --git a/libs/Microsoft.MixedReality.WebRTC/Interop/PeerConnectionInterop.cs b/libs/Microsoft.MixedReality.WebRTC/Interop/PeerConnectionInterop.cs
index e3bd9bc81..c8d6a2f4b 100644
--- a/libs/Microsoft.MixedReality.WebRTC/Interop/PeerConnectionInterop.cs
+++ b/libs/Microsoft.MixedReality.WebRTC/Interop/PeerConnectionInterop.cs
@@ -587,6 +587,10 @@ public static extern void PeerConnection_AddIceCandidate(IntPtr peerHandle, stri
EntryPoint = "mrsPeerConnectionCreateAnswer")]
public static extern uint PeerConnection_CreateAnswer(IntPtr peerHandle);
+ [DllImport(Utils.dllPath, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi,
+ EntryPoint = "mrsPeerConnectionSetBitrate")]
+ public static extern uint PeerConnection_SetBitrate(IntPtr peerHandle, int minBitrate, int startBitrate, int maxBitrate);
+
[DllImport(Utils.dllPath, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi,
EntryPoint = "mrsPeerConnectionSetRemoteDescription")]
public static extern uint PeerConnection_SetRemoteDescription(IntPtr peerHandle, string type, string sdp);
diff --git a/libs/Microsoft.MixedReality.WebRTC/PeerConnection.cs b/libs/Microsoft.MixedReality.WebRTC/PeerConnection.cs
index e66451a21..a5e6445f2 100644
--- a/libs/Microsoft.MixedReality.WebRTC/PeerConnection.cs
+++ b/libs/Microsoft.MixedReality.WebRTC/PeerConnection.cs
@@ -1006,11 +1006,11 @@ public void RemoveLocalAudioTrack()
///
/// Add a new out-of-band data channel with the given ID.
- ///
+ ///
/// A data channel is negotiated out-of-band when the peers agree on an identifier by any mean
/// not known to WebRTC, and both open a data channel with that ID. The WebRTC will match the
/// incoming and outgoing pipes by this ID to allow sending and receiving through that channel.
- ///
+ ///
/// This requires some external mechanism to agree on an available identifier not otherwise taken
/// by another channel, and also requires to ensure that both peers explicitly open that channel.
///
@@ -1035,13 +1035,13 @@ public async Task AddDataChannelAsync(ushort id, string label, bool
///
/// Add a new in-band data channel whose ID will be determined by the implementation.
- ///
+ ///
/// A data channel is negotiated in-band when one peer requests its creation to the WebRTC core,
/// and the implementation negotiates with the remote peer an appropriate ID by sending some
/// SDP offer message. In that case once accepted the other peer will automatically create the
/// appropriate data channel on its side with that negotiated ID, and the ID will be returned on
/// both sides to the user for information.
- ///
+ ///
/// Compares to out-of-band messages, this requires exchanging some SDP messages, but avoids having
/// to determine a common unused ID and having to explicitly open the data channel on both sides.
///
@@ -1159,10 +1159,29 @@ public bool CreateAnswer()
return (PeerConnectionInterop.PeerConnection_CreateAnswer(_nativePeerhandle) == Utils.MRS_SUCCESS);
}
+ ///
+ /// Set the bitrate allocated to all RTP streams sent by this connection.
+ /// Other limitations might affect these limits and are respected (for example
+ /// "b=AS" in SDP).
+ ///
+ /// Minimum bitrate in bits per second.
+ /// Start/current target bitrate in bits per second.
+ /// Maximum bitrate in bits per second.
+ public void SetBitrate(uint? minBitrateBps = null, uint? startBitrateBps = null, uint? maxBitrateBps = null)
+ {
+ ThrowIfConnectionNotOpen();
+ int signedMinBitrateBps = minBitrateBps.HasValue ? (int)minBitrateBps.Value : -1;
+ int signedStartBitrateBps = startBitrateBps.HasValue ? (int)startBitrateBps.Value : -1;
+ int signedMaxBitrateBps = maxBitrateBps.HasValue ? (int)maxBitrateBps.Value : -1;
+ uint res = PeerConnectionInterop.PeerConnection_SetBitrate(_nativePeerhandle,
+ signedMinBitrateBps, signedStartBitrateBps, signedMaxBitrateBps);
+ Utils.ThrowOnErrorCode(res);
+ }
+
///
/// Pass the given SDP description received from the remote peer via signaling to the
/// underlying WebRTC implementation, which will parse and use it.
- ///
+ ///
/// This must be called by the signaler when receiving a message.
///
/// The type of SDP message ("offer", "answer", "ice")