1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/streaming/receiver_packet_router.h"
6
7 #include <algorithm>
8
9 #include "cast/streaming/packet_util.h"
10 #include "cast/streaming/receiver.h"
11 #include "util/osp_logging.h"
12 #include "util/stringprintf.h"
13
14 namespace openscreen {
15 namespace cast {
16
ReceiverPacketRouter(Environment * environment)17 ReceiverPacketRouter::ReceiverPacketRouter(Environment* environment)
18 : environment_(environment) {
19 OSP_DCHECK(environment_);
20 }
21
~ReceiverPacketRouter()22 ReceiverPacketRouter::~ReceiverPacketRouter() {
23 OSP_DCHECK(receivers_.empty());
24 }
25
OnReceiverCreated(Ssrc sender_ssrc,Receiver * receiver)26 void ReceiverPacketRouter::OnReceiverCreated(Ssrc sender_ssrc,
27 Receiver* receiver) {
28 OSP_DCHECK(receivers_.find(sender_ssrc) == receivers_.end());
29 receivers_.emplace_back(sender_ssrc, receiver);
30
31 // If there were no Receiver instances before, resume receiving packets for
32 // dispatch. Reset/Clear the remote endpoint, in preparation for later setting
33 // it to the source of the first packet received.
34 if (receivers_.size() == 1) {
35 environment_->set_remote_endpoint(IPEndpoint{});
36 environment_->ConsumeIncomingPackets(this);
37 }
38 }
39
OnReceiverDestroyed(Ssrc sender_ssrc)40 void ReceiverPacketRouter::OnReceiverDestroyed(Ssrc sender_ssrc) {
41 receivers_.erase_key(sender_ssrc);
42 // If there are no longer any Receivers, suspend receiving packets.
43 if (receivers_.empty()) {
44 environment_->DropIncomingPackets();
45 }
46 }
47
SendRtcpPacket(absl::Span<const uint8_t> packet)48 void ReceiverPacketRouter::SendRtcpPacket(absl::Span<const uint8_t> packet) {
49 OSP_DCHECK(InspectPacketForRouting(packet).first == ApparentPacketType::RTCP);
50
51 // Do not proceed until the remote endpoint is known. See OnReceivedPacket().
52 if (environment_->remote_endpoint().port == 0) {
53 return;
54 }
55
56 environment_->SendPacket(packet);
57 }
58
OnReceivedPacket(const IPEndpoint & source,Clock::time_point arrival_time,std::vector<uint8_t> packet)59 void ReceiverPacketRouter::OnReceivedPacket(const IPEndpoint& source,
60 Clock::time_point arrival_time,
61 std::vector<uint8_t> packet) {
62 OSP_DCHECK_NE(source.port, uint16_t{0});
63
64 // If the sender endpoint is known, ignore any packet that did not come from
65 // that same endpoint.
66 if (environment_->remote_endpoint().port != 0) {
67 if (source != environment_->remote_endpoint()) {
68 return;
69 }
70 }
71
72 const std::pair<ApparentPacketType, Ssrc> seems_like =
73 InspectPacketForRouting(packet);
74 if (seems_like.first == ApparentPacketType::UNKNOWN) {
75 constexpr int kMaxPartiaHexDumpSize = 96;
76 OSP_LOG_WARN << "UNKNOWN packet of " << packet.size()
77 << " bytes. Partial hex dump: "
78 << HexEncode(absl::Span<const uint8_t>(packet).subspan(
79 0, kMaxPartiaHexDumpSize));
80 return;
81 }
82 auto it = receivers_.find(seems_like.second);
83 if (it == receivers_.end()) {
84 return;
85 }
86 // At this point, a valid packet has been matched with a receiver. Lock-in
87 // the remote endpoint as the |source| of this |packet| so that only packets
88 // from the same source are permitted from here onwards.
89 if (environment_->remote_endpoint().port == 0) {
90 environment_->set_remote_endpoint(source);
91 }
92
93 if (seems_like.first == ApparentPacketType::RTP) {
94 it->second->OnReceivedRtpPacket(arrival_time, std::move(packet));
95 } else if (seems_like.first == ApparentPacketType::RTCP) {
96 it->second->OnReceivedRtcpPacket(arrival_time, std::move(packet));
97 }
98 }
99
100 } // namespace cast
101 } // namespace openscreen
102