xref: /aosp_15_r20/external/openscreen/cast/streaming/environment.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "cast/streaming/environment.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <algorithm>
8*3f982cf4SFabien Sanglard #include <utility>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include "cast/streaming/rtp_defines.h"
11*3f982cf4SFabien Sanglard #include "platform/api/task_runner.h"
12*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard namespace openscreen {
15*3f982cf4SFabien Sanglard namespace cast {
16*3f982cf4SFabien Sanglard 
Environment(ClockNowFunctionPtr now_function,TaskRunner * task_runner,const IPEndpoint & local_endpoint)17*3f982cf4SFabien Sanglard Environment::Environment(ClockNowFunctionPtr now_function,
18*3f982cf4SFabien Sanglard                          TaskRunner* task_runner,
19*3f982cf4SFabien Sanglard                          const IPEndpoint& local_endpoint)
20*3f982cf4SFabien Sanglard     : now_function_(now_function), task_runner_(task_runner) {
21*3f982cf4SFabien Sanglard   OSP_DCHECK(now_function_);
22*3f982cf4SFabien Sanglard   OSP_DCHECK(task_runner_);
23*3f982cf4SFabien Sanglard   ErrorOr<std::unique_ptr<UdpSocket>> result =
24*3f982cf4SFabien Sanglard       UdpSocket::Create(task_runner_, this, local_endpoint);
25*3f982cf4SFabien Sanglard   if (result.is_error()) {
26*3f982cf4SFabien Sanglard     OSP_LOG_ERROR << "Unable to create a UDP socket bound to " << local_endpoint
27*3f982cf4SFabien Sanglard                   << ": " << result.error();
28*3f982cf4SFabien Sanglard     return;
29*3f982cf4SFabien Sanglard   }
30*3f982cf4SFabien Sanglard   const_cast<std::unique_ptr<UdpSocket>&>(socket_) = std::move(result.value());
31*3f982cf4SFabien Sanglard   OSP_DCHECK(socket_);
32*3f982cf4SFabien Sanglard   socket_->Bind();
33*3f982cf4SFabien Sanglard }
34*3f982cf4SFabien Sanglard 
35*3f982cf4SFabien Sanglard Environment::~Environment() = default;
36*3f982cf4SFabien Sanglard 
GetBoundLocalEndpoint() const37*3f982cf4SFabien Sanglard IPEndpoint Environment::GetBoundLocalEndpoint() const {
38*3f982cf4SFabien Sanglard   if (socket_) {
39*3f982cf4SFabien Sanglard     return socket_->GetLocalEndpoint();
40*3f982cf4SFabien Sanglard   }
41*3f982cf4SFabien Sanglard   return IPEndpoint{};
42*3f982cf4SFabien Sanglard }
43*3f982cf4SFabien Sanglard 
SetSocketSubscriber(SocketSubscriber * subscriber)44*3f982cf4SFabien Sanglard void Environment::SetSocketSubscriber(SocketSubscriber* subscriber) {
45*3f982cf4SFabien Sanglard   socket_subscriber_ = subscriber;
46*3f982cf4SFabien Sanglard }
47*3f982cf4SFabien Sanglard 
ConsumeIncomingPackets(PacketConsumer * packet_consumer)48*3f982cf4SFabien Sanglard void Environment::ConsumeIncomingPackets(PacketConsumer* packet_consumer) {
49*3f982cf4SFabien Sanglard   OSP_DCHECK(packet_consumer);
50*3f982cf4SFabien Sanglard   OSP_DCHECK(!packet_consumer_);
51*3f982cf4SFabien Sanglard   packet_consumer_ = packet_consumer;
52*3f982cf4SFabien Sanglard }
53*3f982cf4SFabien Sanglard 
DropIncomingPackets()54*3f982cf4SFabien Sanglard void Environment::DropIncomingPackets() {
55*3f982cf4SFabien Sanglard   packet_consumer_ = nullptr;
56*3f982cf4SFabien Sanglard }
57*3f982cf4SFabien Sanglard 
GetMaxPacketSize() const58*3f982cf4SFabien Sanglard int Environment::GetMaxPacketSize() const {
59*3f982cf4SFabien Sanglard   // Return hard-coded values for UDP over wired Ethernet (which is a smaller
60*3f982cf4SFabien Sanglard   // MTU than typical defaults for UDP over 802.11 wireless). Performance would
61*3f982cf4SFabien Sanglard   // be more-optimized if the network were probed for the actual value. See
62*3f982cf4SFabien Sanglard   // discussion in rtp_defines.h.
63*3f982cf4SFabien Sanglard   switch (remote_endpoint_.address.version()) {
64*3f982cf4SFabien Sanglard     case IPAddress::Version::kV4:
65*3f982cf4SFabien Sanglard       return kMaxRtpPacketSizeForIpv4UdpOnEthernet;
66*3f982cf4SFabien Sanglard     case IPAddress::Version::kV6:
67*3f982cf4SFabien Sanglard       return kMaxRtpPacketSizeForIpv6UdpOnEthernet;
68*3f982cf4SFabien Sanglard     default:
69*3f982cf4SFabien Sanglard       OSP_NOTREACHED();
70*3f982cf4SFabien Sanglard   }
71*3f982cf4SFabien Sanglard }
72*3f982cf4SFabien Sanglard 
SendPacket(absl::Span<const uint8_t> packet)73*3f982cf4SFabien Sanglard void Environment::SendPacket(absl::Span<const uint8_t> packet) {
74*3f982cf4SFabien Sanglard   OSP_DCHECK(remote_endpoint_.address);
75*3f982cf4SFabien Sanglard   OSP_DCHECK_NE(remote_endpoint_.port, 0);
76*3f982cf4SFabien Sanglard   if (socket_) {
77*3f982cf4SFabien Sanglard     socket_->SendMessage(packet.data(), packet.size(), remote_endpoint_);
78*3f982cf4SFabien Sanglard   }
79*3f982cf4SFabien Sanglard }
80*3f982cf4SFabien Sanglard 
81*3f982cf4SFabien Sanglard Environment::PacketConsumer::~PacketConsumer() = default;
82*3f982cf4SFabien Sanglard 
OnBound(UdpSocket * socket)83*3f982cf4SFabien Sanglard void Environment::OnBound(UdpSocket* socket) {
84*3f982cf4SFabien Sanglard   OSP_DCHECK(socket == socket_.get());
85*3f982cf4SFabien Sanglard   state_ = SocketState::kReady;
86*3f982cf4SFabien Sanglard 
87*3f982cf4SFabien Sanglard   if (socket_subscriber_) {
88*3f982cf4SFabien Sanglard     socket_subscriber_->OnSocketReady();
89*3f982cf4SFabien Sanglard   }
90*3f982cf4SFabien Sanglard }
91*3f982cf4SFabien Sanglard 
OnError(UdpSocket * socket,Error error)92*3f982cf4SFabien Sanglard void Environment::OnError(UdpSocket* socket, Error error) {
93*3f982cf4SFabien Sanglard   OSP_DCHECK(socket == socket_.get());
94*3f982cf4SFabien Sanglard   // Usually OnError() is only called for non-recoverable Errors. However,
95*3f982cf4SFabien Sanglard   // OnSendError() and OnRead() delegate to this method, to handle their hard
96*3f982cf4SFabien Sanglard   // error cases as well. So, return early here if |error| is recoverable.
97*3f982cf4SFabien Sanglard   if (error.ok() || error.code() == Error::Code::kAgain) {
98*3f982cf4SFabien Sanglard     return;
99*3f982cf4SFabien Sanglard   }
100*3f982cf4SFabien Sanglard 
101*3f982cf4SFabien Sanglard   state_ = SocketState::kInvalid;
102*3f982cf4SFabien Sanglard   if (socket_subscriber_) {
103*3f982cf4SFabien Sanglard     socket_subscriber_->OnSocketInvalid(error);
104*3f982cf4SFabien Sanglard   } else {
105*3f982cf4SFabien Sanglard     // Default behavior when there are no subscribers.
106*3f982cf4SFabien Sanglard     OSP_LOG_ERROR << "For UDP socket bound to " << socket_->GetLocalEndpoint()
107*3f982cf4SFabien Sanglard                   << ": " << error;
108*3f982cf4SFabien Sanglard   }
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard 
OnSendError(UdpSocket * socket,Error error)111*3f982cf4SFabien Sanglard void Environment::OnSendError(UdpSocket* socket, Error error) {
112*3f982cf4SFabien Sanglard   OnError(socket, error);
113*3f982cf4SFabien Sanglard }
114*3f982cf4SFabien Sanglard 
OnRead(UdpSocket * socket,ErrorOr<UdpPacket> packet_or_error)115*3f982cf4SFabien Sanglard void Environment::OnRead(UdpSocket* socket,
116*3f982cf4SFabien Sanglard                          ErrorOr<UdpPacket> packet_or_error) {
117*3f982cf4SFabien Sanglard   if (!packet_consumer_) {
118*3f982cf4SFabien Sanglard     return;
119*3f982cf4SFabien Sanglard   }
120*3f982cf4SFabien Sanglard 
121*3f982cf4SFabien Sanglard   if (packet_or_error.is_error()) {
122*3f982cf4SFabien Sanglard     OnError(socket, packet_or_error.error());
123*3f982cf4SFabien Sanglard     return;
124*3f982cf4SFabien Sanglard   }
125*3f982cf4SFabien Sanglard 
126*3f982cf4SFabien Sanglard   // Ideally, the arrival time would come from the operating system's network
127*3f982cf4SFabien Sanglard   // stack (e.g., by using the SO_TIMESTAMP sockopt on POSIX systems). However,
128*3f982cf4SFabien Sanglard   // there would still be the problem of mapping the timestamp to a value in
129*3f982cf4SFabien Sanglard   // terms of Clock::time_point. So, just sample the Clock here and call that
130*3f982cf4SFabien Sanglard   // the "arrival time." While this can add variance within the system, it
131*3f982cf4SFabien Sanglard   // should be minimal, assuming not too much time has elapsed between the
132*3f982cf4SFabien Sanglard   // actual packet receive event and the when this code here is executing.
133*3f982cf4SFabien Sanglard   const Clock::time_point arrival_time = now_function_();
134*3f982cf4SFabien Sanglard 
135*3f982cf4SFabien Sanglard   UdpPacket packet = std::move(packet_or_error.value());
136*3f982cf4SFabien Sanglard   packet_consumer_->OnReceivedPacket(
137*3f982cf4SFabien Sanglard       packet.source(), arrival_time,
138*3f982cf4SFabien Sanglard       std::move(static_cast<std::vector<uint8_t>&>(packet)));
139*3f982cf4SFabien Sanglard }
140*3f982cf4SFabien Sanglard 
141*3f982cf4SFabien Sanglard }  // namespace cast
142*3f982cf4SFabien Sanglard }  // namespace openscreen
143