/**
 * @file DirettaSync.cpp
 * @brief Unified Diretta sync implementation
 *
 * Based on MPD Diretta Output Plugin v0.4.0
 * Preserves DSD planar handling from original UPnP renderer
 */

#include "DirettaSync.h"
#include <stdexcept>
#include <iomanip>
#include <pthread.h>
#include <sched.h>

namespace {

// G1: Interruptible wait helper for format transitions
// Uses condition variable instead of sleep_for to allow shutdown interruption
// Returns true if wait completed, false if interrupted by wakeup signal
bool interruptibleWait(std::mutex& mutex, std::condition_variable& cv,
                       std::atomic<bool>& wakeupFlag, int timeoutMs) {
    std::unique_lock<std::mutex> lock(mutex);
    bool interrupted = cv.wait_for(lock, std::chrono::milliseconds(timeoutMs),
                                   [&wakeupFlag]() { return wakeupFlag.load(std::memory_order_acquire); });
    if (interrupted) {
        wakeupFlag.store(false, std::memory_order_release);  // Reset for next use
    }
    return !interrupted;  // Return true if timeout (normal), false if interrupted
}

// F1: Worker thread priority elevation for reduced jitter
// Sets SCHED_FIFO real-time priority (requires root on Linux)
// Returns true on success, false on failure (logs warning but continues)
bool setRealtimePriority(int priority = 50) {
    struct sched_param param;
    param.sched_priority = priority;

    int ret = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
    if (ret != 0) {
        // Not fatal - may not have CAP_SYS_NICE or running as non-root
        if (g_verbose) {
            std::cerr << "[DirettaSync] Warning: Could not set SCHED_FIFO priority "
                      << priority << " (error " << ret << ")" << std::endl;
        }
        return false;
    }

    if (g_verbose) {
        std::cout << "[DirettaSync] Worker thread set to SCHED_FIFO priority " << priority << std::endl;
    }
    return true;
}

class RingAccessGuard {
public:
    RingAccessGuard(std::atomic<int>& users, const std::atomic<bool>& reconfiguring)
        : users_(users), active_(false) {
        if (reconfiguring.load(std::memory_order_acquire)) {
            return;
        }
        // C2: acq_rel ensures increment is visible to beginReconfigure() on all architectures
        users_.fetch_add(1, std::memory_order_acq_rel);
        if (reconfiguring.load(std::memory_order_acquire)) {
            // C2: bail-out - never entered guarded section, relaxed is safe
            users_.fetch_sub(1, std::memory_order_relaxed);
            return;
        }
        active_ = true;
    }

    ~RingAccessGuard() {
        if (active_) {
            // C2: release ensures all ring ops complete before decrement
            users_.fetch_sub(1, std::memory_order_release);
        }
    }

    bool active() const { return active_; }

private:
    std::atomic<int>& users_;
    bool active_;
};
} // namespace

//=============================================================================
// Constructor / Destructor
//=============================================================================

DirettaSync::DirettaSync() {
    m_ringBuffer.resize(44100 * 2 * 4, 0x00);
    DIRETTA_LOG("Created");
}

DirettaSync::~DirettaSync() {
    disable();
    DIRETTA_LOG("Destroyed");
}

//=============================================================================
// Initialization (Enable/Disable like MPD)
//=============================================================================

bool DirettaSync::enable(const DirettaConfig& config,
                         std::atomic<bool>* stopSignal) {
    if (m_enabled) {
        DIRETTA_LOG("Already enabled");
        return true;
    }

    m_config = config;
    DIRETTA_LOG("Enabling...");

    if (!discoverTarget(stopSignal)) {
        DIRETTA_LOG("Failed to discover target");
        return false;
    }

    if (!measureMTU()) {
        DIRETTA_LOG("MTU measurement failed, using fallback");
    }

    m_calculator = std::make_unique<DirettaCycleCalculator>(m_effectiveMTU);

    // Note: SDK connection is NOT opened here — it will be opened lazily
    // by open() on the first track. This allows the Diretta Target to remain
    // available for other sources (e.g., DirettaRendererUPnP) until playback
    // actually starts.

    m_enabled = true;
    std::cout << "[DirettaSync] Enabled, MTU=" << m_effectiveMTU << " (SDK deferred until first track)" << std::endl;
    return true;
}

void DirettaSync::disable() {
    DIRETTA_LOG("Disabling...");

    // G1: Signal any pending format transition waits to wake up immediately
    {
        std::lock_guard<std::mutex> lock(m_transitionMutex);
        m_transitionWakeup.store(true, std::memory_order_release);
    }
    m_transitionCv.notify_all();

    if (m_open) {
        close();
    }

    if (m_enabled) {
        shutdownWorker();
        if (m_sdkOpen) {
            DIRETTA::Sync::close();
            m_sdkOpen = false;
        }
        m_calculator.reset();
        m_enabled = false;
    }

    m_hasPreviousFormat = false;
    DIRETTA_LOG("Disabled");
}

bool DirettaSync::openSyncConnection() {
    ACQUA::Clock infoCycle = ACQUA::Clock::MicroSeconds(m_config.infoCycle);

    // CPU affinity: when cpuAudio is set, add OCCUPIED flag to enable SDK CPU pinning
    int threadMode = m_config.threadMode;
    if (m_config.cpuAudio >= 0) {
        threadMode |= 16;  // OCCUPIED = pin SDK thread to CPU
        DIRETTA_LOG("CPU affinity: SDK thread pinned to core " << m_config.cpuAudio
                    << " (OCCUPIED mode, threadMode=" << threadMode << ")");
    }

    DIRETTA_LOG("Opening DIRETTA::Sync with threadMode=" << threadMode
                << " infoCycle=" << m_config.infoCycle << "us");

    bool opened = false;
    for (int attempt = 0; attempt < DirettaRetry::OPEN_RETRIES && !opened; attempt++) {
        if (attempt > 0) {
            DIRETTA_LOG("open() retry #" << attempt);
            std::this_thread::sleep_for(std::chrono::milliseconds(DirettaRetry::OPEN_DELAY_MS));
        }
        opened = DIRETTA::Sync::open(
            DIRETTA::Sync::THRED_MODE(threadMode),
            infoCycle, 0, "slim2diretta", 0x44525400,
            m_config.cpuAudio, m_config.cpuOther, 0, DIRETTA::Sync::MSMODE_AUTO);
    }

    if (!opened) {
        DIRETTA_LOG("DIRETTA::Sync::open failed after 3 attempts");
        return false;
    }

    m_sdkOpen = true;
    inquirySupportFormat(m_targetAddress);

    if (g_verbose) {
        logSinkCapabilities();
    }

    return true;
}

//=============================================================================
// Target Discovery
//=============================================================================

