| /* |
| * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * 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 "test/field_trial.h" |
| #include "test/gtest.h" |
| #include "test/peer_scenario/peer_scenario.h" |
| |
| namespace webrtc { |
| 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) { |
| PeerScenario s(*test_info_); |
| |
| auto* caller = s.CreateClient(PeerScenarioClient::Config()); |
| auto* callee = s.CreateClient(PeerScenarioClient::Config()); |
| |
| auto send_link = {s.net()->NodeBuilder().Build().node}; |
| auto ret_link = {s.net()->NodeBuilder().Build().node}; |
| |
| s.net()->CreateRoute(caller->endpoint(), send_link, callee->endpoint()); |
| s.net()->CreateRoute(callee->endpoint(), ret_link, caller->endpoint()); |
| |
| auto signaling = s.ConnectSignaling(caller, callee, send_link, ret_link); |
| caller->CreateVideo("VIDEO", PeerScenarioClient::VideoSendTrackConfig()); |
| rtc::Event offer_exchange_done; |
| signaling.NegotiateSdp( |
| [](SessionDescriptionInterface* offer) { |
| for (auto& cont : offer->description()->contents()) { |
| cont.media_description()->set_remote_estimate(true); |
| } |
| }, |
| [&](const SessionDescriptionInterface& answer) { |
| for (auto& cont : answer.description()->contents()) { |
| EXPECT_TRUE(cont.media_description()->remote_estimate()); |
| } |
| offer_exchange_done.Set(); |
| }); |
| RTC_CHECK(s.WaitAndProcess(&offer_exchange_done)); |
| } |
| |
| TEST(RemoteEstimateEndToEnd, AudioUsesAbsSendTimeExtension) { |
| ScopedFieldTrials trials("WebRTC-KeepAbsSendTimeExtension/Enabled/"); |
| // Defined before PeerScenario so it gets destructed after, to avoid use after free. |
| rtc::Event received_abs_send_time; |
| PeerScenario s(*test_info_); |
| |
| 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(); |
| }); |
| RTC_CHECK(s.WaitAndProcess(&offer_exchange_done)); |
| send_node->router()->SetWatcher( |
| [extension_map, &received_abs_send_time](const EmulatedIpPacket& packet) { |
| // The dummy packets used by the fake signaling are filled with 0. We |
| // want to ignore those and we can do that on the basis that the first |
| // byte of RTP packets are guaranteed to not be 0. |
| // TODO(srte): Find a more elegant way to check for RTP traffic. |
| if (packet.size() > 1 && packet.cdata()[0] != 0) { |
| auto extensions = GetRtpPacketExtensions(packet.data, extension_map); |
| if (extensions) { |
| EXPECT_TRUE(extensions->hasAbsoluteSendTime); |
| received_abs_send_time.Set(); |
| } |
| } |
| }); |
| RTC_CHECK(s.WaitAndProcess(&received_abs_send_time)); |
| } |
| } // namespace test |
| } // namespace webrtc |