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:

committed by
Commit Bot

parent
09ba21967c
commit
71c6b565ac
@ -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 &&
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user