Bug 1949282 - Add to known unique PTs instead of replacing when signaling is not stable.;r=bwc

Depends on D238836

Differential Revision: https://phabricator.services.mozilla.com/D241311
This commit is contained in:
Dan Baker
2025-03-20 14:57:12 +00:00
parent 5186c3c8fe
commit dd5f2aa6b4
9 changed files with 80 additions and 33 deletions

View File

@@ -694,6 +694,8 @@ void RTCRtpReceiver::UpdateTransport() {
} }
UniquePtr<MediaPipelineFilter> filter; UniquePtr<MediaPipelineFilter> filter;
bool signalingStable =
(mPc->GetSignalingState() == RTCSignalingState::Stable);
auto const& details = GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails(); auto const& details = GetJsepTransceiver().mRecvTrack.GetNegotiatedDetails();
std::vector<webrtc::RtpExtension> extmaps; std::vector<webrtc::RtpExtension> extmaps;
@@ -724,14 +726,22 @@ void RTCRtpReceiver::UpdateTransport() {
// Add unique payload types as a last-ditch fallback // Add unique payload types as a last-ditch fallback
auto uniquePts = auto uniquePts =
GetJsepTransceiver().mRecvTrack.GetUniqueReceivePayloadTypes(); GetJsepTransceiver().mRecvTrack.GetUniqueReceivePayloadTypes();
for (unsigned char& uniquePt : uniquePts) { for (auto uniquePt : uniquePts) {
filter->AddUniqueReceivePT(uniquePt); filter->AddUniqueReceivePT(uniquePt);
} }
// Add duplicate payload types
auto duplicatePts =
GetJsepTransceiver().mRecvTrack.GetDuplicateReceivePayloadTypes();
for (auto duplicatePt : duplicatePts) {
filter->AddDuplicateReceivePT(duplicatePt);
}
} }
if ((mPc->GetSignalingState() == RTCSignalingState::Stable) || filter) { if (signalingStable || filter) {
mPipeline->UpdateTransport_m(GetJsepTransceiver().mTransport.mTransportId, mPipeline->UpdateTransport_m(GetJsepTransceiver().mTransport.mTransportId,
std::move(filter)); std::move(filter), signalingStable);
} }
} }

View File

