Skip to content

Commit

Permalink
Default streams: don't block media even if on different transceiver.
Browse files Browse the repository at this point in the history
This fixes some edge cases where early media could cause default
stream that block the actual signaled media from beind delivered.

Bug: webrtc:11477
Change-Id: I8b26df63a690861bd19f083102d1395e882f8733
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/183120
Commit-Queue: Taylor <[email protected]>
Reviewed-by: Erik Språng <[email protected]>
Reviewed-by: Rasmus Brandt <[email protected]>
Cr-Commit-Position: refs/heads/master@{#32030}
  • Loading branch information
Taylor Brandstetter authored and Commit Bot committed Sep 2, 2020
1 parent 0ade983 commit c03a187
Show file tree
Hide file tree
Showing 17 changed files with 393 additions and 39 deletions.
3 changes: 2 additions & 1 deletion media/base/media_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ class MediaChannel : public sigslot::has_slots<> {
// ssrc must be the first SSRC of the media stream if the stream uses
// multiple SSRCs.
virtual bool RemoveRecvStream(uint32_t ssrc) = 0;
// Resets any cached StreamParams for an unsignaled RecvStream.
// Resets any cached StreamParams for an unsignaled RecvStream, and removes
// any existing unsignaled streams.
virtual void ResetUnsignaledRecvStream() = 0;
// Returns the absoulte sendtime extension id value from media channel.
virtual int GetRtpSendTimeExtnId() const;
Expand Down
5 changes: 5 additions & 0 deletions media/engine/webrtc_voice_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2028,6 +2028,11 @@ void WebRtcVoiceMediaChannel::ResetUnsignaledRecvStream() {
RTC_DCHECK(worker_thread_checker_.IsCurrent());
RTC_LOG(LS_INFO) << "ResetUnsignaledRecvStream.";
unsignaled_stream_params_ = StreamParams();
// Create a copy since RemoveRecvStream will modify |unsignaled_recv_ssrcs_|.
std::vector<uint32_t> to_remove = unsignaled_recv_ssrcs_;
for (uint32_t ssrc : to_remove) {
RemoveRecvStream(ssrc);
}
}

bool WebRtcVoiceMediaChannel::SetLocalSource(uint32_t ssrc,
Expand Down
24 changes: 24 additions & 0 deletions media/engine/webrtc_voice_engine_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2722,6 +2722,30 @@ TEST_P(WebRtcVoiceEngineTestFake, RecvUnsignaledSsrcWithSignaledStreamId) {
EXPECT_TRUE(GetRecvStream(kSsrc1).GetConfig().sync_group.empty());
}

TEST_P(WebRtcVoiceEngineTestFake,
ResetUnsignaledRecvStreamDeletesAllDefaultStreams) {
ASSERT_TRUE(SetupChannel());
// No receive streams to start with.
ASSERT_TRUE(call_.GetAudioReceiveStreams().empty());

// Deliver a couple packets with unsignaled SSRCs.
unsigned char packet[sizeof(kPcmuFrame)];
memcpy(packet, kPcmuFrame, sizeof(kPcmuFrame));
rtc::SetBE32(&packet[8], 0x1234);
DeliverPacket(packet, sizeof(packet));
rtc::SetBE32(&packet[8], 0x5678);
DeliverPacket(packet, sizeof(packet));

// Verify that the receive streams were created.
const auto& receivers1 = call_.GetAudioReceiveStreams();
ASSERT_EQ(receivers1.size(), 2u);

// Should remove all default streams.
channel_->ResetUnsignaledRecvStream();
const auto& receivers2 = call_.GetAudioReceiveStreams();
EXPECT_EQ(0u, receivers2.size());
}

// Test that receiving N unsignaled stream works (streams will be created), and
// that packets are forwarded to them all.
TEST_P(WebRtcVoiceEngineTestFake, RecvMultipleUnsignaled) {
Expand Down
1 change: 1 addition & 0 deletions pc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ rtc_library("rtc_pc_base") {
"../rtc_base:rtc_task_queue",
"../rtc_base:stringutils",
"../rtc_base/synchronization:mutex",
"../rtc_base/synchronization:sequence_checker",
"../rtc_base/system:file_wrapper",
"../rtc_base/system:rtc_export",
"../rtc_base/third_party/base64",
Expand Down
62 changes: 45 additions & 17 deletions pc/channel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "rtc_base/logging.h"
#include "rtc_base/network_route.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/synchronization/sequence_checker.h"
#include "rtc_base/trace_event.h"

namespace cricket {
Expand Down Expand Up @@ -206,7 +207,7 @@ void BaseChannel::Init_w(webrtc::RtpTransportInternal* rtp_transport) {
}

void BaseChannel::Deinit() {
RTC_DCHECK(worker_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(worker_thread());
media_channel_->SetInterface(/*iface=*/nullptr);
// Packets arrive on the network thread, processing packets calls virtual
// functions, so need to stop this process in Deinit that is called in
Expand Down Expand Up @@ -289,6 +290,13 @@ bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
Bind(&BaseChannel::SetRemoteContent_w, this, content, type, error_desc));
}

void BaseChannel::SetPayloadTypeDemuxingEnabled(bool enabled) {
TRACE_EVENT0("webrtc", "BaseChannel::SetPayloadTypeDemuxingEnabled");
InvokeOnWorker<void>(
RTC_FROM_HERE,
Bind(&BaseChannel::SetPayloadTypeDemuxingEnabled_w, this, enabled));
}

bool BaseChannel::IsReadyToReceiveMedia_w() const {
// Receive data if we are enabled and have local content,
return enabled() &&
Expand Down Expand Up @@ -330,7 +338,7 @@ int BaseChannel::SetOption(SocketType type,
int BaseChannel::SetOption_n(SocketType type,
rtc::Socket::Option opt,
int value) {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
RTC_DCHECK(rtp_transport_);
switch (type) {
case ST_RTP:
Expand All @@ -346,7 +354,7 @@ int BaseChannel::SetOption_n(SocketType type,
}

void BaseChannel::OnWritableState(bool writable) {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
if (writable) {
ChannelWritable_n();
} else {
Expand All @@ -358,7 +366,7 @@ void BaseChannel::OnNetworkRouteChanged(
absl::optional<rtc::NetworkRoute> network_route) {
RTC_LOG(LS_INFO) << "Network route for " << ToString() << " was changed.";

RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
rtc::NetworkRoute new_route;
if (network_route) {
new_route = *(network_route);
Expand Down Expand Up @@ -479,7 +487,7 @@ void BaseChannel::OnRtpPacket(const webrtc::RtpPacketReceived& parsed_packet) {

invoker_.AsyncInvoke<void>(
RTC_FROM_HERE, worker_thread_, [this, packet_buffer, packet_time_us] {
RTC_DCHECK(worker_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(worker_thread());
media_channel_->OnPacketReceived(packet_buffer, packet_time_us);
});
}
Expand Down Expand Up @@ -537,7 +545,7 @@ void BaseChannel::UpdateWritableState_n() {
}

void BaseChannel::ChannelWritable_n() {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
if (writable_) {
return;
}
Expand All @@ -551,7 +559,7 @@ void BaseChannel::ChannelWritable_n() {
}

void BaseChannel::ChannelNotWritable_n() {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
if (!writable_)
return;

Expand All @@ -575,6 +583,24 @@ void BaseChannel::ResetUnsignaledRecvStream_w() {
media_channel()->ResetUnsignaledRecvStream();
}

void BaseChannel::SetPayloadTypeDemuxingEnabled_w(bool enabled) {
RTC_DCHECK_RUN_ON(worker_thread());
if (enabled == payload_type_demuxing_enabled_) {
return;
}
if (!enabled) {
// TODO(crbug.com/11477): This will remove *all* unsignaled streams (those
// without an explicitly signaled SSRC), which may include streams that
// were matched to this channel by MID or RID. Ideally we'd remove only the
// streams that were matched based on payload type alone, but currently
// there is no straightforward way to identify those streams.
media_channel()->ResetUnsignaledRecvStream();
ClearHandledPayloadTypes();
RegisterRtpDemuxerSink();
}
payload_type_demuxing_enabled_ = enabled;
}

bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
SdpType type,
std::string* error_desc) {
Expand Down Expand Up @@ -741,7 +767,7 @@ void BaseChannel::OnMessage(rtc::Message* pmsg) {
switch (pmsg->message_id) {
case MSG_SEND_RTP_PACKET:
case MSG_SEND_RTCP_PACKET: {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
SendPacketMessageData* data =
static_cast<SendPacketMessageData*>(pmsg->pdata);
bool rtcp = pmsg->message_id == MSG_SEND_RTCP_PACKET;
Expand All @@ -756,8 +782,10 @@ void BaseChannel::OnMessage(rtc::Message* pmsg) {
}
}

void BaseChannel::AddHandledPayloadType(int payload_type) {
demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
void BaseChannel::MaybeAddHandledPayloadType(int payload_type) {
if (payload_type_demuxing_enabled_) {
demuxer_criteria_.payload_types.insert(static_cast<uint8_t>(payload_type));
}
}

void BaseChannel::ClearHandledPayloadTypes() {
Expand All @@ -767,7 +795,7 @@ void BaseChannel::ClearHandledPayloadTypes() {
void BaseChannel::FlushRtcpMessages_n() {
// Flush all remaining RTCP messages. This should only be called in
// destructor.
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
rtc::MessageList rtcp_messages;
network_thread_->Clear(this, MSG_SEND_RTCP_PACKET, &rtcp_messages);
for (const auto& message : rtcp_messages) {
Expand All @@ -777,10 +805,10 @@ void BaseChannel::FlushRtcpMessages_n() {
}

void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
[this, sent_packet] {
RTC_DCHECK(worker_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(worker_thread());
SignalSentPacket(sent_packet);
});
}
Expand Down Expand Up @@ -810,7 +838,7 @@ VoiceChannel::~VoiceChannel() {
}

void BaseChannel::UpdateMediaSendRecvState() {
RTC_DCHECK(network_thread_->IsCurrent());
RTC_DCHECK_RUN_ON(network_thread());
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, worker_thread_,
[this] { UpdateMediaSendRecvState_w(); });
}
Expand Down Expand Up @@ -869,7 +897,7 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,

if (webrtc::RtpTransceiverDirectionHasRecv(audio->direction())) {
for (const AudioCodec& codec : audio->codecs()) {
AddHandledPayloadType(codec.id);
MaybeAddHandledPayloadType(codec.id);
}
// Need to re-register the sink to update the handled payload.
if (!RegisterRtpDemuxerSink()) {
Expand Down Expand Up @@ -1062,7 +1090,7 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,

if (webrtc::RtpTransceiverDirectionHasRecv(video->direction())) {
for (const VideoCodec& codec : video->codecs()) {
AddHandledPayloadType(codec.id);
MaybeAddHandledPayloadType(codec.id);
}
// Need to re-register the sink to update the handled payload.
if (!RegisterRtpDemuxerSink()) {
Expand Down Expand Up @@ -1287,7 +1315,7 @@ bool RtpDataChannel::SetLocalContent_w(const MediaContentDescription* content,
return false;
}
for (const DataCodec& codec : data->codecs()) {
AddHandledPayloadType(codec.id);
MaybeAddHandledPayloadType(codec.id);
}
// Need to re-register the sink to update the handled payload.
if (!RegisterRtpDemuxerSink()) {
Expand Down
19 changes: 17 additions & 2 deletions pc/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
#include "rtc_base/async_invoker.h"
#include "rtc_base/async_udp_socket.h"
#include "rtc_base/network.h"
#include "rtc_base/synchronization/sequence_checker.h"
#include "rtc_base/third_party/sigslot/sigslot.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/unique_id_generator.h"

namespace webrtc {
Expand Down Expand Up @@ -124,6 +126,15 @@ class BaseChannel : public ChannelInterface,
bool SetRemoteContent(const MediaContentDescription* content,
webrtc::SdpType type,
std::string* error_desc) override;
// Controls whether this channel will receive packets on the basis of
// matching payload type alone. This is needed for legacy endpoints that
// don't signal SSRCs or use MID/RID, but doesn't make sense if there is
// more than channel of specific media type, As that creates an ambiguity.
//
// This method will also remove any existing streams that were bound to this
// channel on the basis of payload type, since one of these streams might
// actually belong to a new channel. See: crbug.com/webrtc/11477
void SetPayloadTypeDemuxingEnabled(bool enabled) override;

bool Enable(bool enable) override;

Expand Down Expand Up @@ -224,6 +235,7 @@ class BaseChannel : public ChannelInterface,
bool AddRecvStream_w(const StreamParams& sp);
bool RemoveRecvStream_w(uint32_t ssrc);
void ResetUnsignaledRecvStream_w();
void SetPayloadTypeDemuxingEnabled_w(bool enabled);
bool AddSendStream_w(const StreamParams& sp);
bool RemoveSendStream_w(uint32_t ssrc);

Expand Down Expand Up @@ -261,9 +273,11 @@ class BaseChannel : public ChannelInterface,
return worker_thread_->Invoke<T>(posted_from, functor);
}

void AddHandledPayloadType(int payload_type);
// Add |payload_type| to |demuxer_criteria_| if payload type demuxing is
// enabled.
void MaybeAddHandledPayloadType(int payload_type) RTC_RUN_ON(worker_thread());

void ClearHandledPayloadTypes();
void ClearHandledPayloadTypes() RTC_RUN_ON(worker_thread());

void UpdateRtpHeaderExtensionMap(
const RtpHeaderExtensions& header_extensions);
Expand Down Expand Up @@ -308,6 +322,7 @@ class BaseChannel : public ChannelInterface,
// well, but it can be changed only when signaling thread does a synchronous
// call to the worker thread, so it should be safe.
bool enabled_ = false;
bool payload_type_demuxing_enabled_ RTC_GUARDED_BY(worker_thread()) = true;
std::vector<StreamParams> local_streams_;
std::vector<StreamParams> remote_streams_;
webrtc::RtpTransceiverDirection local_content_direction_ =
Expand Down
1 change: 1 addition & 0 deletions pc/channel_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class ChannelInterface {
virtual bool SetRemoteContent(const MediaContentDescription* content,
webrtc::SdpType type,
std::string* error_desc) = 0;
virtual void SetPayloadTypeDemuxingEnabled(bool enabled) = 0;

// Access to the local and remote streams that were set on the channel.
virtual const std::vector<StreamParams>& local_streams() const = 0;
Expand Down
19 changes: 9 additions & 10 deletions pc/channel_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,15 @@ class ChannelManager final {
// call the appropriate Destroy*Channel method when done.

// Creates a voice channel, to be associated with the specified session.
VoiceChannel* CreateVoiceChannel(
webrtc::Call* call,
const cricket::MediaConfig& media_config,
webrtc::RtpTransportInternal* rtp_transport,
rtc::Thread* signaling_thread,
const std::string& content_name,
bool srtp_required,
const webrtc::CryptoOptions& crypto_options,
rtc::UniqueRandomIdGenerator* ssrc_generator,
const AudioOptions& options);
VoiceChannel* CreateVoiceChannel(webrtc::Call* call,
const cricket::MediaConfig& media_config,
webrtc::RtpTransportInternal* rtp_transport,
rtc::Thread* signaling_thread,
const std::string& content_name,
bool srtp_required,
const webrtc::CryptoOptions& crypto_options,
rtc::UniqueRandomIdGenerator* ssrc_generator,
const AudioOptions& options);
// Destroys a voice channel created by CreateVoiceChannel.
void DestroyVoiceChannel(VoiceChannel* voice_channel);

Expand Down
Loading

0 comments on commit c03a187

Please sign in to comment.