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:
parent
6834fa10f1
commit
7add058439
@ -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]));
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user