bool DirettaSync::discoverTarget(std::atomic<bool>* stopSignal) {
    DIRETTA_LOG("Discovering Diretta target...");

    auto lastLogTime = std::chrono::steady_clock::now();
    bool firstAttempt = true;

    while (true) {
        // Check stop signal (Ctrl+C, etc.)
        if (stopSignal && !stopSignal->load(std::memory_order_acquire)) {
            DIRETTA_LOG("Discovery cancelled");
            return false;
        }

        DIRETTA::Find::Setting findSettings;
        findSettings.Loopback = false;
        findSettings.ProductID = 0;
        findSettings.Name = "slim2diretta";
        findSettings.MyID = 0x44525400;

        DIRETTA::Find find(findSettings);
        if (!find.open()) {
            DIRETTA_LOG("Failed to open finder");
            if (!stopSignal) return false;  // No retry if no stop signal
            std::this_thread::sleep_for(
                std::chrono::milliseconds(DirettaRetry::DISCOVER_RETRY_MS));
            continue;
        }

        DIRETTA::Find::PortResalts results;
        bool found = find.findOutput(results) && !results.empty();
        find.close();

        if (found) {
            if (!firstAttempt) {
                std::cout << "[DirettaSync] Found target!" << std::endl;
            }
            DIRETTA_LOG("Found " << results.size() << " target(s)");

            if (results.size() == 1 || m_targetIndex == 0) {
                auto it = results.begin();
                m_targetAddress = it->first;
                DIRETTA_LOG("Selected: " << it->second.targetName);
            } else if (m_targetIndex > 0 && m_targetIndex < static_cast<int>(results.size())) {
                auto it = results.begin();
                std::advance(it, m_targetIndex);
                m_targetAddress = it->first;
                DIRETTA_LOG("Selected target #" << (m_targetIndex + 1));
            } else {
                auto it = results.begin();
                m_targetAddress = it->first;
                DIRETTA_LOG("Selected first target: " << it->second.targetName);
            }
            return true;
        }

        // Target not found
        if (!stopSignal) {
            // No stop signal provided — legacy behavior, fail immediately
            DIRETTA_LOG("No Diretta targets found");
            return false;
        }

        // Log periodically (every 5 seconds)
        auto now = std::chrono::steady_clock::now();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
            now - lastLogTime).count();
        if (firstAttempt || elapsed >= DirettaRetry::DISCOVER_LOG_INTERVAL_MS) {
            std::cout << "[DirettaSync] Target not found, retrying..." << std::endl;
            lastLogTime = now;
        }
        firstAttempt = false;

        // Wait before retry, checking stop signal periodically
        for (int waited = 0; waited < DirettaRetry::DISCOVER_RETRY_MS; waited += 100) {
            if (stopSignal && !stopSignal->load(std::memory_order_acquire)) {
                DIRETTA_LOG("Discovery cancelled");
                return false;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    }
}

bool DirettaSync::measureMTU() {
    if (m_mtuOverride > 0) {
        m_effectiveMTU = m_mtuOverride;
        DIRETTA_LOG("Using configured MTU=" << m_effectiveMTU);
        return true;
    }

    if (m_config.mtu > 0) {
        m_effectiveMTU = m_config.mtu;
        DIRETTA_LOG("Using config MTU=" << m_effectiveMTU);
        return true;
    }

    DIRETTA_LOG("Measuring MTU...");

    DIRETTA::Find::Setting findSettings;
    findSettings.Loopback = false;
    findSettings.ProductID = 0;

    DIRETTA::Find find(findSettings);
    if (!find.open()) {
        m_effectiveMTU = m_config.mtuFallback;
        return false;
    }

    uint32_t measuredMTU = 0;
    bool ok = find.measSendMTU(m_targetAddress, measuredMTU);
    find.close();

    if (ok && measuredMTU > 0) {
        m_effectiveMTU = measuredMTU;
        DIRETTA_LOG("Measured MTU=" << m_effectiveMTU);
        return true;
    }

    m_effectiveMTU = m_config.mtuFallback;
    DIRETTA_LOG("MTU measurement failed, using fallback=" << m_effectiveMTU);
    return false;
}

bool DirettaSync::verifyTargetAvailable() {
    DIRETTA::Find::Setting findSettings;
    findSettings.Loopback = false;
    findSettings.ProductID = 0;

    DIRETTA::Find find(findSettings);
    if (!find.open()) return false;

    DIRETTA::Find::PortResalts results;
    bool found = find.findOutput(results) && !results.empty();
    find.close();

    return found;
}

void DirettaSync::listTargets() {
    DIRETTA::Find::Setting findSettings;
    findSettings.Loopback = false;
    findSettings.ProductID = 0;

    DIRETTA::Find find(findSettings);
    if (!find.open()) {
        std::cerr << "Failed to open Diretta finder" << std::endl;
        return;
    }

    DIRETTA::Find::PortResalts results;
    if (!find.findOutput(results) || results.empty()) {
        std::cout << "No Diretta targets found" << std::endl;
        find.close();
        return;
    }

    std::cout << "\nAvailable Diretta Targets (" << results.size() << " found):\n" << std::endl;

    int index = 1;
    for (const auto& target : results) {
        const auto& info = target.second;
        std::cout << "[" << index << "] " << info.targetName << std::endl;

        // Show output/port name if available (differentiates I2S vs USB, etc.)
        if (!info.outputName.empty()) {
            std::cout << "    Output: " << info.outputName << std::endl;
        }

        // Show port numbers
        std::cout << "    Port: IN=" << info.PI << " OUT=" << info.PO;
        if (info.multiport) {
            std::cout << " (multiport)";
        }
        std::cout << std::endl;

        // Show configuration URL if available
        if (!info.config.empty()) {
            std::cout << "    Config: " << info.config << std::endl;
        }

        // Show SDK version
        std::cout << "    Version: " << info.version << std::endl;

        // Show Product ID
        std::cout << "    ProductID: 0x" << std::hex << info.productID << std::dec << std::endl;

        std::cout << std::endl;
        index++;
    }

    find.close();
}

void DirettaSync::logSinkCapabilities() {
    const auto& info = getSinkInfo();
    std::cout << "[DirettaSync] Sink capabilities:" << std::endl;
    std::cout << "[DirettaSync]   PCM: " << (info.checkSinkSupportPCM() ? "YES" : "NO") << std::endl;
    std::cout << "[DirettaSync]   DSD: " << (info.checkSinkSupportDSD() ? "YES" : "NO") << std::endl;
    std::cout << "[DirettaSync]   DSD LSB: " << (info.checkSinkSupportDSDlsb() ? "YES" : "NO") << std::endl;
    std::cout << "[DirettaSync]   DSD MSB: " << (info.checkSinkSupportDSDmsb() ? "YES" : "NO") << std::endl;

    // SDK 148: Log supported multi-stream modes
    // supportMSmode is a bitmask: bit0=MS1, bit1=MS2, bit2=MS3
    // This field is populated by the SDK after the first connection completes,
    // so it reads 0 on the very first track.
    uint16_t msmode = info.supportMSmode;
    if (msmode != 0) {
        std::cout << "[DirettaSync]   MS modes supported: "
                  << ((msmode & 0x01) ? "MS1 " : "")
                  << ((msmode & 0x02) ? "MS2 " : "")
                  << ((msmode & 0x04) ? "MS3 " : "")
                  << std::endl;
        std::cout << "[DirettaSync]   MS mode requested: AUTO (prefers MS3 > MS1 > NONE)" << std::endl;
        // Note: the actual negotiated MS mode (MSmodeSet) is private in the SDK.
        // We infer the active mode from the AUTO algorithm + target capabilities.
        const char* activeMode = "NONE";
        if (msmode & 0x04) activeMode = "MS3";
        else if (msmode & 0x01) activeMode = "MS1";
        std::cout << "[DirettaSync]   MS mode negotiated: " << activeMode
                  << " (AUTO selects highest supported)" << std::endl;
    } else {
        std::cout << "[DirettaSync]   MS modes: (available from next track — target reports capabilities after first connection)"
                  << std::endl;
    }
}

//=============================================================================
// Open/Close (Connection Management)
//=============================================================================

bool DirettaSync::open(const AudioFormat& format) {

    std::cout << "[DirettaSync] ========== OPEN ==========" << std::endl;
    std::cout << "[DirettaSync] Format: " << format.sampleRate << "Hz/"
              << format.bitDepth << "bit/" << format.channels << "ch "
              << (format.isDSD ? "DSD" : "PCM") << std::endl;

    if (!m_enabled) {
        std::cerr << "[DirettaSync] ERROR: Not enabled" << std::endl;
        return false;
    }

    // Reopen SDK if it was released (e.g., after playlist end)
    if (!m_sdkOpen) {
        std::cout << "[DirettaSync] SDK was released, reopening..." << std::endl;
        if (!openSyncConnection()) {
            std::cerr << "[DirettaSync] ERROR: Failed to reopen SDK" << std::endl;
            return false;
        }
        std::cout << "[DirettaSync] SDK reopened successfully" << std::endl;
    }

    bool newIsDsd = format.isDSD;
    bool needFullConnect = true;  // Whether we need connectPrepare/connect/connectWait

    // Fast path: Already open with same format - just reset buffer and resume
    // This avoids the expensive setSink/connect sequence for same-format track transitions
    if (m_open && m_hasPreviousFormat) {
        bool sameFormat = (m_previousFormat.sampleRate == format.sampleRate &&
                          m_previousFormat.bitDepth == format.bitDepth &&
                          m_previousFormat.channels == format.channels &&
                          m_previousFormat.isDSD == format.isDSD);

        std::cout << "[DirettaSync]   Previous: " << m_previousFormat.sampleRate << "Hz/"
                  << m_previousFormat.bitDepth << "bit/" << m_previousFormat.channels << "ch"
                  << (m_previousFormat.isDSD ? " DSD" : " PCM") << std::endl;
        std::cout << "[DirettaSync]   Current:  " << format.sampleRate << "Hz/"
                  << format.bitDepth << "bit/" << format.channels << "ch"
                  << (format.isDSD ? " DSD" : " PCM") << std::endl;

        if (sameFormat) {
            std::cout << "[DirettaSync] Same format - quick resume (no setSink)" << std::endl;

            // Mirror the proven pause/unpause pattern:
            // 1. Flush silence into pipeline
            // 2. Stop SDK playback (prevents getNewStream calls)
            // 3. Clear buffer (safe — no concurrent worker access)
            // 4. Restart playback
            // Without stop(), stale data from the previous track can leak
            // through between the silence phase and the buffer clear.
            {
                int silenceCount = m_isDsdMode.load(std::memory_order_acquire) ? 30 : 10;
                requestShutdownSilence(silenceCount);
                auto start = std::chrono::steady_clock::now();
                while (m_silenceBuffersRemaining.load(std::memory_order_acquire) > 0) {
                    if (std::chrono::steady_clock::now() - start > std::chrono::milliseconds(100)) break;
                    std::this_thread::yield();
                }
            }

            // Stop SDK playback — this is what pause does and what makes
            // pause/unpause work reliably. Prevents getNewStream() calls
            // so clear() has no concurrent access.
            stop();

            // Clear buffer and reset flags
            // NOTE: Do NOT reset m_postOnlineDelayDone for quick resume!
            // The DAC is already stable from the previous track.
            m_ringBuffer.clear();
            m_prefillComplete = false;
            m_rebuffering.store(false, std::memory_order_relaxed);
            // m_postOnlineDelayDone stays true - DAC already stable
            m_stabilizationCount = 0;
            m_stopRequested = false;
            m_draining = false;
            m_silenceBuffersRemaining = 0;

            // Restart playback (like unpause does)
            play();
            m_playing = true;
            m_paused = false;

            // Log MS mode on quick resume — supportMSmode is populated after first session
            if (g_logLevel >= LogLevel::DEBUG) {
                const auto& info = getSinkInfo();
                uint16_t msmode = info.supportMSmode;
                if (msmode != 0) {
                    const char* activeMode = "NONE";
                    if (msmode & 0x04) activeMode = "MS3";
                    else if (msmode & 0x01) activeMode = "MS1";
                    DIRETTA_LOG("MS mode negotiated: " << activeMode);
                }
            }

            std::cout << "[DirettaSync] ========== OPEN COMPLETE (quick) ==========" << std::endl;
            return true;
        } else {
            // Format change detected
            bool wasDSD = m_previousFormat.isDSD;
            bool nowDSD = format.isDSD;
            bool nowPCM = !format.isDSD;

            // Detect rate changes (DSD or PCM)
            // DSD512×44.1 (22,579,200 Hz) ↔ DSD512×48 (24,576,000 Hz) requires clock domain change
            bool isDsdRateChange = wasDSD && nowDSD &&
                                   (m_previousFormat.sampleRate != format.sampleRate);
            bool isPcmRateChange = !wasDSD && nowPCM &&
                                   (m_previousFormat.sampleRate != format.sampleRate);

            if (wasDSD && (nowPCM || isDsdRateChange)) {
                // DSD→PCM or any DSD rate change: Full close/reopen for clean transition
                // I2S targets are timing-sensitive and need a clean break
                // Rate changes cause noise if target's internal buffers aren't fully flushed
                // Clock domain changes (44.1kHz ↔ 48kHz family) also require full reset
                // Note: We can't send silence here because playback is already stopped
                // (auto-stop happens before URI change), so getNewStream() isn't being called
                if (nowPCM) {
                    std::cout << "[DirettaSync] DSD->PCM transition - full close/reopen" << std::endl;
                } else {
                    int prevMultiplier = m_previousFormat.sampleRate / 2822400;
                    int newMultiplier = format.sampleRate / 2822400;
                    std::cout << "[DirettaSync] DSD" << (prevMultiplier * 64) << "->DSD"
                              << (newMultiplier * 64) << " rate change - full close/reopen" << std::endl;
                }

                int dsdMultiplier = m_previousFormat.sampleRate / 2822400;  // DSD64=1, DSD512=8
                std::cout << "[DirettaSync] Previous format was DSD" << (dsdMultiplier * 64) << std::endl;

                // Clear any pending silence requests (playback is stopped, can't send anyway)
                m_silenceBuffersRemaining = 0;

                // Stop playback and disconnect
                stop();
                disconnect(true);

                // CRITICAL: Stop worker thread BEFORE closing SDK to prevent use-after-free
                joinWorkerWithTimeout(1000);

                // Now safe to close SDK - worker thread is stopped
                DIRETTA::Sync::close();

                m_open = false;
                m_playing = false;
                m_paused = false;

                // Extended delay for target to fully reset
                // DSD→PCM needs delay for clock domain switch
                // DSD rate downgrade needs time to flush internal buffers
                // G4: Scale delay with DSD rate - higher rates have deeper pipelines
                // Also scale for high target PCM rates which need extra PLL settling time
                // G1: Use interruptible wait for responsive shutdown
                int baseDelay = 200 * std::max(1, dsdMultiplier);  // 200ms (DSD64) to 1600ms (DSD512)
                int pcmBonus = 0;
                if (nowPCM && format.sampleRate >= 176400) {
                    // Only apply PCM bonus when transitioning TO PCM (not DSD→DSD rate change)
                    int pcmMultiplier = format.sampleRate / 44100;  // 1 for 44100, 8 for 352800
                    pcmBonus = 100 * pcmMultiplier;  // Extra for high-rate PCM
                }
                int resetDelayMs = baseDelay + pcmBonus;
                std::cout << "[DirettaSync] Waiting " << resetDelayMs
                          << "ms for target to reset..." << std::endl;
                interruptibleWait(m_transitionMutex, m_transitionCv, m_transitionWakeup, resetDelayMs);

                // Mark SDK as closed — will be freshly reopened via openSyncConnection()
                m_sdkOpen = false;

                // Fall through to full open path (needFullConnect is already true)
            } else if (isPcmRateChange) {
                // PCM rate change: Full close/reopen for clean transition
                // Same issue as DSD - stale samples at old rate cause transition noise
                std::cout << "[DirettaSync] PCM " << m_previousFormat.sampleRate << "Hz->"
                          << format.sampleRate << "Hz rate change - full close/reopen" << std::endl;

                // Clear any pending silence requests
                m_silenceBuffersRemaining = 0;

                // Stop playback and disconnect
                stop();
                disconnect(true);

                // CRITICAL: Stop worker thread BEFORE closing SDK to prevent use-after-free
                joinWorkerWithTimeout(1000);

                // Now safe to close SDK - worker thread is stopped
                DIRETTA::Sync::close();

                m_open = false;
                m_playing = false;
                m_paused = false;

                // Shorter delay for PCM rate change (TEST: reduced from 200 to 100)
                // G1: Use interruptible wait for responsive shutdown
                int resetDelayMs = 100;
                std::cout << "[DirettaSync] Waiting " << resetDelayMs
                          << "ms for target to reset..." << std::endl;
                interruptibleWait(m_transitionMutex, m_transitionCv, m_transitionWakeup, resetDelayMs);

                // Mark SDK as closed — will be freshly reopened via openSyncConnection()
                m_sdkOpen = false;

                // Fall through to full open path
            } else {
                // PCM→DSD (or bit depth change)
                // Detect same-family high-rate transitions that need full reset
                // The target's PLL gets stuck when transitioning within same clock family
                // at high rates (e.g., PCM 352.8kHz → DSD512×44.1)

                // Helper lambda to determine clock family (441 = 44.1kHz, 480 = 48kHz)
                auto getClockFamily = [](uint32_t sampleRate) -> int {
                    if (sampleRate % 44100 == 0) return 441;
                    if (sampleRate % 48000 == 0) return 480;
                    return 0;
                };

                int oldFamily = getClockFamily(m_previousFormat.sampleRate);
                int newFamily = getClockFamily(format.sampleRate);
                bool sameFamily = (oldFamily != 0 && oldFamily == newFamily);

                // High-rate: PCM 176.4kHz+ (4fs) or DSD256+ (which corresponds to 4fs base)
                bool oldIsHighRate = m_previousFormat.sampleRate >= 176400;  // Previous was high-rate PCM
                bool newIsHighRate = format.sampleRate >= 11289600;  // DSD256×44.1 = 11,289,600

                bool needsFullReset = sameFamily && (oldIsHighRate || newIsHighRate);

                if (needsFullReset) {
                    // Same clock family high-rate PCM→DSD transition
                    // Full close/reopen required to reset target's PLL
                    int dsdMultiplier = format.sampleRate / 2822400;  // Target DSD rate
                    std::cout << "[DirettaSync] High-rate PCM->DSD" << (dsdMultiplier * 64)
                              << " (same " << oldFamily << "Hz family) - full close/reopen" << std::endl;

                    // Clear any pending silence requests
                    m_silenceBuffersRemaining = 0;

                    // Stop playback and disconnect
                    stop();
                    disconnect(true);

                    // CRITICAL: Stop worker thread BEFORE closing SDK to prevent use-after-free
                    m_running = false;
                    {
                        std::lock_guard<std::mutex> lock(m_workerMutex);
                        if (m_workerThread.joinable()) {
                            m_workerThread.join();
                        }
                    }

                    // Now safe to close SDK - worker thread is stopped
                    DIRETTA::Sync::close();

                    m_open = false;
                    m_playing = false;
                    m_paused = false;

                    // Delay for target to reset - scale with target DSD rate
                    int resetDelayMs = 200 * std::max(1, dsdMultiplier);  // 200ms (DSD64) to 1600ms (DSD512)
                    std::cout << "[DirettaSync] Waiting " << resetDelayMs
                              << "ms for target to reset..." << std::endl;
                    interruptibleWait(m_transitionMutex, m_transitionCv, m_transitionWakeup, resetDelayMs);

                    // Mark SDK as closed — will be freshly reopened via openSyncConnection()
                    m_sdkOpen = false;

                    // Fall through to full open path
                } else {
                    // Different clock family or low-rate: full teardown + fresh reopen
                    std::cout << "[DirettaSync] Format change - full teardown" << std::endl;

                    // Clear any pending silence requests
                    m_silenceBuffersRemaining = 0;

                    // Stop playback and disconnect
                    stop();
                    disconnect(true);

                    // CRITICAL: Stop worker thread BEFORE closing SDK to prevent use-after-free
                    m_running = false;
                    {
                        std::lock_guard<std::mutex> lock(m_workerMutex);
                        if (m_workerThread.joinable()) {
                            m_workerThread.join();
                        }
                    }

                    // Now safe to close SDK - worker thread is stopped
                    DIRETTA::Sync::close();

                    m_open = false;
                    m_playing = false;
                    m_paused = false;

                    // Mark SDK as closed — will be freshly reopened via openSyncConnection()
                    m_sdkOpen = false;

                    // Wait for target to process the format change
                    int resetDelayMs = 200;
                    std::cout << "[DirettaSync] Waiting " << resetDelayMs
                              << "ms for target to reset..." << std::endl;
                    interruptibleWait(m_transitionMutex, m_transitionCv, m_transitionWakeup, resetDelayMs);
                }
            }
            needFullConnect = true;
        }
    }

    // Reopen SDK if it was closed during format transition
    // Using openSyncConnection() ensures a completely fresh SDK state,
    // preventing state accumulation across multiple format changes.
    if (!m_sdkOpen) {
        std::cout << "[DirettaSync] Reopening SDK via openSyncConnection()..." << std::endl;
        if (!openSyncConnection()) {
            std::cerr << "[DirettaSync] Failed to reopen SDK" << std::endl;
            return false;
        }
        std::cout << "[DirettaSync] SDK reopened fresh" << std::endl;
    }

    // Full reset for first open or after format change reopen
    if (needFullConnect) {
        fullReset();
        // Log MS mode after reopen — supportMSmode may now be populated
        if (g_logLevel >= LogLevel::DEBUG && m_hasPreviousFormat) {
            const auto& info = getSinkInfo();
            uint16_t msmode = info.supportMSmode;
            if (msmode != 0) {
                const char* activeMode = "NONE";
                if (msmode & 0x04) activeMode = "MS3";
                else if (msmode & 0x01) activeMode = "MS1";
                DIRETTA_LOG("MS mode negotiated: " << activeMode);
            }
        }
    }
    m_isDsdMode.store(newIsDsd, std::memory_order_release);

    uint32_t effectiveSampleRate;
    int effectiveChannels = format.channels;
    int bitsPerSample;

    if (m_isDsdMode.load(std::memory_order_acquire)) {
        uint32_t dsdBitRate = format.sampleRate;
        uint32_t byteRate = dsdBitRate / 8;
        effectiveSampleRate = dsdBitRate;
        bitsPerSample = 1;

        DIRETTA_LOG("DSD: bitRate=" << dsdBitRate << " byteRate=" << byteRate);

        if (!configureSinkDSD(dsdBitRate, format.channels, format)) {
            return false;
        }
        configureRingDSD(byteRate, format.channels);
    } else {
        effectiveSampleRate = format.sampleRate;

        int acceptedBits;
        configureSinkPCM(format.sampleRate, format.channels, format.bitDepth, acceptedBits);
        bitsPerSample = acceptedBits;

        int direttaBps = (acceptedBits == 32) ? 4 : (acceptedBits == 24) ? 3 : 2;
        int inputBps = (format.bitDepth == 32 || format.bitDepth == 24) ? 4 : 2;

        configureRingPCM(format.sampleRate, format.channels, direttaBps, inputBps, format.isCompressed);
    }

    unsigned int cycleTimeUs = calculateCycleTime(effectiveSampleRate, effectiveChannels, bitsPerSample);
    ACQUA::Clock cycleTime = ACQUA::Clock::MicroSeconds(cycleTimeUs);

    // Initial delay - Target needs time to prepare for new format
    // Longer delay for first open/reconnect, shorter for reconfigure
    int initialDelayMs = needFullConnect ? 500 : 200;
    std::this_thread::sleep_for(std::chrono::milliseconds(initialDelayMs));

    // setSink reconfiguration
    bool sinkSet = false;
    int maxAttempts = needFullConnect ? DirettaRetry::SETSINK_RETRIES_FULL : DirettaRetry::SETSINK_RETRIES_QUICK;
    int retryDelayMs = needFullConnect ? DirettaRetry::SETSINK_DELAY_FULL_MS : DirettaRetry::SETSINK_DELAY_QUICK_MS;
    for (int attempt = 0; attempt < maxAttempts && !sinkSet; attempt++) {
        if (attempt > 0) {
            DIRETTA_LOG("setSink retry #" << attempt);
            std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));
        }
        sinkSet = setSink(m_targetAddress, cycleTime, false, m_effectiveMTU);
    }

    if (!sinkSet) {
        std::cerr << "[DirettaSync] Failed to set sink after " << maxAttempts << " attempts" << std::endl;
        return false;
    }

    // SDK 148: Query format support after setSink to initialize internal structures
    // This may be required for stream objects to be properly allocated
    if (needFullConnect) {
        inquirySupportFormat(m_targetAddress);
    }

    applyTransferMode(m_config.transferMode, cycleTime);

    // Connect sequence - only needed after disconnect
    if (needFullConnect) {
        if (!connectPrepare()) {
            std::cerr << "[DirettaSync] connectPrepare failed" << std::endl;
            return false;
        }

        bool connected = false;
        for (int attempt = 0; attempt < DirettaRetry::CONNECT_RETRIES && !connected; attempt++) {
            if (attempt > 0) {
                DIRETTA_LOG("connect retry #" << attempt);
                std::this_thread::sleep_for(std::chrono::milliseconds(DirettaRetry::CONNECT_DELAY_MS));
            }
            connected = connect(0);
        }

        if (!connected) {
            std::cerr << "[DirettaSync] connect failed" << std::endl;
            return false;
        }

        if (!connectWait()) {
            std::cerr << "[DirettaSync] connectWait failed" << std::endl;
            disconnect();
            return false;
        }
    } else {
        DIRETTA_LOG("Skipping connect sequence (still connected)");
    }

    // Clear buffer and start playback
    m_ringBuffer.clear();
    m_prefillComplete = false;
    m_postOnlineDelayDone = false;

    play();

    if (!waitForOnline(m_config.onlineWaitMs)) {
        DIRETTA_LOG("WARNING: Did not come online within timeout");
    }

    m_postOnlineDelayDone = false;
    m_stabilizationCount = 0;

    // Save format state
    m_previousFormat = format;
    m_hasPreviousFormat = true;
    m_currentFormat = format;

    m_open = true;
    m_playing = true;
    m_paused = false;

    std::cout << "[DirettaSync] ========== OPEN COMPLETE ==========" << std::endl;
    return true;
}

