blob: 0458a921f1b299922ba7c1a83df3af254b246258 [file] [log] [blame] [edit]
// Copyright 2024 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.
#ifndef QUICHE_QUIC_MOQT_MOQT_PROBE_MANAGER_H_
#define QUICHE_QUIC_MOQT_MOQT_PROBE_MANAGER_H_
#include <cstdint>
#include <memory>
#include <optional>
#include "quiche/quic/core/quic_alarm.h"
#include "quiche/quic/core/quic_alarm_factory.h"
#include "quiche/quic/core/quic_clock.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/common/quiche_callbacks.h"
#include "quiche/web_transport/web_transport.h"
namespace moqt {
// ID of a probe.
using ProbeId = uint64_t;
// Potential outcomes of a proge.
enum class ProbeStatus : uint8_t {
// Probe has finished successfully.
kSuccess,
// Probe has timed out.
kTimeout,
// Probe has been aborted, via a STOP_SENDING or for some other reason.
kAborted,
};
// Represents the results of a probe.
struct ProbeResult {
ProbeId id;
ProbeStatus status;
// The number of bytes requested on the probe.
quic::QuicByteCount probe_size;
// Time elapsed between the time the probe was requested and now.
quic::QuicTimeDelta time_elapsed;
};
// Interface used to mock out MoqtProbeManager.
class MoqtProbeManagerInterface {
public:
using Callback = quiche::SingleUseCallback<void(const ProbeResult& result)>;
virtual ~MoqtProbeManagerInterface() = default;
// Starts the probe. Returns the ID of the probe, or nullopt if the probe
// cannot be started. Will fail if a probe is already pending.
virtual std::optional<ProbeId> StartProbe(quic::QuicByteCount probe_size,
quic::QuicTimeDelta timeout,
Callback callback) = 0;
// Cancels the currently pending probe.
virtual std::optional<ProbeId> StopProbe() = 0;
};
namespace test {
class MoqtProbeManagerPeer;
}
// MoqtProbeManager keeps track of the pending bandwidth probe, including
// ensuring there is only one probe pending, and handling the timeout.
class MoqtProbeManager : public MoqtProbeManagerInterface {
public:
explicit MoqtProbeManager(webtransport::Session* session,
const quic::QuicClock* clock,
quic::QuicAlarmFactory& alarm_factory)
: session_(session),
clock_(clock),
timeout_alarm_(alarm_factory.CreateAlarm(new AlarmDelegate(this))) {}
// MoqtProbeManagerInterface implementation.
std::optional<ProbeId> StartProbe(quic::QuicByteCount probe_size,
quic::QuicTimeDelta timeout,
Callback callback) override;
std::optional<ProbeId> StopProbe() override;
private:
friend class ::moqt::test::MoqtProbeManagerPeer;
struct PendingProbe {
ProbeId id;
quic::QuicTime start;
quic::QuicTime deadline;
quic::QuicByteCount probe_size;
webtransport::StreamId stream_id;
Callback callback;
};
class ProbeStreamVisitor : public webtransport::StreamVisitor {
public:
ProbeStreamVisitor(MoqtProbeManager* manager, webtransport::Stream* stream,
ProbeId probe_id, quic::QuicByteCount probe_size)
: manager_(manager),
stream_(stream),
probe_id_(probe_id),
data_remaining_(probe_size) {}
void OnCanRead() override {}
void OnCanWrite() override;
void OnResetStreamReceived(webtransport::StreamErrorCode error) override {}
void OnStopSendingReceived(webtransport::StreamErrorCode error) override;
void OnWriteSideInDataRecvdState() override;
private:
// Ensures the stream is associated with the currently active probe.
bool ValidateProbe() {
if (!manager_->probe_.has_value() || manager_->probe_->id != probe_id_) {
// TODO: figure out the error code.
stream_->ResetWithUserCode(0);
return false;
}
return true;
}
MoqtProbeManager* manager_;
webtransport::Stream* stream_;
ProbeId probe_id_;
bool header_sent_ = false;
quic::QuicByteCount data_remaining_;
};
class AlarmDelegate : public quic::QuicAlarm::DelegateWithoutContext {
public:
explicit AlarmDelegate(MoqtProbeManager* manager) : manager_(manager) {}
void OnAlarm() override { manager_->OnAlarm(); }
private:
MoqtProbeManager* manager_;
};
void RescheduleAlarm();
void OnAlarm();
void ClosePendingProbe(ProbeStatus status);
std::optional<PendingProbe> probe_;
webtransport::Session* session_;
const quic::QuicClock* clock_;
std::unique_ptr<quic::QuicAlarm> timeout_alarm_;
ProbeId next_probe_id_ = 0;
};
} // namespace moqt
#endif // QUICHE_QUIC_MOQT_MOQT_PROBE_MANAGER_H_