# Architecture

Audio Path Tone Tester is a Windows audio-path diagnostic tool. It is not a
music player. The architecture should preserve low-level backend details instead
of hiding them behind a generic playback abstraction.

## Layers

### App / UI

- Presents backend, device, format, signal, buffer, scheduling, lifecycle, and
  logging controls.
- Shows realtime status, initialization log, playback log, error summary, and
  export actions.
- Current UI is implemented with Dear ImGui + Win32/DX11 and packaged as a
  one-file Windows executable.
- The GUI uses a device-first three-tab diagnostic flow: Output Path, Test
  Conditions, and Logs.

### Core Diagnostic Model

Core types:

- `PlaybackConfig`
- `FormatDescriptor`
- `DeviceInfo`
- `RealtimeStats`
- `DeviceLifecycleState`
- `DiagnosticEvent`
- `DiagnosticBundle`

Implemented components include:

- `src/core/audio_types.h`
- `src/core/device_lifecycle.h`
- `src/core/device_discovery.h`
- `src/core/audio_backend.h`
- `src/core/diagnostic_log.h`
- `src/core/diagnostic_bundle.h`
- `src/core/signal_generator.h`
- `src/backends/null_backend.h`
- `src/backends/wasapi_endpoint_discovery.h`
- `src/backends/wasapi_format_probe.h`
- `src/diagnostics/null_diagnostic_session.h`
- `src/app/diagnostic_ui_state.h`
- `third_party/imgui`

Initial device discovery model:

- `DiscoverySnapshot`: one no-playback discovery capture for a backend or
  synthetic fixture.
- `DeviceCapabilitySnapshot`: one device plus backend-specific identifiers,
  availability, default-role markers, known-problem flag, and capability probe
  records.
- `CapabilityProbeRecord`: discovery-only, format-support, buffer-range,
  latency, or driver-info result with requested/accepted formats, raw API error
  fields, and backend-specific fields.
- The model explicitly records whether a snapshot opened a device, initialized a
  stream, or started a stream. Task 017 snapshots must remain dry-run safe.

### Backend Interface

Planned backend contract:

```cpp
class IAudioBackend {
 public:
  virtual ~IAudioBackend() = default;
  virtual DeviceList enumerateDevices() = 0;
  virtual FormatProbeResult probeFormats(const DeviceInfo& device) = 0;
  virtual InitializeResult initialize(const PlaybackConfig& config) = 0;
  virtual StartResult start() = 0;
  virtual StopResult stop() = 0;
  virtual ResetResult reset() = 0;
  virtual RealtimeStats getRealtimeStats() const = 0;
  virtual BackendError getLastError() const = 0;
  virtual ShutdownResult shutdown() = 0;
};
```

The exact C++ signatures can change when implemented, but the separation of
device enumeration, format probing, initialization, playback, stats, errors, and
shutdown should remain.

### Backends

- `NullBackend`: validates config, generation, buffering, logging, and
  diagnostic export without touching hardware.
- `WasapiEndpointDiscovery`: enumerates render endpoints through Core Audio
  without activating audio clients, initializing streams, or starting playback.
- `WasapiFormatProbe`: activates `IAudioClient` for one explicit endpoint ID
  and runs bounded `GetMixFormat`, `GetDevicePeriod`, and
  `IsFormatSupported` probes without `Initialize` or playback.
- `WasapiBackend`: shared and exclusive PCM first.
- `MMEBackend`: waveOut path.
- `DirectSoundBackend`: legacy DirectSound path.
- `KernelStreamingBackend`: planned low-level KS filter/pin path staged behind
  explicit safety/model, discovery/probe, and playback tasks.
- `AsioBackend`: optional build path gated by `ENABLE_ASIO`.

### Audio Thread Scheduling

The application treats MMCSS as a backend-aware audio-thread setting rather
than a WASAPI-only feature. App-owned render, polling, or stream-service
threads may register and revert on the same thread through the shared
audio-thread scheduling helper. Driver-owned callback threads, such as ASIO
callbacks owned by the vendor driver, are logged as application-owned-thread
only unless a backend later provides a safe same-thread registration path.

## Signal Generation

Planned signal modules:

- PCM 1 kHz sine.
- PCM silence.
- PCM channel assignment tests.
- DoP payload and silence generation.
- Native DSD test stream and silence/idle pattern.

DSD test streams are for path confirmation first, not precision measurement.

Initial implementation:

- Deterministic PCM float32 sine generation.
- PCM float32 silence generation.
- Default 1 kHz, -20 dBFS, stereo.
- Phase-continuous chunked generation.
- Basic channel assignment support.
- `NullBackend` no-hardware generation and realtime stats simulation.

Initial no-hardware diagnostic session:

- Runs `NullBackend` initialize/start/stop/shutdown.
- Records lifecycle, stats, and summary events.
- Can write the deterministic diagnostic bundle directory.
- Opens no real audio device.

## Logging And Bundles

Planned outputs:

- Human-readable initialization/playback log.
- JSONL event log.
- CSV realtime stats.
- `config.json`
- `device_dump.json`
- `format_probe.json`
- `summary.txt`
- Diagnostic zip bundle.

Timestamps should include wall clock and high-resolution monotonic timing.

Initial logging implementation:

- Versioned JSONL-compatible `DiagnosticEvent` schema.
- Lifecycle transition events.
- Runtime stats events.
- Backend-specific string field map for API-specific diagnostics.
- Roundtrip tests and `tests/fixtures/sample_session.jsonl`.
- Directory-based diagnostic bundle writer for no-hardware runs.

Initial UI shell:

- Win32/DX11 Dear ImGui app shell.
- Placeholder diagnostic controls and log/status panes.
- No-hardware `Run Null` and `Export Null Bundle` actions.
- No-real-API discovery snapshot load/select state for future backend
  enumeration results.
- Real-device controls remain disabled; no audio-device enumeration or playback.

## Device Safety

All backend implementations must obey `docs/DEVICE_STABILITY_POLICY.md`.
Lifecycle behavior is not incidental plumbing; it is part of the diagnostic
surface.