void DirettaSync::close() {
    std::cout << "[DirettaSync] Close()" << std::endl;

    if (!m_open) {
        DIRETTA_LOG("Not open");
        return;
    }

    // Request shutdown silence
    requestShutdownSilence(m_isDsdMode.load(std::memory_order_acquire) ? 50 : 20);

    auto start = std::chrono::steady_clock::now();
    while (m_silenceBuffersRemaining.load(std::memory_order_acquire) > 0) {
        if (std::chrono::steady_clock::now() - start > std::chrono::milliseconds(150)) {
            DIRETTA_LOG("Silence timeout");
            break;
        }
        std::this_thread::yield();
    }

    m_stopRequested = true;

    stop();
    disconnect(true);  // Wait for proper disconnection before returning

    int waitCount = 0;
    while (m_workerActive.load() && waitCount < 50) {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        waitCount++;
    }

    m_open = false;
    m_playing = false;
    m_paused = false;
    m_rebuffering.store(false, std::memory_order_relaxed);

    DIRETTA_LOG("Close() done");
}

void DirettaSync::release() {
    std::cout << "[DirettaSync] Release() - fully releasing target" << std::endl;

    // First do a normal close if still open
    if (m_open) {
        close();
    }

    // Now fully close the SDK connection so target is released
    if (m_sdkOpen) {
        DIRETTA_LOG("Closing SDK connection...");

        // Shutdown worker thread
        joinWorkerWithTimeout(1000);

        // Close SDK-level connection
        DIRETTA::Sync::close();
        m_sdkOpen = false;

        // Brief delay to ensure target processes the disconnect
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        std::cout << "[DirettaSync] Target released" << std::endl;
    }

    // Clear format state so next open() starts fresh
    m_hasPreviousFormat = false;
}

