// Copyright (C) 2026 half144 and PS5 React contributors // SPDX-License-Identifier: GPL-3.0-or-later // Additional attribution term: see LICENSE-ATTRIBUTION. // tools/test_passthrough.py: the IEC 61937 packer and the EDID audio parser, driven from Python. // pack ac3|eac3|dts writes the bursts as the sink receives them (little-endian) // edid prints the capabilities as JSON #include "audio_sink.hpp" #include "iec61937.hpp" #include #include #include #include #include #include namespace host { bool sink_edid(std::vector&) { return false; } } // namespace host namespace { std::vector read(const char* path) { std::ifstream in(path, std::ios::binary); return {std::istreambuf_iterator(in), std::istreambuf_iterator()}; } int pack(const char* format, const char* in, const char* out, std::size_t piece) { const iec61937::Codec codec = !std::strcmp(format, "eac3") ? iec61937::Codec::eac3 : !std::strcmp(format, "dts") ? iec61937::Codec::dts : iec61937::Codec::ac3; const std::vector stream = read(in); std::vector bytes; const auto consume = [&](const std::uint16_t* words, std::size_t frames, std::int64_t) { for (std::size_t i = 0; i < frames * 2; ++i) { bytes.push_back(static_cast(words[i] & 0xff)); bytes.push_back(static_cast(words[i] >> 8)); } }; static iec61937::Packer packer; // 64 KiB of buffers packer.reset(codec); for (std::size_t at = 0; at < stream.size(); at += piece) packer.feed(stream.data() + at, std::min(piece, stream.size() - at), static_cast(at), consume); packer.flush(consume); std::ofstream(out, std::ios::binary).write(reinterpret_cast(bytes.data()), static_cast(bytes.size())); return 0; } std::string numbers(const std::vector& values) { std::string out = "["; for (std::size_t i = 0; i < values.size(); ++i) out += (i ? "," : "") + std::to_string(values[i]); return out + "]"; } int edid(const char* path) { const std::vector data = read(path); const audio_sink::Capabilities caps = audio_sink::parse_edid(data.data(), data.size()); std::printf("{\"known\":%s,\"name\":\"%s\",\"ac3\":%s,\"eac3\":%s,\"dts\":%s,\"pcmChannels\":%d,\"formats\":[", caps.known ? "true" : "false", caps.name.c_str(), caps.ac3 ? "true" : "false", caps.eac3 ? "true" : "false", caps.dts ? "true" : "false", caps.pcm_channels); for (std::size_t i = 0; i < caps.formats.size(); ++i) { const audio_sink::Format& f = caps.formats[i]; std::printf("%s{\"codec\":\"%s\",\"channels\":%d,\"sampleRates\":%s,\"bitDepths\":%s,\"maxBitrate\":%d}", i ? "," : "", f.codec.c_str(), f.channels, numbers(f.rates).c_str(), numbers(f.bit_depths).c_str(), f.max_bitrate); } std::printf("]}\n"); return 0; } } // namespace int main(int argc, char** argv) { if (argc == 6 && !std::strcmp(argv[1], "pack")) return pack(argv[2], argv[3], argv[4], std::stoul(argv[5])); if (argc == 3 && !std::strcmp(argv[1], "edid")) return edid(argv[2]); std::fprintf(stderr, "usage: %s pack ac3|eac3|dts in out piece | edid file\n", argv[0]); return 2; }