Allow sending abs-send-time for audio streams.

Bug: webrtc:10742
Change-Id: I088c8221e04e84152cfce925051bf6bc23d5fe68
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/149061
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28861}
This commit is contained in:
Sebastian Jansson
2019-08-14 11:31:02 +02:00
committed by Commit Bot
parent 09ba21967c
commit 71c6b565ac
8 changed files with 98 additions and 2 deletions

View File

@ -207,6 +207,8 @@ AudioSendStream::ExtensionIds AudioSendStream::FindExtensionIds(
for (const auto& extension : extensions) { for (const auto& extension : extensions) {
if (extension.uri == RtpExtension::kAudioLevelUri) { if (extension.uri == RtpExtension::kAudioLevelUri) {
ids.audio_level = extension.id; ids.audio_level = extension.id;
} else if (extension.uri == RtpExtension::kAbsSendTimeUri) {
ids.abs_send_time = extension.id;
} else if (extension.uri == RtpExtension::kTransportSequenceNumberUri) { } else if (extension.uri == RtpExtension::kTransportSequenceNumberUri) {
ids.transport_sequence_number = extension.id; ids.transport_sequence_number = extension.id;
} else if (extension.uri == RtpExtension::kMidUri) { } else if (extension.uri == RtpExtension::kMidUri) {
@ -273,6 +275,16 @@ void AudioSendStream::ConfigureStream(
channel_send->SetSendAudioLevelIndicationStatus(new_ids.audio_level != 0, channel_send->SetSendAudioLevelIndicationStatus(new_ids.audio_level != 0,
new_ids.audio_level); new_ids.audio_level);
} }
if (first_time || new_ids.abs_send_time != old_ids.abs_send_time) {
channel_send->GetRtpRtcp()->DeregisterSendRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime);
if (new_ids.abs_send_time) {
channel_send->GetRtpRtcp()->RegisterSendRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, new_ids.abs_send_time);
}
}
bool transport_seq_num_id_changed = bool transport_seq_num_id_changed =
new_ids.transport_sequence_number != old_ids.transport_sequence_number; new_ids.transport_sequence_number != old_ids.transport_sequence_number;
if (first_time || (transport_seq_num_id_changed && if (first_time || (transport_seq_num_id_changed &&

View File

@ -183,6 +183,7 @@ class AudioSendStream final : public webrtc::AudioSendStream,
// So it should be safe to use 0 here to indicate "not configured". // So it should be safe to use 0 here to indicate "not configured".
struct ExtensionIds { struct ExtensionIds {
int audio_level = 0; int audio_level = 0;
int abs_send_time = 0;
int transport_sequence_number = 0; int transport_sequence_number = 0;
int mid = 0; int mid = 0;
int rid = 0; int rid = 0;

View File

@ -516,6 +516,8 @@ RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
int id = 1; int id = 1;
capabilities.header_extensions.push_back( capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kAudioLevelUri, id++)); webrtc::RtpExtension(webrtc::RtpExtension::kAudioLevelUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kAbsSendTimeUri, id++));
capabilities.header_extensions.push_back(webrtc::RtpExtension( capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kTransportSequenceNumberUri, id++)); webrtc::RtpExtension::kTransportSequenceNumberUri, id++));
return capabilities; return capabilities;

View File

@ -102,6 +102,9 @@ NetworkRouterNode::NetworkRouterNode(rtc::TaskQueue* task_queue)
void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) { void NetworkRouterNode::OnPacketReceived(EmulatedIpPacket packet) {
RTC_DCHECK_RUN_ON(task_queue_); RTC_DCHECK_RUN_ON(task_queue_);
if (watcher_) {
watcher_(packet);
}
auto receiver_it = routing_.find(packet.to.ipaddr()); auto receiver_it = routing_.find(packet.to.ipaddr());
if (receiver_it == routing_.end()) { if (receiver_it == routing_.end()) {
return; return;
@ -128,6 +131,14 @@ void NetworkRouterNode::RemoveReceiver(rtc::IPAddress dest_ip) {
routing_.erase(dest_ip); routing_.erase(dest_ip);
} }
void NetworkRouterNode::SetWatcher(
std::function<void(const EmulatedIpPacket&)> watcher) {
task_queue_->PostTask([=] {
RTC_DCHECK_RUN_ON(task_queue_);
watcher_ = watcher;
});
}
EmulatedNetworkNode::EmulatedNetworkNode( EmulatedNetworkNode::EmulatedNetworkNode(
Clock* clock, Clock* clock,
rtc::TaskQueue* task_queue, rtc::TaskQueue* task_queue,

View File

@ -102,11 +102,14 @@ class NetworkRouterNode : public EmulatedNetworkReceiverInterface {
void SetReceiver(rtc::IPAddress dest_ip, void SetReceiver(rtc::IPAddress dest_ip,
EmulatedNetworkReceiverInterface* receiver); EmulatedNetworkReceiverInterface* receiver);
void RemoveReceiver(rtc::IPAddress dest_ip); void RemoveReceiver(rtc::IPAddress dest_ip);
void SetWatcher(std::function<void(const EmulatedIpPacket&)> watcher);
private: private:
rtc::TaskQueue* const task_queue_; rtc::TaskQueue* const task_queue_;
std::map<rtc::IPAddress, EmulatedNetworkReceiverInterface*> routing_ std::map<rtc::IPAddress, EmulatedNetworkReceiverInterface*> routing_
RTC_GUARDED_BY(task_queue_); RTC_GUARDED_BY(task_queue_);
std::function<void(const EmulatedIpPacket&)> watcher_
RTC_GUARDED_BY(task_queue_);
}; };
// Represents node in the emulated network. Nodes can be connected with each // Represents node in the emulated network. Nodes can be connected with each

View File

@ -241,7 +241,7 @@ void PeerScenarioClient::CreateAndSetSdp(
SdpCreateObserver([=](SessionDescriptionInterface* offer) { SdpCreateObserver([=](SessionDescriptionInterface* offer) {
std::string sdp_offer; std::string sdp_offer;
offer->ToString(&sdp_offer); offer->ToString(&sdp_offer);
printf("%s\n", sdp_offer.c_str()); RTC_LOG(LS_INFO) << sdp_offer;
peer_connection_->SetLocalDescription( peer_connection_->SetLocalDescription(
SdpSetObserver([sdp_offer, offer_handler]() { SdpSetObserver([sdp_offer, offer_handler]() {
offer_handler(std::move(sdp_offer)); offer_handler(std::move(sdp_offer));
@ -261,7 +261,7 @@ void PeerScenarioClient::SetSdpOfferAndGetAnswer(
SdpCreateObserver([=](SessionDescriptionInterface* answer) { SdpCreateObserver([=](SessionDescriptionInterface* answer) {
std::string sdp_answer; std::string sdp_answer;
answer->ToString(&sdp_answer); answer->ToString(&sdp_answer);
printf("%s\n", sdp_answer.c_str()); RTC_LOG(LS_INFO) << sdp_answer;
peer_connection_->SetLocalDescription( peer_connection_->SetLocalDescription(
SdpSetObserver([answer_handler, sdp_answer]() { SdpSetObserver([answer_handler, sdp_answer]() {
answer_handler(sdp_answer); answer_handler(sdp_answer);

View File

@ -17,7 +17,9 @@ if (rtc_include_tests) {
] ]
deps = [ deps = [
"..:peer_scenario", "..:peer_scenario",
"../../:field_trial",
"../../:test_support", "../../:test_support",
"../../../modules/rtp_rtcp:rtp_rtcp",
"../../../pc:rtc_pc_base", "../../../pc:rtc_pc_base",
] ]
} }

View File

@ -8,12 +8,37 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "modules/rtp_rtcp/source/rtp_utility.h"
#include "pc/media_session.h"
#include "pc/session_description.h" #include "pc/session_description.h"
#include "test/field_trial.h"
#include "test/gtest.h" #include "test/gtest.h"
#include "test/peer_scenario/peer_scenario.h" #include "test/peer_scenario/peer_scenario.h"
namespace webrtc { namespace webrtc {
namespace test { namespace test {
namespace {
RtpHeaderExtensionMap AudioExtensions(
const SessionDescriptionInterface& session) {
auto* audio_desc =
cricket::GetFirstAudioContentDescription(session.description());
return RtpHeaderExtensionMap(audio_desc->rtp_header_extensions());
}
absl::optional<RTPHeaderExtension> GetRtpPacketExtensions(
const rtc::ArrayView<const uint8_t> packet,
const RtpHeaderExtensionMap& extension_map) {
RtpUtility::RtpHeaderParser rtp_parser(packet.data(), packet.size());
if (!rtp_parser.RTCP()) {
RTPHeader header;
if (rtp_parser.Parse(&header, &extension_map, true)) {
return header.extension;
}
}
return absl::nullopt;
}
} // namespace
TEST(RemoteEstimateEndToEnd, OfferedCapabilityIsInAnswer) { TEST(RemoteEstimateEndToEnd, OfferedCapabilityIsInAnswer) {
PeerScenario s; PeerScenario s;
@ -45,5 +70,45 @@ TEST(RemoteEstimateEndToEnd, OfferedCapabilityIsInAnswer) {
EXPECT_TRUE(s.WaitAndProcess(&offer_exchange_done)); EXPECT_TRUE(s.WaitAndProcess(&offer_exchange_done));
} }
TEST(RemoteEstimateEndToEnd, AudioUsesAbsSendTimeExtension) {
ScopedFieldTrials trials("WebRTC-KeepAbsSendTimeExtension/Enabled/");
PeerScenario s;
auto* caller = s.CreateClient(PeerScenarioClient::Config());
auto* callee = s.CreateClient(PeerScenarioClient::Config());
auto send_node = s.net()->NodeBuilder().Build().node;
auto ret_node = s.net()->NodeBuilder().Build().node;
s.net()->CreateRoute(caller->endpoint(), {send_node}, callee->endpoint());
s.net()->CreateRoute(callee->endpoint(), {ret_node}, caller->endpoint());
auto signaling = s.ConnectSignaling(caller, callee, {send_node}, {ret_node});
caller->CreateAudio("AUDIO", cricket::AudioOptions());
signaling.StartIceSignaling();
RtpHeaderExtensionMap extension_map;
rtc::Event offer_exchange_done;
signaling.NegotiateSdp(
[&extension_map](SessionDescriptionInterface* offer) {
extension_map = AudioExtensions(*offer);
EXPECT_TRUE(extension_map.IsRegistered(kRtpExtensionAbsoluteSendTime));
},
[&](const SessionDescriptionInterface& answer) {
EXPECT_TRUE(AudioExtensions(answer).IsRegistered(
kRtpExtensionAbsoluteSendTime));
offer_exchange_done.Set();
});
EXPECT_TRUE(s.WaitAndProcess(&offer_exchange_done));
rtc::Event received_abs_send_time;
send_node->router()->SetWatcher(
[extension_map, &received_abs_send_time](const EmulatedIpPacket& packet) {
auto extensions = GetRtpPacketExtensions(packet.data, extension_map);
if (extensions) {
EXPECT_TRUE(extensions->hasAbsoluteSendTime);
received_abs_send_time.Set();
}
});
EXPECT_TRUE(s.WaitAndProcess(&received_abs_send_time));
}
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc