Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Transport::setMinOutgoingBitrate #1035

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions node/src/DirectTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ export class DirectTransport extends
'setMaxOutgoingBitrate() not implemented in DirectTransport');
}

/**
* @override
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async setMinOutgoingBitrate(bitrate: number): Promise<void>
{
throw new UnsupportedError(
'setMinOutgoingBitrate() not implemented in DirectTransport');
}

/**
* Send RTCP packet.
*/
Expand Down
17 changes: 15 additions & 2 deletions node/src/Transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export type TransportTraceEventData =

export type SctpState = 'new' | 'connecting' | 'connected' | 'failed' | 'closed';

export type TransportEvents =
{
export type TransportEvents =
{
routerclose: [];
listenserverclose: [];
trace: [TransportTraceEventData];
Expand Down Expand Up @@ -523,6 +523,19 @@ export class Transport<Events extends TransportEvents = TransportEvents,
'transport.setMaxOutgoingBitrate', this.internal.transportId, reqData);
}

/**
* Set maximum outgoing bitrate for sending media.
*/
async setMinOutgoingBitrate(bitrate: number): Promise<void>
{
logger.debug('setMinOutgoingBitrate() [bitrate:%s]', bitrate);

const reqData = { bitrate };

await this.channel.request(
'transport.setMinOutgoingBitrate', this.internal.transportId, reqData);
}