@@ -1393,7 +1393,7 @@ void RTCRtpSender::UpdateTransport() {
} }
mPipeline->UpdateTransport_m(GetJsepTransceiver().mTransport.mTransportId, mPipeline->UpdateTransport_m(GetJsepTransceiver().mTransport.mTransportId,
nullptr); nullptr, true);
} }
void RTCRtpSender::MaybeUpdateConduit() { void RTCRtpSender::MaybeUpdateConduit() {

View File

@@ -731,7 +731,7 @@ void JsepTrack::SetUniqueReceivePayloadTypes(std::vector<JsepTrack*>& tracks,
bool localOffer) { bool localOffer) {
// Maps to track details if no other track contains the payload type, // Maps to track details if no other track contains the payload type,
// otherwise maps to nullptr. // otherwise maps to nullptr.
std::map<uint16_t, JsepTrack*> payloadTypeToDetailsMap; std::map<uint16_t, std::tuple<JsepTrack*, bool>> payloadTypeToDetailsMap;
for (JsepTrack* track : tracks) { for (JsepTrack* track : tracks) {
if (track->GetMediaType() == SdpMediaSection::kApplication) { if (track->GetMediaType() == SdpMediaSection::kApplication) {
@@ -751,23 +751,24 @@ void JsepTrack::SetUniqueReceivePayloadTypes(std::vector<JsepTrack*>& tracks,
} }
for (uint16_t pt : payloadTypesForTrack) { for (uint16_t pt : payloadTypesForTrack) {
if (payloadTypeToDetailsMap.count(pt)) { payloadTypeToDetailsMap[pt] =
// Found in more than one track, not unique std::make_tuple(track, !payloadTypeToDetailsMap.count(pt));
payloadTypeToDetailsMap[pt] = nullptr;
} else {
payloadTypeToDetailsMap[pt] = track;
}
} }
} }
for (auto ptAndDetails : payloadTypeToDetailsMap) { for (auto ptAndDetails : payloadTypeToDetailsMap) {
uint16_t uniquePt = ptAndDetails.first; uint16_t uniquePt = ptAndDetails.first;
MOZ_ASSERT(uniquePt <= UINT8_MAX); MOZ_ASSERT(uniquePt <= UINT8_MAX);
auto* trackDetails = ptAndDetails.second; auto* trackDetails = std::get<JsepTrack*>(ptAndDetails.second);
if (trackDetails) { if (trackDetails) {
if (std::get<bool>(ptAndDetails.second)) {
trackDetails->mUniqueReceivePayloadTypes.push_back( trackDetails->mUniqueReceivePayloadTypes.push_back(
static_cast<uint8_t>(uniquePt)); static_cast<uint8_t>(uniquePt));
} else {
trackDetails->mDuplicateReceivePayloadTypes.push_back(
static_cast<uint8_t>(uniquePt));
}
} }
} }
} }

View File

@@ -136,6 +136,7 @@ class JsepTrack {
mVideoPreferredCodec = rhs.mVideoPreferredCodec; mVideoPreferredCodec = rhs.mVideoPreferredCodec;
mUniqueReceivePayloadTypes = rhs.mUniqueReceivePayloadTypes; mUniqueReceivePayloadTypes = rhs.mUniqueReceivePayloadTypes;
mReceivePayloadTypes = rhs.mReceivePayloadTypes; mReceivePayloadTypes = rhs.mReceivePayloadTypes;
mDuplicateReceivePayloadTypes = rhs.mDuplicateReceivePayloadTypes;
mPrototypeCodecs.clear(); mPrototypeCodecs.clear();
for (const auto& codec : rhs.mPrototypeCodecs) { for (const auto& codec : rhs.mPrototypeCodecs) {
@@ -264,6 +265,10 @@ class JsepTrack {
return mUniqueReceivePayloadTypes; return mUniqueReceivePayloadTypes;
} }
std::vector<uint8_t> GetDuplicateReceivePayloadTypes() const {
return mDuplicateReceivePayloadTypes;
}
private: private:
std::vector<UniquePtr<JsepCodecDescription>> GetCodecClones() const; std::vector<UniquePtr<JsepCodecDescription>> GetCodecClones() const;
static void EnsureNoDuplicatePayloadTypes( static void EnsureNoDuplicatePayloadTypes(
@@ -336,6 +341,8 @@ class JsepTrack {
// Used for matching SSRC to PT as only unique PTs support for this. // Used for matching SSRC to PT as only unique PTs support for this.
std::vector<uint8_t> mUniqueReceivePayloadTypes; std::vector<uint8_t> mUniqueReceivePayloadTypes;
std::vector<uint16_t> mReceivePayloadTypes; std::vector<uint16_t> mReceivePayloadTypes;
// Payload types that are duplicate
std::vector<uint8_t> mDuplicateReceivePayloadTypes;
}; };
} // namespace mozilla } // namespace mozilla

View File

@@ -298,17 +298,21 @@ void MediaPipeline::DetachTransport_s() {
mReceiverRtcpSendEventListener.DisconnectIfExists(); mReceiverRtcpSendEventListener.DisconnectIfExists();
} }
void MediaPipeline::UpdateTransport_m( void MediaPipeline::UpdateTransport_m(const std::string& aTransportId,
const std::string& aTransportId, UniquePtr<MediaPipelineFilter>&& aFilter) { UniquePtr<MediaPipelineFilter>&& aFilter,
bool aSignalingStable) {
mStsThread->Dispatch(NS_NewRunnableFunction( mStsThread->Dispatch(NS_NewRunnableFunction(
__func__, [aTransportId, filter = std::move(aFilter), __func__,
self = RefPtr<MediaPipeline>(this)]() mutable { [aTransportId, filter = std::move(aFilter),
self->UpdateTransport_s(aTransportId, std::move(filter)); self = RefPtr<MediaPipeline>(this), aSignalingStable]() mutable {
self->UpdateTransport_s(aTransportId, std::move(filter),
aSignalingStable);
})); }));
} }
void MediaPipeline::UpdateTransport_s( void MediaPipeline::UpdateTransport_s(const std::string& aTransportId,
const std::string& aTransportId, UniquePtr<MediaPipelineFilter>&& aFilter) { UniquePtr<MediaPipelineFilter>&& aFilter,
bool aSignalingStable) {
ASSERT_ON_THREAD(mStsThread); ASSERT_ON_THREAD(mStsThread);
if (!mSignalsConnected) { if (!mSignalsConnected) {
mTransportHandler->SignalStateChange.connect( mTransportHandler->SignalStateChange.connect(
@@ -339,7 +343,7 @@ void MediaPipeline::UpdateTransport_s(
if (mFilter && aFilter) { if (mFilter && aFilter) {
// Use the new filter, but don't forget any remote SSRCs that we've learned // Use the new filter, but don't forget any remote SSRCs that we've learned
// by receiving traffic. // by receiving traffic.
mFilter->Update(*aFilter); mFilter->Update(*aFilter, aSignalingStable);
} else { } else {
mFilter = std::move(aFilter); mFilter = std::move(aFilter);
} }

View File

@@ -112,10 +112,12 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual void Shutdown(); virtual void Shutdown();
void UpdateTransport_m(const std::string& aTransportId, void UpdateTransport_m(const std::string& aTransportId,
UniquePtr<MediaPipelineFilter>&& aFilter); UniquePtr<MediaPipelineFilter>&& aFilter,
bool aSignalingStable);
void UpdateTransport_s(const std::string& aTransportId, void UpdateTransport_s(const std::string& aTransportId,
UniquePtr<MediaPipelineFilter>&& aFilter); UniquePtr<MediaPipelineFilter>&& aFilter,
bool aSignalingStable);
virtual DirectionType Direction() const { return mDirection; } virtual DirectionType Direction() const { return mDirection; }
size_t Level() const { return mLevel; } size_t Level() const { return mLevel; }

View File

@@ -130,7 +130,12 @@ void MediaPipelineFilter::AddUniqueReceivePT(uint8_t payload_type) {
receive_payload_type_set_.insert(payload_type); receive_payload_type_set_.insert(payload_type);
} }
void MediaPipelineFilter::Update(const MediaPipelineFilter& filter_update) { void MediaPipelineFilter::AddDuplicateReceivePT(uint8_t payload_type) {
duplicate_payload_type_set_.insert(payload_type);
}
void MediaPipelineFilter::Update(const MediaPipelineFilter& filter_update,
bool signalingStable) {
// We will not stomp the remote_ssrc_set_ if the update has no ssrcs, // We will not stomp the remote_ssrc_set_ if the update has no ssrcs,
// because we don't want to unlearn any remote ssrcs unless the other end // because we don't want to unlearn any remote ssrcs unless the other end
// has explicitly given us a new set. // has explicitly given us a new set.
@@ -144,7 +149,20 @@ void MediaPipelineFilter::Update(const MediaPipelineFilter& filter_update) {
mRemoteMid = filter_update.mRemoteMid; mRemoteMid = filter_update.mRemoteMid;
mRemoteMidBindings = filter_update.mRemoteMidBindings; mRemoteMidBindings = filter_update.mRemoteMidBindings;
} }
// If we are signaling is stable replace the filters values otherwise add to
// them.
if (signalingStable) {
receive_payload_type_set_ = filter_update.receive_payload_type_set_; receive_payload_type_set_ = filter_update.receive_payload_type_set_;
duplicate_payload_type_set_ = filter_update.duplicate_payload_type_set_;
} else {
for (const auto& uniquePT : filter_update.receive_payload_type_set_) {
if (!receive_payload_type_set_.count(uniquePT) &&
!duplicate_payload_type_set_.count(uniquePT)) {
AddUniqueReceivePT(uniquePT);
}
}
}
// Use extmapping from new filter // Use extmapping from new filter
mExtMap = filter_update.mExtMap; mExtMap = filter_update.mExtMap;

View File

@@ -68,7 +68,10 @@ class MediaPipelineFilter {
// When a payload type id is unique to our media section, add it here. // When a payload type id is unique to our media section, add it here.
void AddUniqueReceivePT(uint8_t payload_type); void AddUniqueReceivePT(uint8_t payload_type);
void Update(const MediaPipelineFilter& filter_update); // When a payload type id is NOT unique to our media section, add it here.
void AddDuplicateReceivePT(uint8_t payload_type);
void Update(const MediaPipelineFilter& filter_update, bool signalingStable);
std::vector<webrtc::RtpExtension> GetExtmap() const { return mExtMap; } std::vector<webrtc::RtpExtension> GetExtmap() const { return mExtMap; }
@@ -77,6 +80,7 @@ class MediaPipelineFilter {
// for readability. // for readability.
std::set<uint32_t> remote_ssrc_set_; std::set<uint32_t> remote_ssrc_set_;
std::set<uint8_t> receive_payload_type_set_; std::set<uint8_t> receive_payload_type_set_;
std::set<uint8_t> duplicate_payload_type_set_;
Maybe<std::string> mRemoteMid; Maybe<std::string> mRemoteMid;
std::set<uint32_t> mRemoteMidBindings; std::set<uint32_t> mRemoteMidBindings;
// RID extension can be set by tests and is sticky, the rest of // RID extension can be set by tests and is sticky, the rest of

View File

@@ -290,7 +290,7 @@ class TestAgent {
void UpdateTransport_s(const std::string& aTransportId, void UpdateTransport_s(const std::string& aTransportId,
UniquePtr<MediaPipelineFilter>&& aFilter) { UniquePtr<MediaPipelineFilter>&& aFilter) {
audio_pipeline_->UpdateTransport_s(aTransportId, std::move(aFilter)); audio_pipeline_->UpdateTransport_s(aTransportId, std::move(aFilter), false);
} }
void Stop() { void Stop() {
@@ -380,7 +380,7 @@ class TestAgentSend : public TestAgent {
audio_pipeline->SetSendTrackOverride(audio_track_); audio_pipeline->SetSendTrackOverride(audio_track_);
control_.Update([](auto& aControl) { aControl.mTransmitting = true; }); control_.Update([](auto& aControl) { aControl.mTransmitting = true; });
audio_pipeline->UpdateTransport_m(aTransportId, nullptr); audio_pipeline->UpdateTransport_m(aTransportId, nullptr, true);
audio_pipeline_ = audio_pipeline; audio_pipeline_ = audio_pipeline;
} }
}; };
@@ -411,7 +411,8 @@ class TestAgentReceive : public TestAgent {
})); }));
control_.Update([](auto& aControl) { aControl.mReceiving = true; }); control_.Update([](auto& aControl) { aControl.mReceiving = true; });
audio_pipeline->UpdateTransport_m(aTransportId, std::move(bundle_filter_)); audio_pipeline->UpdateTransport_m(aTransportId, std::move(bundle_filter_),
true);
audio_pipeline_ = audio_pipeline; audio_pipeline_ = audio_pipeline;
} }
@@ -421,7 +422,7 @@ class TestAgentReceive : public TestAgent {
void UpdateTransport_s(const std::string& aTransportId, void UpdateTransport_s(const std::string& aTransportId,
UniquePtr<MediaPipelineFilter>&& filter) { UniquePtr<MediaPipelineFilter>&& filter) {
audio_pipeline_->UpdateTransport_s(aTransportId, std::move(filter)); audio_pipeline_->UpdateTransport_s(aTransportId, std::move(filter), false);
} }
private: private:
@@ -684,7 +685,7 @@ TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) {
// Update but remember binding./ // Update but remember binding./
MediaPipelineFilter filter2; MediaPipelineFilter filter2;
filter.Update(filter2); filter.Update(filter2, true);
// Ensure that the old SSRC still works. // Ensure that the old SSRC still works.
EXPECT_TRUE(Filter(filter, 555, 110)); EXPECT_TRUE(Filter(filter, 555, 110));
@@ -692,7 +693,7 @@ TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) {
// Forget the previous binding // Forget the previous binding
MediaPipelineFilter filter3; MediaPipelineFilter filter3;
filter3.SetRemoteMediaStreamId(Some(std::string("mid1"))); filter3.SetRemoteMediaStreamId(Some(std::string("mid1")));
filter.Update(filter3); filter.Update(filter3, true);
ASSERT_FALSE(Filter(filter, 555, 110)); ASSERT_FALSE(Filter(filter, 555, 110));
} }