bool DirettaSync::reopenForFormatChange() {
    DIRETTA_LOG("reopenForFormatChange: stopping...");

    stop();
    disconnect(true);

    // CRITICAL: Stop worker thread BEFORE closing SDK to prevent use-after-free
    joinWorkerWithTimeout(1000);

    // Now safe to close SDK - worker thread is stopped
    DIRETTA::Sync::close();

    // Reset state flags so subsequent open path starts fresh.
    // Without this, PCM→DSD transitions retain stale state causing noise.
    m_open = false;
    m_playing = false;
    m_paused = false;

    // G1: Use interruptible wait for responsive shutdown
    DIRETTA_LOG("Waiting " << m_config.formatSwitchDelayMs << "ms...");
    interruptibleWait(m_transitionMutex, m_transitionCv, m_transitionWakeup,
                      static_cast<int>(m_config.formatSwitchDelayMs));

    ACQUA::Clock infoCycle = ACQUA::Clock::MicroSeconds(m_config.infoCycle);

    int threadMode = m_config.threadMode;
    if (m_config.cpuAudio >= 0) {
        threadMode |= 16;  // OCCUPIED
    }
    if (!DIRETTA::Sync::open(
            DIRETTA::Sync::THRED_MODE(threadMode),
            infoCycle, 0, "slim2diretta", 0x44525400,
            m_config.cpuAudio, m_config.cpuOther, 0, DIRETTA::Sync::MSMODE_AUTO)) {
        std::cerr << "[DirettaSync] Failed to re-open sync" << std::endl;
        return false;
    }

    // NOTE: Do NOT call setSink() or inquirySupportFormat() here!
    // The caller will handle all configuration with the proper cycleTime
    // calculated from the new format. Calling setSink() twice with different
    // parameters corrupts SDK 148's internal stream state.

    DIRETTA_LOG("reopenForFormatChange complete (SDK reopened, awaiting caller config)");
    return true;
}

void DirettaSync::fullReset() {
    DIRETTA_LOG("fullReset()");

    m_stopRequested = true;
    m_draining = false;

    int waitCount = 0;
    while (m_workerActive.load(std::memory_order_acquire) && waitCount < 50) {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        waitCount++;
    }

    {
        std::lock_guard<std::mutex> lock(m_configMutex);
        ReconfigureGuard guard(*this);

        m_prefillComplete = false;
        m_postOnlineDelayDone = false;
        m_silenceBuffersRemaining = 0;
        m_stabilizationCount = 0;
        m_streamCount = 0;
        m_pushCount = 0;
        m_rebuffering.store(false, std::memory_order_relaxed);
        m_isDsdMode.store(false, std::memory_order_release);
        m_needDsdBitReversal.store(false, std::memory_order_release);
        m_needDsdByteSwap.store(false, std::memory_order_release);
        m_isLowBitrate.store(false, std::memory_order_release);
        m_need24BitPack.store(false, std::memory_order_release);
        m_need16To32Upsample.store(false, std::memory_order_release);
        m_need16To24Upsample.store(false, std::memory_order_release);
        m_bytesPerFrame.store(0, std::memory_order_release);
        m_framesPerBufferRemainder.store(0, std::memory_order_release);
        m_framesPerBufferAccumulator.store(0, std::memory_order_release);

        m_ringBuffer.clear();
    }

    m_stopRequested = false;
}

//=============================================================================
// Sink Configuration
//=============================================================================

void DirettaSync::configureSinkPCM(int rate, int channels, int inputBits, int& acceptedBits) {
    std::lock_guard<std::mutex> lock(m_configMutex);

    DIRETTA::FormatConfigure fmt;
    fmt.setSpeed(rate);
    fmt.setChannel(channels);

    // Only offer 32-bit if source is 32-bit — avoids opening 32-bit on DACs
    // that report 32-bit support at the Diretta target level but are actually
    // limited to 24-bit, which causes white noise.
    if (inputBits >= 32) {
        fmt.setFormat(DIRETTA::FormatID::FMT_PCM_SIGNED_32);
        if (checkSinkSupport(fmt)) {
            setSinkConfigure(fmt);
            acceptedBits = 32;
            DIRETTA_LOG("Sink PCM: " << rate << "Hz " << channels << "ch 32-bit");
            return;
        }
    }

    fmt.setFormat(DIRETTA::FormatID::FMT_PCM_SIGNED_24);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        acceptedBits = 24;
        DIRETTA_LOG("Sink PCM: " << rate << "Hz " << channels << "ch 24-bit");
        return;
    }

    fmt.setFormat(DIRETTA::FormatID::FMT_PCM_SIGNED_16);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        acceptedBits = 16;
        DIRETTA_LOG("Sink PCM: " << rate << "Hz " << channels << "ch 16-bit");
        return;
    }

    throw std::runtime_error("No supported PCM format found");
}

