Move some receive stream configuration into webrtc::AudioReceiveStream.

Simplify creation of VoE channels and Call streams in WVoMC.

BUG=webrtc:4690

Review URL: https://codereview.webrtc.org/1454073002

Cr-Commit-Position: refs/heads/master@{#10731}
This commit is contained in:
solenberg 2015-11-20 09:59:34 -08:00 committed by Commit bot
parent 6834fa10f1
commit 7add058439
7 changed files with 274 additions and 337 deletions

View File

@ -188,8 +188,6 @@ class FakeWebRtcVoiceEngine
red_type(117),
nack_max_packets(0),
send_ssrc(0),
receive_audio_level_ext_(-1),
receive_absolute_sender_time_ext_(-1),
associate_send_channel(-1),
neteq_capacity(-1),
neteq_fast_accelerate(false) {
@ -211,8 +209,6 @@ class FakeWebRtcVoiceEngine
int red_type;
int nack_max_packets;
uint32_t send_ssrc;
int receive_audio_level_ext_;
int receive_absolute_sender_time_ext_;
int associate_send_channel;
DtmfInfo dtmf_info;
std::vector<webrtc::CodecInst> recv_codecs;
@ -352,15 +348,6 @@ class FakeWebRtcVoiceEngine
channels_[++last_channel_] = ch;
return last_channel_;
}
int GetReceiveRtpExtensionId(int channel, const std::string& extension) {
WEBRTC_ASSERT_CHANNEL(channel);
if (extension == kRtpAudioLevelHeaderExtension) {
return channels_[channel]->receive_audio_level_ext_;
} else if (extension == kRtpAbsoluteSenderTimeHeaderExtension) {
return channels_[channel]->receive_absolute_sender_time_ext_;
}
return -1;
}
int GetNumSetSendCodecs() const { return num_set_send_codecs_; }
@ -710,23 +697,12 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(GetRemoteSSRC, (int channel, unsigned int& ssrc));
WEBRTC_STUB(SetSendAudioLevelIndicationStatus, (int channel, bool enable,
unsigned char id));
WEBRTC_FUNC(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
unsigned char id)) {
WEBRTC_CHECK_CHANNEL(channel);
WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
channels_[channel]->receive_audio_level_ext_ = (enable) ? id : -1;
return 0;
}
WEBRTC_STUB(SetReceiveAudioLevelIndicationStatus, (int channel, bool enable,
unsigned char id));
WEBRTC_STUB(SetSendAbsoluteSenderTimeStatus, (int channel, bool enable,
unsigned char id));
WEBRTC_FUNC(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
unsigned char id)) {
WEBRTC_CHECK_CHANNEL(channel);
WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id);
channels_[channel]->receive_absolute_sender_time_ext_ = (enable) ? id : -1;
return 0;
}
WEBRTC_STUB(SetReceiveAbsoluteSenderTimeStatus, (int channel, bool enable,
unsigned char id));
WEBRTC_STUB(SetRTCPStatus, (int channel, bool enable));
WEBRTC_STUB(GetRTCPStatus, (int channel, bool& enabled));
WEBRTC_STUB(SetRTCP_CNAME, (int channel, const char cname[256]));

View File

