Index: webrtc/media/engine/webrtcvoiceengine.cc |
diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc |
index e0d9884e8f1b2939b777b9f61df6e4722636e9ce..dcbdb65de0ecdbcdb805cdf8c38eea214b0411a2 100644 |
--- a/webrtc/media/engine/webrtcvoiceengine.cc |
+++ b/webrtc/media/engine/webrtcvoiceengine.cc |
@@ -40,12 +40,15 @@ |
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h" |
#include "webrtc/modules/audio_processing/include/audio_processing.h" |
#include "webrtc/system_wrappers/include/field_trial.h" |
+#include "webrtc/system_wrappers/include/metrics.h" |
#include "webrtc/system_wrappers/include/trace.h" |
#include "webrtc/voice_engine/transmit_mixer.h" |
namespace cricket { |
namespace { |
+constexpr size_t kMaxUnsignaledRecvStreams = 50; |
+ |
const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo | |
webrtc::kTraceWarning | webrtc::kTraceError | |
webrtc::kTraceCritical; |
@@ -2237,12 +2240,10 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) { |
return false; |
} |
- // If the default receive stream was created with this ssrc, we unmark it as |
- // being the default stream, and possibly recreate the AudioReceiveStream, if |
- // sync_label has changed. |
- if (IsDefaultRecvStream(ssrc)) { |
+ // If this stream was previously received unsignaled, we promote it, possibly |
+ // recreating the AudioReceiveStream, if sync_label has changed. |
+ if (MaybeDeregisterUnsignaledRecvStream(ssrc)) { |
recv_streams_[ssrc]->MaybeRecreateAudioReceiveStream(sp.sync_label); |
- default_recv_ssrc_ = -1; |
return true; |
} |
@@ -2306,10 +2307,7 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) { |
return false; |
} |
- // Deregister default channel, if that's the one being destroyed. |
- if (IsDefaultRecvStream(ssrc)) { |
- default_recv_ssrc_ = -1; |
- } |
+ MaybeDeregisterUnsignaledRecvStream(ssrc); |
const int channel = it->second->channel(); |
@@ -2369,21 +2367,21 @@ int WebRtcVoiceMediaChannel::GetOutputLevel() { |
bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) { |
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
+ std::vector<uint32_t> ssrcs(1, ssrc); |
if (ssrc == 0) { |
default_recv_volume_ = volume; |
- if (default_recv_ssrc_ == -1) { |
- return true; |
- } |
- ssrc = static_cast<uint32_t>(default_recv_ssrc_); |
+ ssrcs = unsignaled_recv_ssrcs_; |
} |
- const auto it = recv_streams_.find(ssrc); |
- if (it == recv_streams_.end()) { |
- LOG(LS_WARNING) << "SetOutputVolume: no recv stream" << ssrc; |
- return false; |
+ for (uint32_t ssrc : ssrcs) { |
+ const auto it = recv_streams_.find(ssrc); |
+ if (it == recv_streams_.end()) { |
+ LOG(LS_WARNING) << "SetOutputVolume: no recv stream " << ssrc; |
+ return false; |
+ } |
+ it->second->SetOutputVolume(volume); |
+ LOG(LS_INFO) << "SetOutputVolume() to " << volume |
+ << " for recv stream with ssrc " << ssrc; |
} |
- it->second->SetOutputVolume(volume); |
- LOG(LS_INFO) << "SetOutputVolume() to " << volume |
- << " for recv stream with ssrc " << ssrc; |
return true; |
} |
@@ -2434,35 +2432,53 @@ void WebRtcVoiceMediaChannel::OnPacketReceived( |
return; |
} |
- // Create a default receive stream for this unsignalled and previously not |
- // received ssrc. If there already is a default receive stream, delete it. |
+ // Create an unsignaled receive stream for this previously not received ssrc. |
+ // If there already is N unsignaled receive streams, delete the oldest. |
// See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5208 |
uint32_t ssrc = 0; |
if (!GetRtpSsrc(packet->cdata(), packet->size(), &ssrc)) { |
return; |
} |
+ RTC_DCHECK(std::find(unsignaled_recv_ssrcs_.begin(), |
+ unsignaled_recv_ssrcs_.end(), ssrc) == unsignaled_recv_ssrcs_.end()); |
+ // Add new stream. |
StreamParams sp; |
sp.ssrcs.push_back(ssrc); |
- LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << "."; |
+ LOG(LS_INFO) << "Creating unsignaled receive stream for SSRC=" << ssrc; |
if (!AddRecvStream(sp)) { |
- LOG(LS_WARNING) << "Could not create default receive stream."; |
+ LOG(LS_WARNING) << "Could not create unsignaled receive stream."; |
return; |
} |
- if (default_recv_ssrc_ != -1) { |
- LOG(LS_INFO) << "Removing default receive stream with ssrc " |
- << default_recv_ssrc_; |
- RTC_DCHECK_NE(ssrc, default_recv_ssrc_); |
- RemoveRecvStream(default_recv_ssrc_); |
+ unsignaled_recv_ssrcs_.push_back(ssrc); |
+ RTC_HISTOGRAM_COUNTS_LINEAR( |
+ "WebRTC.Audio.NumOfUnsignaledStreams", unsignaled_recv_ssrcs_.size(), 1, |
+ 100, 101); |
+ |
+ // Remove oldest unsignaled stream, if we have too many. |
+ if (unsignaled_recv_ssrcs_.size() > kMaxUnsignaledRecvStreams) { |
+ uint32_t remove_ssrc = unsignaled_recv_ssrcs_.front(); |
+ LOG(LS_INFO) << "Removing unsignaled receive stream with SSRC=" |
+ << remove_ssrc; |
+ RemoveRecvStream(remove_ssrc); |
} |
- default_recv_ssrc_ = ssrc; |
+ RTC_DCHECK_GE(kMaxUnsignaledRecvStreams, unsignaled_recv_ssrcs_.size()); |
- SetOutputVolume(default_recv_ssrc_, default_recv_volume_); |
+ SetOutputVolume(ssrc, default_recv_volume_); |
+ |
+ // The default sink can only be attached to one stream at a time, so we hook |
+ // it up to the *latest* unsignaled stream we've seen, in order to support the |
+ // case where the SSRC of one unsignaled stream changes. |
if (default_sink_) { |
+ for (uint32_t drop_ssrc : unsignaled_recv_ssrcs_) { |
+ auto it = recv_streams_.find(drop_ssrc); |
+ it->second->SetRawAudioSink(nullptr); |
+ } |
std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink( |
new ProxySink(default_sink_.get())); |
- SetRawAudioSink(default_recv_ssrc_, std::move(proxy_sink)); |
+ SetRawAudioSink(ssrc, std::move(proxy_sink)); |
} |
+ |
delivery_result = call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO, |
packet->cdata(), |
packet->size(), |
@@ -2627,17 +2643,17 @@ void WebRtcVoiceMediaChannel::SetRawAudioSink( |
LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::SetRawAudioSink: ssrc:" << ssrc |
<< " " << (sink ? "(ptr)" : "NULL"); |
if (ssrc == 0) { |
- if (default_recv_ssrc_ != -1) { |
+ if (!unsignaled_recv_ssrcs_.empty()) { |
std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink( |
sink ? new ProxySink(sink.get()) : nullptr); |
- SetRawAudioSink(default_recv_ssrc_, std::move(proxy_sink)); |
+ SetRawAudioSink(unsignaled_recv_ssrcs_.back(), std::move(proxy_sink)); |
} |
default_sink_ = std::move(sink); |
return; |
} |
const auto it = recv_streams_.find(ssrc); |
if (it == recv_streams_.end()) { |
- LOG(LS_WARNING) << "SetRawAudioSink: no recv stream" << ssrc; |
+ LOG(LS_WARNING) << "SetRawAudioSink: no recv stream " << ssrc; |
return; |
} |
it->second->SetRawAudioSink(std::move(sink)); |
@@ -2666,6 +2682,19 @@ int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const { |
} |
return -1; |
} |
+ |
+bool WebRtcVoiceMediaChannel:: |
+ MaybeDeregisterUnsignaledRecvStream(uint32_t ssrc) { |
+ RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
+ auto it = std::find(unsignaled_recv_ssrcs_.begin(), |
+ unsignaled_recv_ssrcs_.end(), |
+ ssrc); |
+ if (it != unsignaled_recv_ssrcs_.end()) { |
+ unsignaled_recv_ssrcs_.erase(it); |
+ return true; |
+ } |
+ return false; |
+} |
} // namespace cricket |
#endif // HAVE_WEBRTC_VOICE |