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