bool DirettaSync::configureSinkDSD(uint32_t dsdBitRate, int channels, const AudioFormat& format) {
    std::lock_guard<std::mutex> lock(m_configMutex);

    DIRETTA_LOG("DSD: bitRate=" << dsdBitRate << " ch=" << channels);

    // Source format: DSF=LSB, DFF=MSB
    bool sourceIsLSB = (format.dsdFormat == AudioFormat::DSDFormat::DSF);
    DIRETTA_LOG("Source DSD format: " << (sourceIsLSB ? "LSB (DSF)" : "MSB (DFF)"));

    const auto& info = getSinkInfo();
    DIRETTA_LOG("Sink DSD support: " << (info.checkSinkSupportDSD() ? "YES" : "NO"));
    DIRETTA_LOG("Sink DSD LSB: " << (info.checkSinkSupportDSDlsb() ? "YES" : "NO"));
    DIRETTA_LOG("Sink DSD MSB: " << (info.checkSinkSupportDSDmsb() ? "YES" : "NO"));

    DIRETTA::FormatConfigure fmt;
    fmt.setSpeed(dsdBitRate);
    fmt.setChannel(channels);

    // Try LSB | BIG first (most common for DSF files)
    fmt.setFormat(DIRETTA::FormatID::FMT_DSD1 |
                  DIRETTA::FormatID::FMT_DSD_SIZ_32 |
                  DIRETTA::FormatID::FMT_DSD_LSB |
                  DIRETTA::FormatID::FMT_DSD_BIG);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        m_needDsdBitReversal.store(!sourceIsLSB, std::memory_order_release);  // Reverse if source is MSB (DFF)
        m_needDsdByteSwap.store(false, std::memory_order_release);  // BIG endian = no swap
        // Set cached conversion mode: no swap, maybe bit reverse
        m_dsdConversionMode.store(m_needDsdBitReversal.load(std::memory_order_acquire)
            ? DirettaRingBuffer::DSDConversionMode::BitReverseOnly
            : DirettaRingBuffer::DSDConversionMode::Passthrough, std::memory_order_release);
        DIRETTA_LOG("Sink DSD: LSB | BIG"
                    << (m_needDsdBitReversal.load(std::memory_order_acquire) ? " (bit reversal)" : "")
                    << " mode=" << static_cast<int>(m_dsdConversionMode.load(std::memory_order_relaxed)));
        return true;
    }

    // Try MSB | BIG
    fmt.setFormat(DIRETTA::FormatID::FMT_DSD1 |
                  DIRETTA::FormatID::FMT_DSD_SIZ_32 |
                  DIRETTA::FormatID::FMT_DSD_MSB |
                  DIRETTA::FormatID::FMT_DSD_BIG);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        m_needDsdBitReversal.store(sourceIsLSB, std::memory_order_release);  // Reverse if source is LSB (DSF)
        m_needDsdByteSwap.store(false, std::memory_order_release);  // BIG endian = no swap
        // Set cached conversion mode: no swap, maybe bit reverse
        m_dsdConversionMode.store(m_needDsdBitReversal.load(std::memory_order_acquire)
            ? DirettaRingBuffer::DSDConversionMode::BitReverseOnly
            : DirettaRingBuffer::DSDConversionMode::Passthrough, std::memory_order_release);
        DIRETTA_LOG("Sink DSD: MSB | BIG"
                    << (m_needDsdBitReversal.load(std::memory_order_acquire) ? " (bit reversal)" : "")
                    << " mode=" << static_cast<int>(m_dsdConversionMode.load(std::memory_order_relaxed)));
        return true;
    }

    // Try LSB | LITTLE
    fmt.setFormat(DIRETTA::FormatID::FMT_DSD1 |
                  DIRETTA::FormatID::FMT_DSD_SIZ_32 |
                  DIRETTA::FormatID::FMT_DSD_LSB |
                  DIRETTA::FormatID::FMT_DSD_LITTLE);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        m_needDsdBitReversal.store(!sourceIsLSB, std::memory_order_release);
        m_needDsdByteSwap.store(true, std::memory_order_release);  // LITTLE endian = swap bytes
        // Set cached conversion mode: always swap, maybe bit reverse
        m_dsdConversionMode.store(m_needDsdBitReversal.load(std::memory_order_acquire)
            ? DirettaRingBuffer::DSDConversionMode::BitReverseAndSwap
            : DirettaRingBuffer::DSDConversionMode::ByteSwapOnly, std::memory_order_release);
        DIRETTA_LOG("Sink DSD: LSB | LITTLE"
                    << (m_needDsdBitReversal.load(std::memory_order_acquire) ? " (bit reversal)" : "")
                    << " (byte swap) mode=" << static_cast<int>(m_dsdConversionMode.load(std::memory_order_relaxed)));
        return true;
    }

    // Try MSB | LITTLE
    fmt.setFormat(DIRETTA::FormatID::FMT_DSD1 |
                  DIRETTA::FormatID::FMT_DSD_SIZ_32 |
                  DIRETTA::FormatID::FMT_DSD_MSB |
                  DIRETTA::FormatID::FMT_DSD_LITTLE);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        m_needDsdBitReversal.store(sourceIsLSB, std::memory_order_release);
        m_needDsdByteSwap.store(true, std::memory_order_release);  // LITTLE endian = swap bytes
        // Set cached conversion mode: always swap, maybe bit reverse
        m_dsdConversionMode.store(m_needDsdBitReversal.load(std::memory_order_acquire)
            ? DirettaRingBuffer::DSDConversionMode::BitReverseAndSwap
            : DirettaRingBuffer::DSDConversionMode::ByteSwapOnly, std::memory_order_release);
        DIRETTA_LOG("Sink DSD: MSB | LITTLE"
                    << (m_needDsdBitReversal.load(std::memory_order_acquire) ? " (bit reversal)" : "")
                    << " (byte swap) mode=" << static_cast<int>(m_dsdConversionMode.load(std::memory_order_relaxed)));
        return true;
    }

    // Last resort - assume LSB | BIG target
    fmt.setFormat(DIRETTA::FormatID::FMT_DSD1);
    if (checkSinkSupport(fmt)) {
        setSinkConfigure(fmt);
        m_needDsdBitReversal.store(!sourceIsLSB, std::memory_order_release);
        m_needDsdByteSwap.store(false, std::memory_order_release);
        DIRETTA_LOG("Sink DSD: FMT_DSD1 only"
                    << (m_needDsdBitReversal.load(std::memory_order_acquire) ? " (bit reversal)" : ""));

        // Set cached conversion mode for optimized DSD path
        bool needReverse = m_needDsdBitReversal.load(std::memory_order_acquire);
        bool needSwap = m_needDsdByteSwap.load(std::memory_order_acquire);
        if (needReverse && needSwap) {
            m_dsdConversionMode.store(DirettaRingBuffer::DSDConversionMode::BitReverseAndSwap, std::memory_order_release);
        } else if (needReverse) {
            m_dsdConversionMode.store(DirettaRingBuffer::DSDConversionMode::BitReverseOnly, std::memory_order_release);
        } else if (needSwap) {
            m_dsdConversionMode.store(DirettaRingBuffer::DSDConversionMode::ByteSwapOnly, std::memory_order_release);
        } else {
            m_dsdConversionMode.store(DirettaRingBuffer::DSDConversionMode::Passthrough, std::memory_order_release);
        }
        DIRETTA_LOG("DSD conversion mode: " << static_cast<int>(m_dsdConversionMode.load(std::memory_order_relaxed)));
        return true;
    }

    std::cerr << "[DirettaSync] ERROR: DAC does not support native DSD — "
              << "configure LMS to send DoP instead of native DSD" << std::endl;
    return false;
}

//=============================================================================
// Ring Buffer Configuration
//=============================================================================

size_t DirettaSync::calculateAlignedPrefill(size_t bytesPerSecond, size_t bytesPerBuffer,
                                            bool isDSD, bool isCompressed) {
    // Determine target fill time based on format
    // High sample rates (>192kHz): LMS streams at ~1x real-time, need larger prefill
    uint32_t rate = m_sampleRate.load(std::memory_order_relaxed);
    bool highRate = !isDSD && (rate > DirettaBuffer::HIGHRATE_THRESHOLD);

    size_t targetMs;
    if (isDSD) {
        targetMs = DirettaBuffer::PREFILL_MS_DSD;
    } else if (highRate && isCompressed) {
        targetMs = DirettaBuffer::PREFILL_MS_HIGHRATE_COMPRESSED;
    } else if (highRate) {
        targetMs = DirettaBuffer::PREFILL_MS_HIGHRATE_UNCOMPRESSED;
    } else if (isCompressed) {
        targetMs = DirettaBuffer::PREFILL_MS_COMPRESSED;
    } else {
        targetMs = DirettaBuffer::PREFILL_MS_UNCOMPRESSED;
    }

    // Convert to bytes
    size_t targetBytes = (bytesPerSecond * targetMs) / 1000;

    // Calculate buffer count, rounding UP to ensure we meet the target
    size_t targetBuffers = (targetBytes + bytesPerBuffer - 1) / bytesPerBuffer;

    // Clamp to reasonable bounds
    // Min: 8 buffers (ensures stability)
    // Max: 1/2 of ring buffer capacity for high rates, 1/4 for normal rates
    size_t ringSize = m_ringBuffer.size();
    size_t divisor = highRate ? 2 : 4;
    size_t maxBuffers = (ringSize > 0 && bytesPerBuffer > 0) ? ringSize / (divisor * bytesPerBuffer) : 100;

    targetBuffers = std::max(targetBuffers, size_t{8});
    targetBuffers = std::min(targetBuffers, maxBuffers);

    return targetBuffers;
}