@ -1135,6 +1135,7 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in,
}
return false;
}
const std::vector<RtpHeaderExtension>&
WebRtcVoiceEngine::rtp_header_extensions() const {
RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
@ -1353,8 +1354,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
uint32_t ssrc, const std::string& c_name,
const std::vector<webrtc::RtpExtension>& extensions,
webrtc::Call* call)
: channel_(ch),
voe_audio_transport_(voe_audio_transport),
: voe_audio_transport_(voe_audio_transport),
call_(call),
config_(nullptr) {
RTC_DCHECK_GE(ch, 0);
@ -1429,7 +1429,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread());
RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread());
RTC_DCHECK(voe_audio_transport_);
voe_audio_transport_->OnData(channel_,
voe_audio_transport_->OnData(config_.voe_channel_id,
audio_data,
bits_per_sample,
sample_rate,
@ -1449,13 +1449,12 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
// Accessor to the VoE channel ID.
int channel() const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
return channel_;
return config_.voe_channel_id;
}
private:
rtc::ThreadChecker worker_thread_checker_;
rtc::ThreadChecker audio_capture_thread_checker_;
const int channel_ = -1;
webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
webrtc::Call* call_ = nullptr;
webrtc::AudioSendStream::Config config_;
@ -1473,18 +1472,72 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
public:
explicit WebRtcAudioReceiveStream(int voe_channel_id)
: channel_(voe_channel_id) {}
WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc,
bool use_combined_bwe, const std::string& sync_group,
const std::vector<webrtc::RtpExtension>& extensions,
webrtc::Call* call)
: call_(call),
config_() {
RTC_DCHECK_GE(ch, 0);
RTC_DCHECK(call);
config_.rtp.remote_ssrc = remote_ssrc;
config_.rtp.local_ssrc = local_ssrc;
config_.voe_channel_id = ch;
config_.sync_group = sync_group;
RecreateAudioReceiveStream(use_combined_bwe, extensions);
}
int channel() { return channel_; }
~WebRtcAudioReceiveStream() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
call_->DestroyAudioReceiveStream(stream_);
}
void RecreateAudioReceiveStream(
const std::vector<webrtc::RtpExtension>& extensions) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions);
}
void RecreateAudioReceiveStream(bool use_combined_bwe) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions);
}
webrtc::AudioReceiveStream::Stats GetStats() const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RTC_DCHECK(stream_);
return stream_->GetStats();
}
int channel() const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
return config_.voe_channel_id;
}
private:
int channel_;
void RecreateAudioReceiveStream(bool use_combined_bwe,
const std::vector<webrtc::RtpExtension>& extensions) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
if (stream_) {
call_->DestroyAudioReceiveStream(stream_);
stream_ = nullptr;
}
config_.rtp.extensions = extensions;
config_.combined_audio_video_bwe = use_combined_bwe;
RTC_DCHECK(!stream_);
stream_ = call_->CreateAudioReceiveStream(config_);
RTC_CHECK(stream_);
}
rtc::ThreadChecker worker_thread_checker_;
webrtc::Call* call_ = nullptr;
webrtc::AudioReceiveStream::Config config_;
// The stream is owned by WebRtcAudioReceiveStream and may be reallocated if
// configuration changes.
webrtc::AudioReceiveStream* stream_ = nullptr;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream);
};
// WebRtcVoiceMediaChannel
WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
const AudioOptions& options,
webrtc::Call* call)
@ -1498,19 +1551,15 @@ WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel";
// Remove any remaining send streams.
// TODO(solenberg): Should be able to delete the streams directly, without
// going through RemoveNnStream(), once stream objects handle
// all (de)configuration.
while (!send_streams_.empty()) {
RemoveSendStream(send_streams_.begin()->first);
}
// Remove any remaining receive streams.
while (!receive_channels_.empty()) {
RemoveRecvStream(receive_channels_.begin()->first);
while (!recv_streams_.empty()) {
RemoveRecvStream(recv_streams_.begin()->first);
}
RTC_DCHECK(receive_streams_.empty());
// Unregister ourselves from the engine.
engine()->UnregisterChannel(this);
}
@ -1544,8 +1593,21 @@ bool WebRtcVoiceMediaChannel::SetRecvParameters(
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
// TODO(pthatcher): Refactor this to be more clean now that we have
// all the information at once.
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
if (!SetRecvCodecs(params.codecs)) {
return false;
}
std::vector<webrtc::RtpExtension> recv_rtp_extensions =
FindAudioRtpHeaderExtensions(params.extensions);
if (recv_rtp_extensions_ != recv_rtp_extensions) {
recv_rtp_extensions_.swap(recv_rtp_extensions);
for (auto& it : recv_streams_) {
it.second->RecreateAudioReceiveStream(recv_rtp_extensions_);
}
}
return true;
}
bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
@ -1579,7 +1641,10 @@ bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
}
// TODO(solenberg): Don't recreate unless options changed.
RecreateAudioReceiveStreams();
for (auto& it : recv_streams_) {
it.second->RecreateAudioReceiveStream(
options_.combined_audio_video_bwe.value_or(false));
}
LOG(LS_INFO) << "Set voice channel options. Current options: "
<< options_.ToString();
@ -1865,7 +1930,7 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
}
// Set nack status on receive channels and update |nack_enabled_|.
for (const auto& ch : receive_channels_) {
for (const auto& ch : recv_streams_) {
SetNack(ch.second->channel(), nack_enabled_);
}
@ -1901,49 +1966,6 @@ bool WebRtcVoiceMediaChannel::SetSendCodec(
return true;
}
bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
if (receive_extensions_ == extensions) {
return true;
}
for (const auto& ch : receive_channels_) {
if (!SetChannelRecvRtpHeaderExtensions(ch.second->channel(), extensions)) {
return false;
}
}
receive_extensions_ = extensions;
// Recreate AudioReceiveStream:s.
recv_rtp_extensions_ = FindAudioRtpHeaderExtensions(extensions);
RecreateAudioReceiveStreams();
return true;
}
bool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions(
int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
const RtpHeaderExtension* audio_level_extension =
FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
if (!SetHeaderExtension(
&webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id,
audio_level_extension)) {
return false;
}
const RtpHeaderExtension* send_time_extension =
FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
if (!SetHeaderExtension(
&webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id,
send_time_extension)) {
return false;
}
return true;
}
bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
desired_playout_ = playout;
return ChangePlayout(desired_playout_);
@ -1963,7 +1985,7 @@ bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
return true;
}
for (const auto& ch : receive_channels_) {
for (const auto& ch : recv_streams_) {
if (!SetPlayout(ch.second->channel(), playout)) {
LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
<< ch.second->channel() << " failed";
@ -2068,7 +2090,7 @@ int WebRtcVoiceMediaChannel::CreateVoEChannel() {
return id;
}
bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) {
if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
LOG_RTCERR1(DeRegisterExternalTransport, channel);
}
@ -2117,10 +2139,10 @@ bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
// with the same SSRC in order to send receiver reports.
if (send_streams_.size() == 1) {
receiver_reports_ssrc_ = ssrc;
for (const auto& ch : receive_channels_) {
int recv_channel = ch.second->channel();
for (const auto& stream : recv_streams_) {
int recv_channel = stream.second->channel();
if (engine()->voe()->rtp()->SetLocalSSRC(recv_channel, ssrc) != 0) {
LOG_RTCERR2(SetLocalSSRC, ch.second->channel(), ssrc);
LOG_RTCERR2(SetLocalSSRC, recv_channel, ssrc);
return false;
}
engine()->voe()->base()->AssociateSendChannel(recv_channel, channel);
@ -2146,15 +2168,12 @@ bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
int channel = it->second->channel();
ChangeSend(channel, SEND_NOTHING);
// Delete the WebRtcVoiceChannelRenderer object connected to the channel,
// this will disconnect the audio renderer with the send channel.
delete it->second;
send_streams_.erase(it);
// Clean up and delete the send channel.
// Clean up and delete the send stream+channel.
LOG(LS_INFO) << "Removing audio send stream " << ssrc
<< " with VoiceEngine channel #" << channel << ".";
if (!DeleteChannel(channel)) {
delete it->second;
send_streams_.erase(it);
if (!DeleteVoEChannel(channel)) {
return false;
}
if (send_streams_.empty()) {
@ -2171,7 +2190,7 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
return false;
}
uint32_t ssrc = sp.first_ssrc();
const uint32_t ssrc = sp.first_ssrc();
if (ssrc == 0) {
LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
return false;
@ -2183,52 +2202,19 @@ bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
RemoveRecvStream(ssrc);
}
if (receive_channels_.find(ssrc) != receive_channels_.end()) {
if (GetReceiveChannelId(ssrc) != -1) {
LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
return false;
}
RTC_DCHECK(receive_stream_params_.find(ssrc) == receive_stream_params_.end());
// Create a new channel for receiving audio data.
int channel = CreateVoEChannel();
const int channel = CreateVoEChannel();
if (channel == -1) {
return false;
}
if (!ConfigureRecvChannel(channel)) {
DeleteChannel(channel);
return false;
}
WebRtcAudioReceiveStream* stream = new WebRtcAudioReceiveStream(channel);
receive_channels_.insert(std::make_pair(ssrc, stream));
receive_stream_params_[ssrc] = sp;
AddAudioReceiveStream(ssrc);
LOG(LS_INFO) << "New audio stream " << ssrc
<< " registered to VoiceEngine channel #"
<< channel << ".";
return true;
}
bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
int send_channel = GetSendChannelId(receiver_reports_ssrc_);
if (send_channel != -1) {
// Associate receive channel with first send channel (so the receive channel
// can obtain RTT from the send channel)
engine()->voe()->base()->AssociateSendChannel(channel, send_channel);
LOG(LS_INFO) << "VoiceEngine channel #" << channel
<< " is associated with channel #" << send_channel << ".";
}
if (engine()->voe()->rtp()->SetLocalSSRC(channel,
receiver_reports_ssrc_) == -1) {
LOG_RTCERR1(SetLocalSSRC, channel);
return false;
}
// Turn off all supported codecs.
int ncodecs = engine()->voe()->codec()->NumOfCodecs();
const int ncodecs = engine()->voe()->codec()->NumOfCodecs();
for (int i = 0; i < ncodecs; ++i) {
webrtc::CodecInst voe_codec;
if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
@ -2236,6 +2222,7 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
if (engine()->voe()->codec()->SetRecPayloadType(
channel, voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
DeleteVoEChannel(channel);
return false;
}
}
@ -2249,19 +2236,29 @@ bool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
if (engine()->voe()->codec()->SetRecPayloadType(
channel, voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
DeleteVoEChannel(channel);
return false;
}
}
}
SetNack(channel, nack_enabled_);
// Set RTP header extension for the new channel.
if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) {
return false;
const int send_channel = GetSendChannelId(receiver_reports_ssrc_);
if (send_channel != -1) {
// Associate receive channel with first send channel (so the receive channel
// can obtain RTT from the send channel)
engine()->voe()->base()->AssociateSendChannel(channel, send_channel);
LOG(LS_INFO) << "VoiceEngine channel #" << channel
<< " is associated with channel #" << send_channel << ".";
}
recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream(
channel, ssrc, receiver_reports_ssrc_,
options_.combined_audio_video_bwe.value_or(false), sp.sync_label,
recv_rtp_extensions_, call_)));
SetNack(channel, nack_enabled_);
SetPlayout(channel, playout_);
return true;
}
@ -2269,28 +2266,26 @@ bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
auto it = receive_channels_.find(ssrc);
if (it == receive_channels_.end()) {
const auto it = recv_streams_.find(ssrc);
if (it == recv_streams_.end()) {
LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
<< " which doesn't exist.";
return false;
}
RemoveAudioReceiveStream(ssrc);
receive_stream_params_.erase(ssrc);
const int channel = it->second->channel();
delete it->second;
receive_channels_.erase(it);
// Deregister default channel, if that's the one being destroyed.
if (IsDefaultRecvStream(ssrc)) {
default_recv_ssrc_ = -1;
}
LOG(LS_INFO) << "Removing audio stream " << ssrc
const int channel = it->second->channel();
// Clean up and delete the receive stream+channel.
LOG(LS_INFO) << "Removing audio receive stream " << ssrc
<< " with VoiceEngine channel #" << channel << ".";
return DeleteChannel(channel);
delete it->second;
recv_streams_.erase(it);
return DeleteVoEChannel(channel);
}
bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc,
@ -2320,7 +2315,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams(
AudioInfo::StreamList* actives) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
actives->clear();
for (const auto& ch : receive_channels_) {
for (const auto& ch : recv_streams_) {
int level = GetOutputLevel(ch.second->channel());
if (level > 0) {
actives->push_back(std::make_pair(ch.first, level));
@ -2332,7 +2327,7 @@ bool WebRtcVoiceMediaChannel::GetActiveStreams(
int WebRtcVoiceMediaChannel::GetOutputLevel() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
int highest = 0;
for (const auto& ch : receive_channels_) {
for (const auto& ch : recv_streams_) {
highest = std::max(GetOutputLevel(ch.second->channel()), highest);
}
return highest;
@ -2647,7 +2642,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
// Get SSRC and stats for each receiver.
RTC_DCHECK(info->receivers.size() == 0);
for (const auto& stream : receive_streams_) {
for (const auto& stream : recv_streams_) {
webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
VoiceReceiverInfo rinfo;
rinfo.add_ssrc(stats.remote_ssrc);
@ -2689,8 +2684,8 @@ int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
const auto it = receive_channels_.find(ssrc);
if (it != receive_channels_.end()) {
const auto it = recv_streams_.find(ssrc);
if (it != recv_streams_.end()) {
return it->second->channel();
}
return -1;
@ -2763,59 +2758,6 @@ bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
return true;
}
bool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
int channel_id, const RtpHeaderExtension* extension) {
bool enable = false;
int id = 0;
std::string uri;
if (extension) {
enable = true;
id = extension->id;
uri = extension->uri;
}
if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) {
LOG_RTCERR4(*setter, uri, channel_id, enable, id);
return false;
}
return true;
}
void WebRtcVoiceMediaChannel::RecreateAudioReceiveStreams() {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
for (const auto& it : receive_channels_) {
RemoveAudioReceiveStream(it.first);
}
for (const auto& it : receive_channels_) {
AddAudioReceiveStream(it.first);
}
}
void WebRtcVoiceMediaChannel::AddAudioReceiveStream(uint32_t ssrc) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
WebRtcAudioReceiveStream* stream = receive_channels_[ssrc];
RTC_DCHECK(stream != nullptr);
RTC_DCHECK(receive_streams_.find(ssrc) == receive_streams_.end());
webrtc::AudioReceiveStream::Config config;
config.rtp.remote_ssrc = ssrc;
// Only add RTP extensions if we support combined A/V BWE.
config.rtp.extensions = recv_rtp_extensions_;
config.combined_audio_video_bwe =
options_.combined_audio_video_bwe.value_or(false);
config.voe_channel_id = stream->channel();
config.sync_group = receive_stream_params_[ssrc].sync_label;
webrtc::AudioReceiveStream* s = call_->CreateAudioReceiveStream(config);
receive_streams_.insert(std::make_pair(ssrc, s));
}
void WebRtcVoiceMediaChannel::RemoveAudioReceiveStream(uint32_t ssrc) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
auto stream_it = receive_streams_.find(ssrc);
if (stream_it != receive_streams_.end()) {
call_->DestroyAudioReceiveStream(stream_it->second);
receive_streams_.erase(stream_it);
}
}
bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal(
const std::vector<AudioCodec>& new_codecs) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
@ -2824,7 +2766,7 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal(
if (engine()->FindWebRtcCodec(codec, &voe_codec)) {
LOG(LS_INFO) << ToString(codec);
voe_codec.pltype = codec.id;
for (const auto& ch : receive_channels_) {
for (const auto& ch : recv_streams_) {
if (engine()->voe()->codec()->SetRecPayloadType(
ch.second->channel(), voe_codec) == -1) {
LOG_RTCERR2(SetRecPayloadType, ch.second->channel(),
@ -2839,7 +2781,6 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecsInternal(
}
return true;
}
} // namespace cricket
#endif // HAVE_WEBRTC_VOICE

View File

@ -248,8 +248,6 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
bool SetOptions(const AudioOptions& options);
bool SetMaxSendBandwidth(int bps);
bool SetRecvCodecs(const std::vector<AudioCodec>& codecs);
bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions);
bool SetLocalRenderer(uint32_t ssrc, AudioRenderer* renderer);
bool MuteStream(uint32_t ssrc, bool mute);
@ -260,35 +258,20 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
const std::vector<AudioCodec>& all_codecs,
webrtc::CodecInst* send_codec);
bool SetPlayout(int channel, bool playout);
typedef int (webrtc::VoERTP_RTCP::* ExtensionSetterFunction)(int, bool,
unsigned char);
void SetNack(int channel, bool nack_enabled);
bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec);
bool ChangePlayout(bool playout);
bool ChangeSend(SendFlags send);
bool ChangeSend(int channel, SendFlags send);
bool ConfigureRecvChannel(int channel);
int CreateVoEChannel();
bool DeleteChannel(int channel);
bool DeleteVoEChannel(int channel);
bool IsDefaultRecvStream(uint32_t ssrc) {
return default_recv_ssrc_ == static_cast<int64_t>(ssrc);
}
bool SetSendCodecs(int channel, const std::vector<AudioCodec>& codecs);
bool SetSendBitrateInternal(int bps);
bool SetHeaderExtension(ExtensionSetterFunction setter, int channel_id,
const RtpHeaderExtension* extension);
void RecreateAudioReceiveStreams();
void AddAudioReceiveStream(uint32_t ssrc);
void RemoveAudioReceiveStream(uint32_t ssrc);
bool SetRecvCodecsInternal(const std::vector<AudioCodec>& new_codecs);
bool SetChannelRecvRtpHeaderExtensions(
int channel_id,
const std::vector<RtpHeaderExtension>& extensions);
rtc::ThreadChecker worker_thread_checker_;
WebRtcVoiceEngine* const engine_ = nullptr;
@ -320,13 +303,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
std::vector<webrtc::RtpExtension> send_rtp_extensions_;
class WebRtcAudioReceiveStream;
std::map<uint32_t, WebRtcAudioReceiveStream*> receive_channels_;
std::map<uint32_t, webrtc::AudioReceiveStream*> receive_streams_;
std::map<uint32_t, StreamParams> receive_stream_params_;
// receive_channels_ can be read from WebRtc callback thread. Access from
// the WebRtc thread must be synchronized with edits on the worker thread.
// Reads on the worker thread are ok.
std::vector<RtpHeaderExtension> receive_extensions_;
std::map<uint32_t, WebRtcAudioReceiveStream*> recv_streams_;
std::vector<webrtc::RtpExtension> recv_rtp_extensions_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcVoiceMediaChannel);

View File

@ -144,6 +144,12 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
return send_stream->GetConfig();
}
const webrtc::AudioReceiveStream::Config& GetRecvStreamConfig(uint32_t ssrc) {
const auto* recv_stream = call_.GetAudioReceiveStream(ssrc);
EXPECT_TRUE(recv_stream);
return recv_stream->GetConfig();
}
void TestInsertDtmf(uint32_t ssrc, bool caller) {
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
channel_ = engine_.CreateChannel(&call_, cricket::AudioOptions());
@ -239,7 +245,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
EXPECT_EQ(ext, GetSendStreamConfig(kSsrc1).rtp.extensions[0].name);
EXPECT_EQ(id, GetSendStreamConfig(kSsrc1).rtp.extensions[0].id);
// Ensure extension is set properly on new channels.
// Ensure extension is set properly on new stream.
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc2)));
EXPECT_NE(call_.GetAudioSendStream(kSsrc1),
@ -258,42 +264,43 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
EXPECT_TRUE(SetupEngineWithRecvStream());
int channel_num = voe_.GetLastChannel();
// Ensure extensions are off by default.
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
cricket::AudioRecvParameters parameters;
// Ensure unknown extensions won't cause an error.
parameters.extensions.push_back(cricket::RtpHeaderExtension(
recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(
"urn:ietf:params:unknownextention", 1));
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
// Ensure extensions stay off with an empty list of headers.
parameters.extensions.clear();
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
recv_parameters_.extensions.clear();
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
// Ensure extension is set properly.
const int id = 2;
parameters.extensions.push_back(cricket::RtpHeaderExtension(ext, id));
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(channel_num, ext));
recv_parameters_.extensions.push_back(cricket::RtpHeaderExtension(ext, id));
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].name);
EXPECT_EQ(id, GetRecvStreamConfig(kSsrc1).rtp.extensions[0].id);
// Ensure extension is set properly on new channel.
// The first stream to occupy the default channel.
// Ensure extension is set properly on new stream.
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrc2)));
int new_channel_num = voe_.GetLastChannel();
EXPECT_NE(channel_num, new_channel_num);
EXPECT_EQ(id, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
EXPECT_NE(call_.GetAudioReceiveStream(kSsrc1),
call_.GetAudioReceiveStream(kSsrc2));
EXPECT_EQ(1u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size());
EXPECT_EQ(ext, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].name);
EXPECT_EQ(id, GetRecvStreamConfig(kSsrc2).rtp.extensions[0].id);
// Ensure all extensions go back off with an empty list.
parameters.extensions.clear();
EXPECT_TRUE(channel_->SetRecvParameters(parameters));
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(channel_num, ext));
EXPECT_EQ(-1, voe_.GetReceiveRtpExtensionId(new_channel_num, ext));
recv_parameters_.extensions.clear();
EXPECT_TRUE(channel_->SetRecvParameters(recv_parameters_));
EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc1).rtp.extensions.size());
EXPECT_EQ(0u, GetRecvStreamConfig(kSsrc2).rtp.extensions.size());
}
webrtc::AudioSendStream::Stats GetAudioSendStreamStats() const {
@ -2402,8 +2409,9 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrcWithMultipleStreams) {
EXPECT_TRUE(SetupEngineWithSendStream());
EXPECT_TRUE(call_.GetAudioSendStream(kSsrc1));
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
EXPECT_EQ(kSsrc1, voe_.GetLocalSSRC(voe_.GetLastChannel()));
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrc2)));
EXPECT_EQ(kSsrc1, GetRecvStreamConfig(kSsrc2).rtp.local_ssrc);
}
// Test that the local SSRC is the same on sending and receiving channels if the