/**
* Create a Producer.
*/
Expand Down
13 changes: 12 additions & 1 deletion node/src/tests/test-WebRtcTransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,14 @@ test('webRtcTransport.setMaxIncomingBitrate() succeeds', async () =>

test('webRtcTransport.setMaxOutgoingBitrate() succeeds', async () =>
{
await expect(transport.setMaxIncomingBitrate(100000))
await expect(transport.setMaxOutgoingBitrate(100000))
.resolves
.toBeUndefined();
}, 2000);

test('webRtcTransport.setMinOutgoingBitrate() succeeds', async () =>
{
await expect(transport.setMinOutgoingBitrate(100000))
.resolves
.toBeUndefined();
}, 2000);
Expand Down Expand Up @@ -500,6 +507,10 @@ test('WebRtcTransport methods reject if closed', async () =>
.rejects
.toThrow(Error);

await expect(transport.setMinOutgoingBitrate(200000))
.rejects
.toThrow(Error);

await expect(transport.restartIce())
.rejects
.toThrow(Error);
Expand Down
6 changes: 6 additions & 0 deletions rust/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,12 @@ request_response!(
TransportSetMaxOutgoingBitrateRequest { bitrate: u32 },
);

request_response!(
TransportId,
"transport.setMinOutgoingBitrate",
TransportSetMinOutgoingBitrateRequest { bitrate: u32 },
);

request_response!(
TransportId,
"transport.restartIce",
Expand Down
7 changes: 7 additions & 0 deletions rust/src/router/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::messages::{
TransportEnableTraceEventRequest, TransportGetStatsRequest, TransportProduceDataRequest,
TransportProduceRequest, TransportSetMaxIncomingBitrateRequest,
TransportSetMaxOutgoingBitrateRequest,
TransportSetMinOutgoingBitrateRequest,
};
pub use crate::ortc::{
ConsumerRtpParametersError, RtpCapabilitiesError, RtpParametersError, RtpParametersMappingError,
Expand Down Expand Up @@ -387,6 +388,12 @@ pub(super) trait TransportImpl: TransportGeneric {
.await
}

async fn set_min_outgoing_bitrate_impl(&self, bitrate: u32) -> Result<(), RequestError> {
self.channel()
.request(self.id(), TransportSetMinOutgoingBitrateRequest { bitrate })
.await
}

async fn enable_trace_event_impl(
&self,
types: Vec<TransportTraceEventType>,
Expand Down
8 changes: 8 additions & 0 deletions rust/src/router/webrtc_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,14 @@ impl WebRtcTransport {
self.set_max_outgoing_bitrate_impl(bitrate).await
}

/// Set minimum outgoing bitrate for media streams sent by the remote endpoint over this
/// transport.
pub async fn set_min_outgoing_bitrate(&self, bitrate: u32) -> Result<(), RequestError> {
debug!("set_min_outgoing_bitrate() [bitrate:{}]", bitrate);

self.set_min_outgoing_bitrate_impl(bitrate).await
}

/// Local ICE role. Due to the mediasoup ICE Lite design, this is always `Controlled`.
#[must_use]
pub fn ice_role(&self) -> IceRole {
Expand Down
22 changes: 22 additions & 0 deletions rust/tests/integration/webrtc_transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,28 @@ fn set_max_outgoing_bitrate_succeeds() {
});
}

#[test]
fn set_min_outgoing_bitrate_succeeds() {
future::block_on(async move {
let (_worker, router) = init().await;

let transport = router
.create_webrtc_transport(WebRtcTransportOptions::new(TransportListenIps::new(
ListenIp {
ip: IpAddr::V4(Ipv4Addr::LOCALHOST),
announced_ip: Some("9.9.9.1".parse().unwrap()),
},
)))
.await
.expect("Failed to create WebRTC transport");

transport
.set_min_outgoing_bitrate(100000)
.await
.expect("Failed to set min outgoing bitrate on WebRTC transport");
});
}

#[test]
fn restart_ice_succeeds() {
future::block_on(async move {
Expand Down
1 change: 1 addition & 0 deletions worker/include/Channel/ChannelRequest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace Channel
TRANSPORT_CONNECT,
TRANSPORT_SET_MAX_INCOMING_BITRATE,
TRANSPORT_SET_MAX_OUTGOING_BITRATE,
TRANSPORT_SET_MIN_OUTGOING_BITRATE,
TRANSPORT_RESTART_ICE,
TRANSPORT_PRODUCE,
TRANSPORT_CONSUME,
Expand Down
1 change: 1 addition & 0 deletions worker/include/RTC/Transport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ namespace RTC
uint32_t initialAvailableOutgoingBitrate{ 600000u };
uint32_t maxIncomingBitrate{ 0u };
uint32_t maxOutgoingBitrate{ 0u };
uint32_t minOutgoingBitrate{ 0u };
struct TraceEventTypes traceEventTypes;
};
} // namespace RTC
Expand Down
5 changes: 4 additions & 1 deletion worker/include/RTC/TransportCongestionControlClient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ namespace RTC
RTC::TransportCongestionControlClient::Listener* listener,
RTC::BweType bweType,
uint32_t initialAvailableBitrate,
uint32_t maxOutgoingBitrate);
uint32_t maxOutgoingBitrate,
uint32_t minOutgoingBitrate);
virtual ~TransportCongestionControlClient();

public:
Expand All @@ -74,6 +75,7 @@ namespace RTC
void ReceiveRtcpTransportFeedback(const RTC::RTCP::FeedbackRtpTransportPacket* feedback);
void SetDesiredBitrate(uint32_t desiredBitrate, bool force);
void SetMaxOutgoingBitrate(uint32_t maxBitrate);
void SetMinOutgoingBitrate(uint32_t minBitrate);
const Bitrates& GetBitrates() const
{
return this->bitrates;
Expand Down Expand Up @@ -118,6 +120,7 @@ namespace RTC
RTC::BweType bweType;
uint32_t initialAvailableBitrate{ 0u };
uint32_t maxOutgoingBitrate{ 0u };
uint32_t minOutgoingBitrate{ 0u };
Bitrates bitrates;
bool availableBitrateEventCalled{ false };
uint64_t lastAvailableBitrateEventAtMs{ 0u };
Expand Down
1 change: 1 addition & 0 deletions worker/src/Channel/ChannelRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace Channel
{ "transport.connect", ChannelRequest::MethodId::TRANSPORT_CONNECT },
{ "transport.setMaxIncomingBitrate", ChannelRequest::MethodId::TRANSPORT_SET_MAX_INCOMING_BITRATE },
{ "transport.setMaxOutgoingBitrate", ChannelRequest::MethodId::TRANSPORT_SET_MAX_OUTGOING_BITRATE },
{ "transport.setMinOutgoingBitrate", ChannelRequest::MethodId::TRANSPORT_SET_MIN_OUTGOING_BITRATE },
{ "transport.restartIce", ChannelRequest::MethodId::TRANSPORT_RESTART_ICE },
{ "transport.produce", ChannelRequest::MethodId::TRANSPORT_PRODUCE },
{ "transport.consume", ChannelRequest::MethodId::TRANSPORT_CONSUME },
Expand Down
61 changes: 60 additions & 1 deletion worker/src/RTC/Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,12 @@ namespace RTC
"bitrate must be >= %" PRIu32 " bps", RTC::TransportCongestionControlMinOutgoingBitrate);
}

if (this->minOutgoingBitrate != 0u && bitrate < this->minOutgoingBitrate)
{
MS_THROW_TYPE_ERROR(
"bitrate must be >= minOutgoingBitrate (%" PRIu32 " bps)", this->minOutgoingBitrate);
}

if (this->tccClient)
{
// NOTE: This may throw so don't update things before calling this
Expand All @@ -651,6 +657,55 @@ namespace RTC
break;
}

case Channel::ChannelRequest::MethodId::TRANSPORT_SET_MIN_OUTGOING_BITRATE:
{
auto jsonBitrateIt = request->data.find("bitrate");

// clang-format off
if (
jsonBitrateIt == request->data.end() ||
!Utils::Json::IsPositiveInteger(*jsonBitrateIt)
)
// clang-format on
{
MS_THROW_TYPE_ERROR("missing bitrate");
}

const uint32_t bitrate = jsonBitrateIt->get<uint32_t>();

if (bitrate < RTC::TransportCongestionControlMinOutgoingBitrate)
{
MS_THROW_TYPE_ERROR(
"bitrate must be >= %" PRIu32 " bps", RTC::TransportCongestionControlMinOutgoingBitrate);
}

if (this->maxOutgoingBitrate != 0u && bitrate > this->maxOutgoingBitrate)
{
MS_THROW_TYPE_ERROR(
"bitrate must be <= maxOutgoingBitrate (%" PRIu32 " bps)", this->maxOutgoingBitrate);
}

if (this->tccClient)
{
// NOTE: This may throw so don't update things before calling this
// method.
this->tccClient->SetMinOutgoingBitrate(bitrate);
this->minOutgoingBitrate = bitrate;

MS_DEBUG_TAG(bwe, "minimum outgoing bitrate set to %" PRIu32, this->minOutgoingBitrate);

ComputeOutgoingDesiredBitrate();
}
else
{
this->minOutgoingBitrate = bitrate;
}

request->Accept();

break;
}

case Channel::ChannelRequest::MethodId::TRANSPORT_PRODUCE:
{
std::string producerId;
Expand Down Expand Up @@ -1002,7 +1057,11 @@ namespace RTC
};

this->tccClient = std::make_shared<RTC::TransportCongestionControlClient>(
this, bweType, this->initialAvailableOutgoingBitrate, this->maxOutgoingBitrate);
this,
bweType,
this->initialAvailableOutgoingBitrate,
this->maxOutgoingBitrate,
this->minOutgoingBitrate);

if (IsConnected())
this->tccClient->TransportConnected();
Expand Down
22 changes: 19 additions & 3 deletions worker/src/RTC/TransportCongestionControlClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ namespace RTC
RTC::TransportCongestionControlClient::Listener* listener,
RTC::BweType bweType,
uint32_t initialAvailableBitrate,
uint32_t maxOutgoingBitrate)
uint32_t maxOutgoingBitrate,
uint32_t minOutgoingBitrate)
: listener(listener), bweType(bweType),
initialAvailableBitrate(std::max<uint32_t>(
initialAvailableBitrate, RTC::TransportCongestionControlMinOutgoingBitrate)),
maxOutgoingBitrate(maxOutgoingBitrate)
maxOutgoingBitrate(maxOutgoingBitrate), minOutgoingBitrate(minOutgoingBitrate)
{
MS_TRACE();

Expand Down Expand Up @@ -281,6 +282,16 @@ namespace RTC
}
}