void DirettaSync::configureRingPCM(int rate, int channels, int direttaBps, int inputBps, bool isCompressed) {
    std::lock_guard<std::mutex> lock(m_configMutex);
    ReconfigureGuard guard(*this);

    m_sampleRate.store(rate, std::memory_order_release);
    m_channels.store(channels, std::memory_order_release);
    m_bytesPerSample.store(direttaBps, std::memory_order_release);
    m_inputBytesPerSample.store(inputBps, std::memory_order_release);
    m_need24BitPack.store(direttaBps == 3 && inputBps == 4, std::memory_order_release);
    m_need16To32Upsample.store(direttaBps == 4 && inputBps == 2, std::memory_order_release);
    m_need16To24Upsample.store(direttaBps == 3 && inputBps == 2, std::memory_order_release);
    m_isDsdMode.store(false, std::memory_order_release);
    m_needDsdBitReversal.store(false, std::memory_order_release);
    m_needDsdByteSwap.store(false, std::memory_order_release);
    m_isLowBitrate.store(direttaBps <= 2 && rate <= 48000, std::memory_order_release);
    m_dsdConversionMode.store(DirettaRingBuffer::DSDConversionMode::Passthrough, std::memory_order_release);

    // Increment format generation to invalidate cached values in sendAudio
    m_formatGeneration.fetch_add(1, std::memory_order_release);
    // C1: Also increment consumer generation for getNewStream
    m_consumerStateGen.fetch_add(1, std::memory_order_release);

    size_t bytesPerSecond = static_cast<size_t>(rate) * channels * direttaBps;
    float bufferSec = DirettaBuffer::pcmBufferSeconds(static_cast<uint32_t>(rate));
    size_t ringSize = DirettaBuffer::calculateBufferSize(bytesPerSecond, bufferSec);

    m_ringBuffer.resize(ringSize, 0x00);
    ringSize = m_ringBuffer.size();

    int bytesPerFrame = channels * direttaBps;
    int framesBase = rate / 1000;
    int framesRemainder = rate % 1000;
    m_bytesPerFrame.store(bytesPerFrame, std::memory_order_release);
    m_framesPerBufferRemainder.store(static_cast<uint32_t>(framesRemainder), std::memory_order_release);
    m_framesPerBufferAccumulator.store(0, std::memory_order_release);

    size_t bytesPerBuffer = static_cast<size_t>(framesBase) * bytesPerFrame;
    m_bytesPerBuffer.store(static_cast<int>(bytesPerBuffer), std::memory_order_release);

    // Aligned prefill: calculate as whole-buffer count for clean transitions
    m_prefillTargetBuffers = calculateAlignedPrefill(bytesPerSecond, bytesPerBuffer, false, isCompressed);

    // For non-integer sample rates (44.1kHz family), calculate exact byte count
    // accounting for the frames remainder accumulator pattern
    if (framesRemainder == 0) {
        m_prefillTarget = m_prefillTargetBuffers * bytesPerBuffer;
    } else {
        // Compute the sum of N callback sizes to stay on true boundaries
        size_t totalBytes = 0;
        uint32_t acc = 0;
        for (size_t i = 0; i < m_prefillTargetBuffers; ++i) {
            size_t bytesThis = bytesPerBuffer;
            acc += static_cast<uint32_t>(framesRemainder);
            if (acc >= 1000) {
                acc -= 1000;
                bytesThis += static_cast<size_t>(bytesPerFrame);
            }
            totalBytes += bytesThis;
        }
        m_prefillTarget = totalBytes;
    }
    m_prefillComplete = false;

    DIRETTA_LOG("Ring PCM: " << rate << "Hz " << channels << "ch "
                << direttaBps << "bps, buffer=" << ringSize
                << ", prefill=" << m_prefillTargetBuffers << " buffers ("
                << m_prefillTarget << " bytes, "
                << (isCompressed ? "compressed" : "uncompressed") << ")");
}

void DirettaSync::configureRingDSD(uint32_t byteRate, int channels) {
    std::lock_guard<std::mutex> lock(m_configMutex);
    ReconfigureGuard guard(*this);

    m_isDsdMode.store(true, std::memory_order_release);
    m_need24BitPack.store(false, std::memory_order_release);
    m_need16To32Upsample.store(false, std::memory_order_release);
    m_need16To24Upsample.store(false, std::memory_order_release);
    m_channels.store(channels, std::memory_order_release);
    m_isLowBitrate.store(false, std::memory_order_release);

    // Increment format generation to invalidate cached values in sendAudio
    m_formatGeneration.fetch_add(1, std::memory_order_release);
    // C1: Also increment consumer generation for getNewStream
    m_consumerStateGen.fetch_add(1, std::memory_order_release);

    uint32_t bytesPerSecond = byteRate * channels;
    size_t ringSize = DirettaBuffer::calculateBufferSize(bytesPerSecond, DirettaBuffer::DSD_BUFFER_SECONDS);

    m_ringBuffer.resize(ringSize, 0x69);  // DSD silence
    ringSize = m_ringBuffer.size();

    uint32_t inputBytesPerMs = (byteRate / 1000) * channels;
    size_t bytesPerBuffer = inputBytesPerMs;
    bytesPerBuffer = ((bytesPerBuffer + (4 * channels - 1)) / (4 * channels)) * (4 * channels);
    if (bytesPerBuffer < 64) bytesPerBuffer = 64;
    m_bytesPerBuffer.store(static_cast<int>(bytesPerBuffer), std::memory_order_release);
    m_bytesPerFrame.store(0, std::memory_order_release);
    m_framesPerBufferRemainder.store(0, std::memory_order_release);
    m_framesPerBufferAccumulator.store(0, std::memory_order_release);

    // Aligned prefill: calculate as whole-buffer count for clean transitions
    m_prefillTargetBuffers = calculateAlignedPrefill(bytesPerSecond, bytesPerBuffer, true, false);
    m_prefillTarget = m_prefillTargetBuffers * bytesPerBuffer;
    m_prefillComplete = false;

    DIRETTA_LOG("Ring DSD: byteRate=" << byteRate << " ch=" << channels
                << " buffer=" << ringSize << " prefill=" << m_prefillTargetBuffers
                << " buffers (" << m_prefillTarget << " bytes)");
}

//=============================================================================
// Playback Control
//=============================================================================

bool DirettaSync::startPlayback() {
    if (!m_open) return false;
    if (m_playing && !m_paused) return true;

    if (m_paused) {
        resumePlayback();
        return true;
    }

    play();
    m_playing = true;
    m_paused = false;
    return true;
}

void DirettaSync::stopPlayback(bool immediate) {
    // Log accumulated underruns at session end
    uint32_t underruns = m_underrunCount.exchange(0, std::memory_order_relaxed);
    if (underruns > 0) {
        std::cerr << "[DirettaSync] Session had " << underruns << " underrun(s)" << std::endl;
    }

    if (!m_playing) return;

    if (!immediate) {
        requestShutdownSilence(m_isDsdMode.load(std::memory_order_acquire) ? 50 : 20);

        auto start = std::chrono::steady_clock::now();
        while (m_silenceBuffersRemaining.load() > 0) {
            if (std::chrono::steady_clock::now() - start > std::chrono::milliseconds(150)) break;
            std::this_thread::yield();
        }
    }

    stop();
    m_playing = false;
    m_paused = false;
}

void DirettaSync::pausePlayback() {
    if (!m_playing || m_paused) return;

    requestShutdownSilence(m_isDsdMode.load(std::memory_order_acquire) ? 30 : 10);

    auto start = std::chrono::steady_clock::now();
    while (m_silenceBuffersRemaining.load() > 0) {
        if (std::chrono::steady_clock::now() - start > std::chrono::milliseconds(80)) break;
        std::this_thread::yield();
    }

    stop();
    m_paused = true;
}

void DirettaSync::resumePlayback() {
    if (!m_paused) return;

    DIRETTA_LOG("Resuming from pause...");

    // Reset flags set during pausePlayback()
    m_draining = false;
    m_stopRequested = false;
    m_silenceBuffersRemaining = 0;

    // Clear stale buffer data and require fresh prefill
    m_ringBuffer.clear();
    m_prefillComplete = false;

    play();
    m_paused = false;
    m_playing = true;

    DIRETTA_LOG("Resumed - buffer cleared, waiting for prefill");
}

void DirettaSync::sendPreTransitionSilence() {
    // Pre-transition silence disabled - was causing issues during format switching
    // The stopPlayback() silence mechanism handles this case adequately
}

//=============================================================================
// Audio Data (Push Interface)
//=============================================================================

size_t DirettaSync::sendAudio(const uint8_t* data, size_t numSamples) {
    if (m_draining.load(std::memory_order_acquire)) return 0;
    if (m_stopRequested.load(std::memory_order_acquire)) return 0;
    if (!is_online()) return 0;

    RingAccessGuard ringGuard(m_ringUsers, m_reconfiguring);
    if (!ringGuard.active()) return 0;

    // Generation counter optimization: single atomic load vs 5-6 loads
    // Only reload format atomics when format has actually changed
    uint32_t gen = m_formatGeneration.load(std::memory_order_acquire);
    if (gen != m_cachedFormatGen) {
        m_cachedDsdMode = m_isDsdMode.load(std::memory_order_acquire);
        m_cachedPack24bit = m_need24BitPack.load(std::memory_order_acquire);
        m_cachedUpsample16to32 = m_need16To32Upsample.load(std::memory_order_acquire);
        m_cachedUpsample16to24 = m_need16To24Upsample.load(std::memory_order_acquire);
        m_cachedChannels = m_channels.load(std::memory_order_acquire);
        m_cachedBytesPerSample = m_bytesPerSample.load(std::memory_order_acquire);
        m_cachedDsdConversionMode = m_dsdConversionMode.load(std::memory_order_acquire);
        m_cachedFormatGen = gen;
    }

    // Use cached values (no atomic loads in hot path)
    bool dsdMode = m_cachedDsdMode;
    bool pack24bit = m_cachedPack24bit;
    bool upsample16to32 = m_cachedUpsample16to32;
    bool upsample16to24 = m_cachedUpsample16to24;
    int numChannels = m_cachedChannels;
    int bytesPerSample = m_cachedBytesPerSample;

    size_t written = 0;
    size_t totalBytes;
    const char* formatLabel;

    if (dsdMode) {
        // DSD: numSamples encoding from AudioEngine
        // numSamples = (totalBytes * 8) / channels
        // Reverse: totalBytes = numSamples * channels / 8
        totalBytes = (numSamples * numChannels) / 8;

        // Use optimized path with cached conversion mode (no per-iteration branching)
        written = m_ringBuffer.pushDSDPlanarOptimized(
            data, totalBytes, numChannels, m_cachedDsdConversionMode);
        formatLabel = "DSD";

    } else if (pack24bit) {
        // PCM 24-bit: numSamples is sample count
        size_t bytesPerFrame = 4 * numChannels;  // S24_P32
        totalBytes = numSamples * bytesPerFrame;

        written = m_ringBuffer.push24BitPacked(data, totalBytes);
        formatLabel = "PCM24";

    } else if (upsample16to32) {
        // PCM 16->32
        size_t bytesPerFrame = 2 * numChannels;
        totalBytes = numSamples * bytesPerFrame;

        written = m_ringBuffer.push16To32(data, totalBytes);
        formatLabel = "PCM16->32";

    } else if (upsample16to24) {
        // PCM 16->24 (sink only supports 24-bit, not 32-bit)
        size_t bytesPerFrame = 2 * numChannels;
        totalBytes = numSamples * bytesPerFrame;

        written = m_ringBuffer.push16To24(data, totalBytes);
        formatLabel = "PCM16->24";

    } else {
        // PCM direct copy
        size_t bytesPerFrame = static_cast<size_t>(bytesPerSample) * numChannels;
        totalBytes = numSamples * bytesPerFrame;

        written = m_ringBuffer.push(data, totalBytes);
        formatLabel = "PCM";
    }

    // Check prefill completion
    if (written > 0) {
        if (!m_prefillComplete.load(std::memory_order_acquire)) {
            if (m_ringBuffer.getAvailable() >= m_prefillTarget) {
                m_prefillComplete = true;
                DIRETTA_LOG(formatLabel << " prefill complete: " << m_ringBuffer.getAvailable() << " bytes");
            }
        }

        if (g_verbose) {
            int count = m_pushCount.fetch_add(1, std::memory_order_relaxed) + 1;
            if (count <= 3 || count % 500 == 0) {
                // A3: Async logging in hot path - zero heap allocation
                DIRETTA_LOG_ASYNC_FMT("sendAudio #%d in=%zu out=%zu avail=%zu [%s]",
                                      count, totalBytes, written,
                                      m_ringBuffer.getAvailable(), formatLabel);
            }
        }
    }

    return written;
}