View File

@ -73,19 +73,35 @@ AudioReceiveStream::AudioReceiveStream(
RTC_DCHECK(remote_bitrate_estimator_);
RTC_DCHECK(audio_state_.get());
RTC_DCHECK(rtp_header_parser_);
for (const auto& ext : config.rtp.extensions) {
const int channel_id = config.voe_channel_id;
ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
int error = rtp->SetLocalSSRC(channel_id, config.rtp.local_ssrc);
RTC_DCHECK_EQ(0, error);
for (const auto& extension : config.rtp.extensions) {
// One-byte-extension local identifiers are in the range 1-14 inclusive.
RTC_DCHECK_GE(ext.id, 1);
RTC_DCHECK_LE(ext.id, 14);
if (ext.name == RtpExtension::kAudioLevel) {
RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, ext.id));
} else if (ext.name == RtpExtension::kAbsSendTime) {
RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, ext.id));
} else if (ext.name == RtpExtension::kTransportSequenceNumber) {
RTC_CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber, ext.id));
RTC_DCHECK_GE(extension.id, 1);
RTC_DCHECK_LE(extension.id, 14);
if (extension.name == RtpExtension::kAudioLevel) {
error = rtp->SetReceiveAudioLevelIndicationStatus(channel_id, true,
extension.id);
RTC_DCHECK_EQ(0, error);
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, extension.id);
RTC_DCHECK(registered);
} else if (extension.name == RtpExtension::kAbsSendTime) {
error = rtp->SetReceiveAbsoluteSenderTimeStatus(channel_id, true,
extension.id);
RTC_DCHECK_EQ(0, error);
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, extension.id);
RTC_DCHECK(registered);
} else if (extension.name == RtpExtension::kTransportSequenceNumber) {
// TODO(holmer): Need to do something here or in DeliverRtp() to actually
// handle audio packets with this header extension.
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber, extension.id);
RTC_DCHECK(registered);
} else {
RTC_NOTREACHED() << "Unsupported RTP extension.";
}
@ -97,18 +113,61 @@ AudioReceiveStream::~AudioReceiveStream() {
LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString();
}
void AudioReceiveStream::Start() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::Stop() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::SignalNetworkState(NetworkState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
return false;
}
bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
size_t length,
const PacketTime& packet_time) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
RTPHeader header;
if (!rtp_header_parser_->Parse(packet, length, &header)) {
return false;
}
// Only forward if the parsed header has absolute sender time. RTP timestamps
// may have different rates for audio and video and shouldn't be mixed.
if (config_.combined_audio_video_bwe &&
header.extension.hasAbsoluteSendTime) {
int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
if (packet_time.timestamp >= 0)
arrival_time_ms = (packet_time.timestamp + 500) / 1000;
size_t payload_size = length - header.headerLength;
remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
header, false);
}
return true;
}
webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
webrtc::AudioReceiveStream::Stats stats;
stats.remote_ssrc = config_.rtp.remote_ssrc;
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
VoiceEngine* voice_engine = audio_state->voice_engine();
ScopedVoEInterface<VoECodec> codec(voice_engine);
ScopedVoEInterface<VoENetEqStats> neteq(voice_engine);
ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine);
ScopedVoEInterface<VoEVideoSync> sync(voice_engine);
ScopedVoEInterface<VoEVolumeControl> volume(voice_engine);
ScopedVoEInterface<VoECodec> codec(voice_engine());
ScopedVoEInterface<VoENetEqStats> neteq(voice_engine());
ScopedVoEInterface<VoERTP_RTCP> rtp(voice_engine());
ScopedVoEInterface<VoEVideoSync> sync(voice_engine());
ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
webrtc::CallStatistics call_stats = {0};
int error = rtp->GetRTCPStatistics(config_.voe_channel_id, call_stats);
@ -175,50 +234,12 @@ const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const {
return config_;
}
void AudioReceiveStream::Start() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::Stop() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::SignalNetworkState(NetworkState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
return false;
}
bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
size_t length,
const PacketTime& packet_time) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
RTPHeader header;
if (!rtp_header_parser_->Parse(packet, length, &header)) {
return false;
}
// Only forward if the parsed header has absolute sender time. RTP timestamps
// may have different rates for audio and video and shouldn't be mixed.
if (config_.combined_audio_video_bwe &&
header.extension.hasAbsoluteSendTime) {
int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
if (packet_time.timestamp >= 0)
arrival_time_ms = (packet_time.timestamp + 500) / 1000;
size_t payload_size = length - header.headerLength;
remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
header, false);
}
return true;
VoiceEngine* AudioReceiveStream::voice_engine() const {
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
VoiceEngine* voice_engine = audio_state->voice_engine();
RTC_DCHECK(voice_engine);
return voice_engine;
}
} // namespace internal
} // namespace webrtc

