Implement Cast Streaming mirroring, DLNA casting, daemon+GUI, and breadd integration
Some checks failed
dev release / build (push) Failing after 12s

Builds out the full v1 scope: a vendored+patched openscreen subset for
low-latency Cast Streaming (Mirroring receiver 0F5096E8) alongside the
existing Cast V2/HLS and new DLNA/AVTransport casting paths, breadcastd's
Idle/Casting state machine with a private IPC socket, the breadcast GTK4
popup as a thin IPC client, and bread.cast.*/bread.command.cast.* breadd
integration (device discovery, start/stop, mirroring lifecycle events).
Also adds bakery/systemd/Forgejo CI packaging.

Validated end-to-end against a real Chromecast/Google TV: negotiated
Cast Streaming session, live pipeline playback, and daemon+GUI click-to-cast/
stop through the actual popup.
This commit is contained in:
Breadway 2026-08-03 09:07:21 +08:00
parent 887c29002f
commit 8c745d18e0
283 changed files with 36788 additions and 0 deletions

View file

@ -0,0 +1,115 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cast/streaming/impl/statistics_common.h"
#include "util/osp_logging.h"
namespace openscreen::cast {
// static
StatisticsEvent::Type StatisticsEvent::FromWireType(WireType wire_type) {
switch (wire_type) {
case WireType::kAudioAckSent:
case WireType::kVideoAckSent:
case WireType::kUnifiedAckSent:
return Type::kFrameAckSent;
case WireType::kAudioPlayoutDelay:
case WireType::kVideoRenderDelay:
case WireType::kUnifiedRenderDelay:
return Type::kFramePlayedOut;
case WireType::kAudioFrameDecoded:
case WireType::kVideoFrameDecoded:
case WireType::kUnifiedFrameDecoded:
return Type::kFrameDecoded;
case WireType::kAudioPacketReceived:
case WireType::kVideoPacketReceived:
case WireType::kUnifiedPacketReceived:
return Type::kPacketReceived;
default:
OSP_VLOG << "Unexpected RTCP log message received: "
<< static_cast<int>(wire_type);
return Type::kUnknown;
}
}
// static
StatisticsEvent::WireType StatisticsEvent::ToWireType(Type type) {
switch (type) {
case Type::kUnknown:
return WireType::kUnknown;
case Type::kFrameAckSent:
return WireType::kUnifiedAckSent;
case Type::kFramePlayedOut:
return WireType::kUnifiedRenderDelay;
case Type::kFrameDecoded:
return WireType::kUnifiedFrameDecoded;
case Type::kPacketReceived:
return WireType::kUnifiedPacketReceived;
default:
OSP_VLOG << "Unknown RTCP log message event type: "
<< static_cast<int>(type);
return WireType::kUnknown;
}
}
// static
StatisticsEvent::MediaType StatisticsEvent::ToMediaType(StreamType type) {
switch (type) {
case StreamType::kUnknown:
return MediaType::kUnknown;
case StreamType::kAudio:
return MediaType::kAudio;
case StreamType::kVideo:
return MediaType::kVideo;
}
OSP_NOTREACHED();
}
StatisticsEvent::StatisticsEvent(const StatisticsEvent& other) = default;
StatisticsEvent::StatisticsEvent(StatisticsEvent&& other) noexcept = default;
StatisticsEvent& StatisticsEvent::operator=(const StatisticsEvent& other) =
default;
StatisticsEvent& StatisticsEvent::operator=(StatisticsEvent&& other) = default;
bool StatisticsEvent::operator==(const StatisticsEvent& other) const {
return frame_id == other.frame_id && type == other.type &&
media_type == other.media_type &&
rtp_timestamp == other.rtp_timestamp && size == other.size &&
timestamp == other.timestamp &&
received_timestamp == other.received_timestamp;
}
FrameEvent::FrameEvent(const FrameEvent& other) = default;
FrameEvent::FrameEvent(FrameEvent&& other) noexcept = default;
FrameEvent& FrameEvent::operator=(const FrameEvent& other) = default;
FrameEvent& FrameEvent::operator=(FrameEvent&& other) = default;
bool FrameEvent::operator==(const FrameEvent& other) const {
return StatisticsEvent::operator==(other) && width == other.width &&
height == other.height && delay_delta == other.delay_delta &&
key_frame == other.key_frame && target_bitrate == other.target_bitrate;
}
PacketEvent::PacketEvent(const PacketEvent& other) = default;
PacketEvent::PacketEvent(PacketEvent&& other) noexcept = default;
PacketEvent& PacketEvent::operator=(const PacketEvent& other) = default;
PacketEvent& PacketEvent::operator=(PacketEvent&& other) = default;
bool PacketEvent::operator==(const PacketEvent& other) const {
return StatisticsEvent::operator==(other) && packet_id == other.packet_id &&
max_packet_id == other.max_packet_id;
}
} // namespace openscreen::cast