float DirettaSync::getBufferLevel() const {
    RingAccessGuard ringGuard(m_ringUsers, m_reconfiguring);
    if (!ringGuard.active()) return 0.0f;
    size_t size = m_ringBuffer.size();
    if (size == 0) return 0.0f;
    return static_cast<float>(m_ringBuffer.getAvailable()) / static_cast<float>(size);
}

void DirettaSync::dumpStats() const {
    std::cout << "\n════════════════════════════════════════" << std::endl;
    std::cout << "[DirettaSync] Runtime Statistics" << std::endl;
    std::cout << "════════════════════════════════════════" << std::endl;
    std::cout << "  State:       "
              << (m_playing.load(std::memory_order_relaxed) ? "PLAYING" :
                  m_paused.load(std::memory_order_relaxed) ? "PAUSED" :
                  m_open.load(std::memory_order_relaxed) ? "OPEN" : "STOPPED")
              << std::endl;
    const auto& fmt = m_currentFormat;
    if (m_open.load(std::memory_order_relaxed)) {
        std::cout << "  Format:      " << fmt.sampleRate << "Hz/"
                  << fmt.bitDepth << "bit/" << fmt.channels << "ch "
                  << (fmt.isDSD ? "DSD" : "PCM") << std::endl;
    }
    size_t ringSize = m_ringBuffer.size();
    size_t avail = m_ringBuffer.getAvailable();
    float fillPct = ringSize > 0 ? (100.0f * avail / ringSize) : 0.0f;
    std::cout << "  Buffer:      " << avail << "/" << ringSize
              << " bytes (" << std::fixed << std::setprecision(1) << fillPct << "%)" << std::endl;
    std::cout << "  MTU:         " << m_effectiveMTU << std::endl;
    std::cout << "  Streams:     " << m_streamCount.load(std::memory_order_relaxed) << std::endl;
    std::cout << "  Pushes:      " << m_pushCount.load(std::memory_order_relaxed) << std::endl;
    std::cout << "  Underruns:   " << m_underrunCount.load(std::memory_order_relaxed) << std::endl;
    std::cout << "════════════════════════════════════════\n" << std::endl;
}

//=============================================================================
// DIRETTA::Sync Overrides
//=============================================================================

bool DirettaSync::getNewStream(diretta_stream& baseStream) {
    // SDK 148 WORKAROUND: Do NOT use DIRETTA::Stream class methods!
    // After Stop→Play (track change), SDK 148's Stream objects are corrupted.
    // Any method call (resize, get_16, etc.) causes segfault.
    // Solution: Use our own persistent buffer and directly set diretta_stream fields.

    m_workerActive = true;

    // C1: Generation counter optimization for stable state
    // Single atomic load in common case (format rarely changes during playback)
    uint32_t gen = m_consumerStateGen.load(std::memory_order_acquire);
    if (gen != m_cachedConsumerGen) {
        // Cold path: reload stable state values
        m_cachedBytesPerBuffer = m_bytesPerBuffer.load(std::memory_order_acquire);
        m_cachedSilenceByte = m_ringBuffer.silenceByte();
        m_cachedConsumerIsDsd = m_isDsdMode.load(std::memory_order_acquire);
        m_cachedConsumerSampleRate = m_sampleRate.load(std::memory_order_acquire);
        // PCM buffer rounding drift fix values (stable per-track)
        m_cachedBytesPerFrame = m_bytesPerFrame.load(std::memory_order_acquire);
        m_cachedFramesPerBufferRemainder = m_framesPerBufferRemainder.load(std::memory_order_acquire);
        m_cachedConsumerGen = gen;
    }

    // Hot path: use cached values
    int currentBytesPerBuffer = m_cachedBytesPerBuffer;
    uint8_t currentSilenceByte = m_cachedSilenceByte;

    // PCM buffer rounding drift fix: accumulator adjusts buffer size for 44.1k family
    // Uses cached remainder/bytesPerFrame, only accumulator is per-call
    if (m_cachedFramesPerBufferRemainder != 0) {
        uint32_t acc = m_framesPerBufferAccumulator.load(std::memory_order_relaxed);
        acc += m_cachedFramesPerBufferRemainder;
        if (acc >= 1000) {
            acc -= 1000;
            currentBytesPerBuffer += m_cachedBytesPerFrame;
        }
        m_framesPerBufferAccumulator.store(acc, std::memory_order_relaxed);
    }

    // SDK 148 WORKAROUND: Use our own buffer instead of Stream::resize()
    // Resize our persistent buffer if needed
    if (m_streamData.size() != static_cast<size_t>(currentBytesPerBuffer)) {
        m_streamData.resize(currentBytesPerBuffer);
    }

    // Directly set the diretta_stream C structure fields
    // The SDK only reads Data.P (pointer) and Size fields
    baseStream.Data.P = m_streamData.data();
    baseStream.Size = currentBytesPerBuffer;

    uint8_t* dest = m_streamData.data();

    RingAccessGuard ringGuard(m_ringUsers, m_reconfiguring);
    if (!ringGuard.active()) {
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_workerActive = false;
        return true;
    }

    bool currentIsDsd = m_cachedConsumerIsDsd;
    size_t currentRingSize = m_ringBuffer.size();

    // Shutdown silence
    int silenceRemaining = m_silenceBuffersRemaining.load(std::memory_order_acquire);
    if (silenceRemaining > 0) {
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_silenceBuffersRemaining.fetch_sub(1, std::memory_order_acq_rel);
        m_workerActive = false;
        return true;
    }

    // Stop requested
    if (m_stopRequested.load(std::memory_order_acquire)) {
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_workerActive = false;
        return true;
    }

    // Prefill not complete
    if (!m_prefillComplete.load(std::memory_order_acquire)) {
        // Diagnostic: Log prefill progress periodically (only in verbose mode)
        if (g_verbose) {
            static int prefillLogCount = 0;
            size_t avail = m_ringBuffer.getAvailable();
            if (prefillLogCount++ % 50 == 0) {  // Log every 50th call (~100ms at typical rates)
                float pct = (m_prefillTarget > 0) ? (100.0f * avail / m_prefillTarget) : 0.0f;
                std::cout << "[Prefill] Waiting: " << avail << "/" << m_prefillTarget
                          << " bytes (" << std::fixed << std::setprecision(1) << pct << "%)"
                          << (currentIsDsd ? " [DSD]" : " [PCM]") << std::endl;
            }
        }
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_workerActive = false;
        return true;
    }

    // Post-online stabilization
    // Scale stabilization to achieve consistent WARMUP TIME regardless of MTU
    // With small MTU (1500), getNewStream() is called more frequently (shorter cycle time)
    // With large MTU (9000+), calls are less frequent (longer cycle time)
    // We need to scale buffer count to achieve target warmup duration
    if (!m_postOnlineDelayDone.load(std::memory_order_acquire)) {
        int stabilizationTarget = static_cast<int>(DirettaBuffer::POST_ONLINE_SILENCE_BUFFERS);

        if (currentIsDsd) {
            // Target warmup time scales with DSD rate:
            // DSD64: 50ms, DSD128: 100ms, DSD256: 200ms, DSD512: 400ms
            // C1: Use cached sample rate from generation counter
            int currentSampleRate = m_cachedConsumerSampleRate;
            int dsdMultiplier = currentSampleRate / 2822400;  // DSD64 = 1
            int targetWarmupMs = 50 * std::max(1, dsdMultiplier);  // 50ms baseline

            // Calculate cycle time based on MTU and data rate
            // cycleTime = (efficientMTU / bytesPerSecond) in microseconds
            int efficientMTU = static_cast<int>(m_effectiveMTU) - DirettaCycleCalculator::OVERHEAD;
            double bytesPerSecond = static_cast<double>(currentSampleRate) * 2 / 8.0;  // 2ch, 1bit
            double cycleTimeUs = (static_cast<double>(efficientMTU) / bytesPerSecond) * 1000000.0;

            // Calculate buffers needed for target warmup time
            // targetWarmupMs * 1000 = warmup in microseconds
            double buffersNeeded = (targetWarmupMs * 1000.0) / cycleTimeUs;
            stabilizationTarget = static_cast<int>(std::ceil(buffersNeeded));

            // Clamp to reasonable range
            stabilizationTarget = std::max(50, std::min(stabilizationTarget, 3000));
        }

        int count = m_stabilizationCount.fetch_add(1, std::memory_order_relaxed) + 1;
        if (count >= stabilizationTarget) {
            m_postOnlineDelayDone = true;
            m_stabilizationCount.store(0, std::memory_order_relaxed);
            DIRETTA_LOG("Post-online stabilization complete (" << count << " buffers)");
        }
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_workerActive = false;
        return true;
    }

    int count = m_streamCount.fetch_add(1, std::memory_order_relaxed) + 1;
    size_t avail = m_ringBuffer.getAvailable();

    if (g_verbose && (count <= 5 || count % 5000 == 0)) {
        float fillPct = (currentRingSize > 0) ? (100.0f * avail / currentRingSize) : 0.0f;
        // A3: Async logging in hot path - zero heap allocation
        DIRETTA_LOG_ASYNC_FMT("getNewStream #%d bpb=%d avail=%zu (%.1f%%) [%s]",
                              count, currentBytesPerBuffer, avail, fillPct,
                              currentIsDsd ? "DSD" : "PCM");
    }

    // Rebuffering: hold silence until buffer recovers to threshold
    // Prevents stuttering ("CD skip" effect) when small data bursts trickle in
    // during a network stall — accumulates data for a clean resumption
    if (m_rebuffering.load(std::memory_order_acquire)) {
        float pct = (m_cachedConsumerSampleRate > static_cast<int>(DirettaBuffer::HIGHRATE_THRESHOLD))
                  ? DirettaBuffer::REBUFFER_THRESHOLD_PCT_HIGHRATE
                  : DirettaBuffer::REBUFFER_THRESHOLD_PCT;
        size_t threshold = static_cast<size_t>(currentRingSize * pct);
        if (avail >= threshold) {
            m_rebuffering.store(false, std::memory_order_release);
            LOG_WARN("[DirettaSync] Rebuffering complete — resuming playback (avail="
                     << avail << ", threshold=" << threshold << ")");
            // Fall through to normal pop below
        } else {
            std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
            m_workerActive = false;
            return true;
        }
    }

    // Underrun detection — enter rebuffering mode for clean silence
    if (avail < static_cast<size_t>(currentBytesPerBuffer)) {
        m_underrunCount.fetch_add(1, std::memory_order_relaxed);
        if (!m_rebuffering.load(std::memory_order_relaxed)) {
            m_rebuffering.store(true, std::memory_order_release);
            LOG_WARN("[DirettaSync] Buffer underrun — entering rebuffering mode (avail=" << avail << ")");
        }
        std::memset(dest, currentSilenceByte, currentBytesPerBuffer);
        m_workerActive = false;
        return true;
    }

    // Pop from ring buffer
    m_ringBuffer.pop(dest, currentBytesPerBuffer);

    // G1: Signal producer that space is now available
    // Use try_lock to avoid blocking the time-critical consumer thread
    // If producer isn't waiting, this is a no-op (harmless notification)
    if (m_flowMutex.try_lock()) {
        m_flowMutex.unlock();
        m_spaceAvailable.notify_one();
    }

    m_workerActive = false;
    return true;
}