View File

@ -44,6 +44,8 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream {
const webrtc::AudioReceiveStream::Config& config() const;
private:
VoiceEngine* voice_engine() const;
rtc::ThreadChecker thread_checker_;
RemoteBitrateEstimator* const remote_bitrate_estimator_;
const webrtc::AudioReceiveStream::Config config_;

View File

@ -38,7 +38,8 @@ const int kChannelId = 2;
const uint32_t kRemoteSsrc = 1234;
const uint32_t kLocalSsrc = 5678;
const size_t kAbsoluteSendTimeLength = 4;
const int kAbsSendTimeId = 3;
const int kAbsSendTimeId = 2;
const int kAudioLevelId = 3;
const int kJitterBufferDelay = -7;
const int kPlayoutBufferDelay = 302;
const unsigned int kSpeechOutputLevel = 99;
@ -59,10 +60,23 @@ struct ConfigHelper {
AudioState::Config config;
config.voice_engine = &voice_engine_;
audio_state_ = AudioState::Create(config);
EXPECT_CALL(voice_engine_, SetLocalSSRC(kChannelId, kLocalSsrc))
.WillOnce(Return(0));
EXPECT_CALL(voice_engine_,
SetReceiveAbsoluteSenderTimeStatus(kChannelId, true, kAbsSendTimeId))
.WillOnce(Return(0));
EXPECT_CALL(voice_engine_,
SetReceiveAudioLevelIndicationStatus(kChannelId, true, kAudioLevelId))
.WillOnce(Return(0));
stream_config_.voe_channel_id = kChannelId;
stream_config_.rtp.local_ssrc = kLocalSsrc;
stream_config_.rtp.remote_ssrc = kRemoteSsrc;
}
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
}
MockRemoteBitrateEstimator* remote_bitrate_estimator() {
return &remote_bitrate_estimator_;
@ -144,7 +158,7 @@ TEST(AudioReceiveStreamTest, ConfigToString) {
config.combined_audio_video_bwe = true;
EXPECT_EQ(
"{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: "
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}]}, "
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 2}]}, "
"receive_transport: nullptr, rtcp_send_transport: nullptr, "
"voe_channel_id: 2, combined_audio_video_bwe: true}",
config.ToString());
@ -159,8 +173,6 @@ TEST(AudioReceiveStreamTest, ConstructDestruct) {
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) {
ConfigHelper helper;
helper.config().combined_audio_video_bwe = true;
helper.config().rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
internal::AudioReceiveStream recv_stream(
helper.remote_bitrate_estimator(), helper.config(), helper.audio_state());
uint8_t rtp_packet[30];