Building sb-send for Windows
============================

This document explains how to cross-compile sb-send for Windows
from a Linux host. You do not need a Windows machine to build.

Prerequisites
-------------

You need two things:

1. The llvm-mingw cross-compiler toolchain
2. Opus libraries pre-built for Windows

Both are available as pre-built packages. You do not need to
compile them from source.

Step 1: Get the llvm-mingw toolchain
-------------------------------------

Download the latest release from:
https://github.com/mstorsjo/llvm-mingw/releases

Get the Ubuntu x86 64 package (the "ucrt" variant). Extract it
somewhere, for example:

    cd /opt
    tar xf llvm-mingw-20240619-ucrt-ubuntu-22.04-x86_64.tar.xz

You need the bin directory to contain compilers like:
    x86 64-w64-mingw32-clang
    aarch64-w64-mingw32-clang

Step 2: Get pre-built Opus for Windows
---------------------------------------

You can build Opus from source using the same toolchain, or
download pre-built static libraries.

To build from source:

    # Get opus source
    cd /tmp
    git clone https://github.com/xiph/opus.git
    cd opus

    # Build for x86 64
    mkdir build-x64 && cd build-x64
    cmake .. \
      -DCMAKE_SYSTEM_NAME=Windows \
      -DCMAKE_C_COMPILER=x86 64-w64-mingw32-clang \
      -DCMAKE_AR=x86 64-w64-mingw32-llvm-ar \
      -DCMAKE_RANLIB=x86 64-w64-mingw32-llvm-ranlib \
      -DCMAKE_C_FLAGS="-O3" \
      -DOPUS_BUILD_SHARED_LIBRARY=OFF \
      -DOPUS_BUILD_TESTING=OFF \
      -DCMAKE_BUILD_TYPE=Release
    cmake --build . -j$(nproc)
    # Result: libopus.a in the build directory

    # Build for aarch64 (repeat with aarch64 compiler)
    cd /tmp/opus
    mkdir build-arm64 && cd build-arm64
    cmake .. \
      -DCMAKE_SYSTEM_NAME=Windows \
      -DCMAKE_C_COMPILER=aarch64-w64-mingw32-clang \
      -DCMAKE_AR=aarch64-w64-mingw32-llvm-ar \
      -DCMAKE_RANLIB=aarch64-w64-mingw32-llvm-ranlib \
      -DCMAKE_C_FLAGS="-O3" \
      -DOPUS_BUILD_SHARED_LIBRARY=OFF \
      -DOPUS_BUILD_TESTING=OFF \
      -DCMAKE_BUILD_TYPE=Release
    cmake --build . -j$(nproc)

You need:
    libopus.a      (the static library)
    include/opus/  (the header files: opus.h, opus multistream.h, etc.)

Step 3: Edit the Makefile
--------------------------

Open the Makefile and update these paths to match your setup:

    TOOLCHAIN = /path/to/your/llvm-mingw
    OPUS X64 = /path/to/opus/build-x64
    OPUS ARM64 = /path/to/opus/build-arm64

Step 4: Build
-------------

    # Build for Windows x86 64
    make sb-send-win64.exe

    # Build for Windows ARM64
    make sb-send-winarm64.exe

    # Build both
    make win

The output files are:
    sb-send-win64.exe     (about 800K, statically linked)
    sb-send-winarm64.exe  (about 730K, statically linked)

Step 5: Deploy
--------------

Copy the .exe file to your Windows machine. It has no runtime
dependencies. No DLLs needed. No Visual C++ runtime needed.

Run from a command prompt:

    sb-send-win64.exe -g mygroup -s server.example.com -a "Microphone (USB)"

To list available audio devices:

    sb-send-win64.exe --list

To use stdin (pipe audio from ffmpeg or sox):

    sox input.wav -t raw -r 48000 -e s -b 16 -c 1 - | sb-send-win64.exe -a -

Troubleshooting
---------------

If the build fails with "cannot find -lopus":
    Make sure OPUS X64 or OPUS ARM64 points to the directory
    containing libopus.a and include/opus/.

If the build fails with "cannot find -lws2 32":
    Make sure you are using the llvm-mingw compilers, not your
    system gcc. The -lws2 32 flag is a Windows library.

If sb-send connects but no audio is heard:
    Make sure the -a device name matches exactly what --list shows.
    The device name must include parentheses if present in the
    listing, e.g. "Microphone (USB Audio Device)".

If sb-send exits immediately with -a:
    Check that the device name is correct. Try --list to see
    available devices. Some devices do not support 48kHz float
    capture. The program will fall back to the device native
    format and print a message about the actual format used.

If audio has dropouts:
    Try -a - for stdin mode and pipe audio from another program.
    Stdin mode has a larger buffer (1 second) which absorbs
    timing jitter better than direct device capture (200ms).