bool DirettaSync::startSyncWorker() {
    std::lock_guard<std::mutex> lock(m_workerMutex);

    DIRETTA_LOG("startSyncWorker (running=" << m_running.load() << ")");

    if (m_running.load() && m_workerThread.joinable()) {
        DIRETTA_LOG("Worker already running");
        return true;
    }

    if (m_workerThread.joinable()) {
        m_workerThread.join();
    }

    m_running = true;
    m_stopRequested = false;

    m_workerThread = std::thread([this]() {
        // F1: Elevate worker thread priority for reduced jitter
        // SCHED_FIFO priority 50 (mid-range real-time) - requires root/CAP_SYS_NICE
        setRealtimePriority(g_rtPriority);

        // Pin worker thread to cpuAudio core (belt and suspenders with SDK
        // cpuMain which doesn't always work, e.g., on RPi 4)
        if (m_config.cpuAudio >= 0) {
            cpu_set_t cpuset;
            CPU_ZERO(&cpuset);
            CPU_SET(m_config.cpuAudio, &cpuset);
            if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0) {
                std::cout << "[DirettaSync] Worker thread pinned to CPU core "
                          << m_config.cpuAudio << std::endl;
            } else {
                std::cerr << "[DirettaSync] WARNING: Failed to pin worker to core "
                          << m_config.cpuAudio << std::endl;
            }
        }

        while (m_running.load(std::memory_order_acquire)) {
            if (!syncWorker()) {
                std::this_thread::sleep_for(std::chrono::microseconds(100));
            }
        }
    });

    return true;
}

//=============================================================================
// Internal Helpers
//=============================================================================

void DirettaSync::beginReconfigure() {
    m_reconfiguring.store(true, std::memory_order_release);
    while (m_ringUsers.load(std::memory_order_acquire) > 0) {
        std::this_thread::yield();
    }
}

void DirettaSync::endReconfigure() {
    m_reconfiguring.store(false, std::memory_order_release);
}

void DirettaSync::shutdownWorker() {
    m_stopRequested = true;
    joinWorkerWithTimeout(1000);
}

bool DirettaSync::joinWorkerWithTimeout(int timeoutMs) {
    m_running = false;

    // Wait for worker to exit syncWorker() with timeout
    int waitCount = 0;
    int maxWaits = timeoutMs / 10;
    while (m_workerActive.load(std::memory_order_acquire) && waitCount < maxWaits) {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        waitCount++;
    }

    if (m_workerActive.load(std::memory_order_acquire)) {
        std::cerr << "[DirettaSync] WARNING: Worker thread did not exit within "
                  << timeoutMs << "ms" << std::endl;
    }

    std::lock_guard<std::mutex> lock(m_workerMutex);
    if (m_workerThread.joinable()) {
        m_workerThread.join();
    }

    return !m_workerActive.load(std::memory_order_acquire);
}

void DirettaSync::requestShutdownSilence(int buffers) {
    // N7: Scale silence buffers with DSD rate for consistent flush timing
    // Higher DSD rates have deeper pipelines requiring more buffers
    int scaledBuffers = buffers;
    if (m_isDsdMode.load(std::memory_order_relaxed)) {
        int sampleRate = m_sampleRate.load(std::memory_order_relaxed);
        int dsdMultiplier = sampleRate / 2822400;  // DSD64=1, DSD512=8
        scaledBuffers = buffers * std::max(1, dsdMultiplier);
    }

    m_silenceBuffersRemaining = scaledBuffers;
    m_draining = true;
    DIRETTA_LOG("Requested " << scaledBuffers << " shutdown silence buffers"
                << (scaledBuffers != buffers ? " (scaled from " + std::to_string(buffers) + ")" : ""));
}

bool DirettaSync::waitForOnline(unsigned int timeoutMs) {
    auto start = std::chrono::steady_clock::now();
    auto timeout = std::chrono::milliseconds(timeoutMs);

    while (!is_online()) {
        if (std::chrono::steady_clock::now() - start > timeout) {
            DIRETTA_LOG("Online timeout");
            return false;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }

    auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::steady_clock::now() - start).count();
    DIRETTA_LOG("Online after " << elapsed << "ms");
    return true;
}

void DirettaSync::applyTransferMode(DirettaTransferMode mode, ACQUA::Clock cycleTime) {
    // Resolve AUTO mode
    DirettaTransferMode effectiveMode = mode;
    if (mode == DirettaTransferMode::AUTO) {
        if (m_isLowBitrate.load(std::memory_order_acquire) ||
            m_isDsdMode.load(std::memory_order_acquire)) {
            effectiveMode = DirettaTransferMode::VAR_AUTO;
        } else {
            effectiveMode = DirettaTransferMode::VAR_MAX;
        }
    }

    // Helper: build minCycle for RANDOM mode
    auto getMinCycle = [this]() {
        return (m_config.cycleMinTime > 0)
            ? ACQUA::Clock::MicroSeconds(m_config.cycleMinTime)
            : ACQUA::Clock::MicroSeconds(333);
    };

    // TargetProfile path: use ProfileMaker for target-adaptive transfer
    if (m_config.targetProfileLimitTime > 0) {
        ACQUA::Clock limitCycle = ACQUA::Clock::MicroSeconds(m_config.targetProfileLimitTime);
        auto pm = getProfileMaker(limitCycle);

        switch (effectiveMode) {
            case DirettaTransferMode::FIX_AUTO:
                DIRETTA_LOG("Using TargetProfile FixAuto (limit=" << m_config.targetProfileLimitTime << "us)");
                pm.configTransferFixAuto(cycleTime);
                break;
            case DirettaTransferMode::RANDOM: {
                ACQUA::Clock minCycle = getMinCycle();
                DIRETTA_LOG("Using TargetProfile Random (limit=" << m_config.targetProfileLimitTime
                            << "us, min=" << m_config.cycleMinTime << "us)");
                pm.configTransferRandom(minCycle, cycleTime, 1);
                break;
            }
            case DirettaTransferMode::VAR_MAX:
                DIRETTA_LOG("Using TargetProfile VarMax (limit=" << m_config.targetProfileLimitTime << "us)");
                pm.configTransferSizeMax();
                break;
            case DirettaTransferMode::VAR_AUTO:
            default:
                DIRETTA_LOG("Using TargetProfile VarAuto (limit=" << m_config.targetProfileLimitTime << "us)");
                pm.configTransferVarAuto(cycleTime);
                break;
        }

        setConfigTransfer(static_cast<DIRETTA::Profile>(pm));
        return;
    }

    // SelfProfile path: direct Sync method calls (no target adaptation)
    switch (effectiveMode) {
        case DirettaTransferMode::FIX_AUTO:
            DIRETTA_LOG("Using FixAuto");
            configTransferFixAuto(cycleTime);
            break;
        case DirettaTransferMode::VAR_AUTO:
            DIRETTA_LOG("Using VarAuto");
            configTransferVarAuto(cycleTime);
            break;
        case DirettaTransferMode::RANDOM: {
            ACQUA::Clock minCycle = getMinCycle();
            DIRETTA_LOG("Using Random (min=" << m_config.cycleMinTime
                        << "us, max=" << cycleTime.getMicroSeconds() << "us)");
            configTransferRandom(minCycle, cycleTime, 1);
            break;
        }
        case DirettaTransferMode::VAR_MAX:
        default:
            DIRETTA_LOG("Using VarMax");
            configTransferVarMax(cycleTime);
            break;
    }
}

unsigned int DirettaSync::calculateCycleTime(uint32_t sampleRate, int channels, int bitsPerSample) {
    if (!m_config.cycleTimeAuto || !m_calculator) {
        return m_config.cycleTime;
    }
    return m_calculator->calculate(sampleRate, channels, bitsPerSample);
}
