// Copyright (C) 2026 half144 and PS5 React contributors // SPDX-License-Identifier: GPL-3.0-or-later // Additional attribution term: see LICENSE-ATTRIBUTION. // The bitstream (passthrough) output slot video players route their bursts to, and // audioOutput.capabilities(): what the connected sink takes. #include "host_api.hpp" #include "audio_sink.hpp" #include "burst_ring.hpp" #include "iec61937.hpp" #include "video_audio.hpp" #include #include #include #include namespace { std::mutex bitstream_mutex; // open and close, from players' audio threads const void* bitstream_owner = nullptr; bool bitstream_open = false; iec61937::Codec bitstream_codec = iec61937::Codec::ac3; std::atomic bitstream_ring{nullptr}; std::atomic bitstream_muted{false}; // On the output's thread, a grain at a time. Muted, the ring is still read, so the clock keeps going. void fill(std::uint16_t* words, std::size_t frames) { std::size_t read = 0; if (BurstRing* ring = bitstream_ring.load(std::memory_order_acquire)) read = ring->read(words, frames); if (bitstream_muted.load(std::memory_order_relaxed)) read = 0; std::memset(words + read * 2, 0, (frames - read) * 2 * sizeof *words); } JSValue capabilities(JSContext* ctx, JSValueConst, int, JSValueConst*) { const audio_sink::Capabilities caps = audio_sink::current(); const auto numbers = [&](const std::vector& values) { JSValue out = JS_NewArray(ctx); for (std::uint32_t i = 0; i < values.size(); ++i) JS_SetPropertyUint32(ctx, out, i, JS_NewInt32(ctx, values[i])); return out; }; JSValue out = JS_NewObject(ctx); JS_SetPropertyStr(ctx, out, "known", JS_NewBool(ctx, caps.known)); JS_SetPropertyStr(ctx, out, "name", JS_NewString(ctx, caps.name.c_str())); JSValue formats = JS_NewArray(ctx); for (std::uint32_t i = 0; i < caps.formats.size(); ++i) { const audio_sink::Format& format = caps.formats[i]; JSValue item = JS_NewObject(ctx); JS_SetPropertyStr(ctx, item, "codec", JS_NewString(ctx, format.codec.c_str())); JS_SetPropertyStr(ctx, item, "channels", JS_NewInt32(ctx, format.channels)); JS_SetPropertyStr(ctx, item, "sampleRates", numbers(format.rates)); if (!format.bit_depths.empty()) JS_SetPropertyStr(ctx, item, "bitDepths", numbers(format.bit_depths)); if (format.max_bitrate) JS_SetPropertyStr(ctx, item, "maxBitrate", JS_NewInt32(ctx, format.max_bitrate)); JS_SetPropertyUint32(ctx, formats, i, item); } JS_SetPropertyStr(ctx, out, "formats", formats); // What a