void TransportCongestionControlClient::SetMinOutgoingBitrate(uint32_t minBitrate)
{
this->minOutgoingBitrate = minBitrate;

ApplyBitrateUpdates();

this->bitrates.minBitrate = std::max<uint32_t>(
this->minOutgoingBitrate, RTC::TransportCongestionControlMinOutgoingBitrate);
}

void TransportCongestionControlClient::SetDesiredBitrate(uint32_t desiredBitrate, bool force)
{
MS_TRACE();
Expand All @@ -305,7 +316,9 @@ namespace RTC
this->bitrates.effectiveDesiredBitrate = desiredBitrate;
#endif

this->bitrates.minBitrate = RTC::TransportCongestionControlMinOutgoingBitrate;
this->bitrates.minBitrate = std::max<uint32_t>(
this->minOutgoingBitrate, RTC::TransportCongestionControlMinOutgoingBitrate);

// NOTE: Setting 'startBitrate' to 'availableBitrate' has proven to generate
// more stable values.
this->bitrates.startBitrate = std::max<uint32_t>(
Expand Down Expand Up @@ -358,6 +371,9 @@ namespace RTC
this->bitrates.maxBitrate = newMaxBitrate;
}

this->bitrates.minBitrate = std::max<uint32_t>(
this->minOutgoingBitrate, RTC::TransportCongestionControlMinOutgoingBitrate);

MS_DEBUG_DEV(
"[desiredBitrate:%" PRIu32 ", desiredBitrateTrend:%" PRIu32 ", startBitrate:%" PRIu32
", minBitrate:%" PRIu32 ", maxBitrate:%" PRIu32 ", maxPaddingBitrate:%" PRIu32 "]",
Expand Down