rust-tts-wrapper 1.6.1

Cross-platform TTS wrapper with C API — mirrors js-tts-wrapper / SwiftTTSWrapper
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy, rustfmt
      - name: Install system dependencies
        run: sudo apt-get update && sudo apt-get install -y libspeechd-dev libclang-dev

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Clippy (Linux features)
        run: cargo clippy --no-default-features --features system,cloud -- -D warnings

      - name: Clippy (floravox)
        run: cargo clippy --no-default-features --features floravox -- -D warnings

      - name: Build (Linux features)
        run: cargo build --no-default-features --features system,cloud

      - name: Run tests
        run: cargo test --no-default-features --features system,cloud

      - name: Build cloud-only
        run: cargo build --no-default-features --features cloud

      - name: Build + test floravox
        # ort's static prebuilts download per-platform and can 504 (same
        # flakiness as the sherpaonnx builds) — non-blocking until proven.
        continue-on-error: true
        run: |
          cargo build --no-default-features --features floravox
          cargo test --no-default-features --features floravox --lib

      - name: Upload C header
        uses: actions/upload-artifact@v4
        with:
          name: tts_wrapper_header
          path: include/tts_wrapper.h

  # ── Library-dependent offline engines ─────────────────────────────
  # qwen3-local, omnivoice-local, and pocket-timing each need an external
  # shared library built from source. Build once per push/PR, cache the
  # artifacts, then clippy + test each feature.
  offline-engines:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - engine: qwen3-local
            repo: predict-woo/qwen3-tts.cpp
            build_flags: ""
            env_var: QWEN3_TTS_LIB
          - engine: omnivoice-local
            repo: ServeurpersoCom/omnivoice.cpp
            build_flags: "-DGGML_BLAS=ON -DOMNIVOICE_SHARED=ON"
            env_var: OMNIVOICE_LIB
          - engine: pocket-timing
            repo: none
            build_flags: ""
            env_var: none
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      # pocket-timing has no external library (ort downloads prebuilts)
      - name: Clippy + test (pocket-timing)
        if: matrix.engine == 'pocket-timing'
        run: |
          cargo clippy --no-default-features --features pocket-timing -- -D warnings
          cargo test --no-default-features --features pocket-timing --lib

      - name: Build runtime library
        if: matrix.repo != 'none'
        run: |
          sudo apt-get update && sudo apt-get install -y cmake libopenblas-dev
          git clone --depth 1 --recurse-submodules https://github.com/${{ matrix.repo }} ~/engine
          cd ~/engine
          # qwen3-tts.cpp expects ggml pre-built in ggml/build/ (it links
          # against those .so files, not via add_subdirectory)
          if [ -d ggml ]; then
            cd ggml
            cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
            cmake --build build -j$(nproc)
            cd ..
          fi
          cmake -S . -B build -DCMAKE_BUILD_TYPE=Release ${{ matrix.build_flags }}
          cmake --build build -j$(nproc)

      - name: Clippy + test (${{ matrix.engine }})
        if: matrix.repo != 'none'
        env:
          QWEN3_TTS_LIB: ${{ matrix.engine == 'qwen3-local' && '/home/runner/engine' || '' }}
          OMNIVOICE_LIB: ${{ matrix.engine == 'omnivoice-local' && '/home/runner/engine' || '' }}
        run: |
          cargo clippy --no-default-features --features ${{ matrix.engine }} -- -D warnings
          cargo test --no-default-features --features ${{ matrix.engine }} --lib

  macos-build:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Clippy (macOS features)
        run: cargo clippy --no-default-features --features avsynth,cloud -- -D warnings

      - name: Build (macOS features)
        run: cargo build --no-default-features --features avsynth,cloud

      - name: Run tests
        run: cargo test --no-default-features --features avsynth,cloud

  mobile-cross-compile:
    # Android + iOS are release platforms now (publish.yml ships .so/.a for
    # them) — catch breakage at PR time. ring/rustls need the NDK clang on
    # Linux; iOS needs Apple clang (macos runner).
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            targets: "aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android"
            android: true
          - os: macos-latest
            targets: "aarch64-apple-ios aarch64-apple-ios-sim"
            android: false
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.targets }}
      - uses: nttld/setup-ndk@v1
        if: matrix.android
        with:
          ndk-version: r27b
          add-to-path: false
      - name: Build all Android targets (cloud only, NDK r27)
        if: matrix.android
        shell: bash
        run: |
          NDK="$ANDROID_NDK_HOME"
          echo "NDK: $NDK"
          test -d "$NDK" || { echo "NDK not found"; exit 1; }
          TC="$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
          set -e
          for T in aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android; do
            case $T in
              armv7-linux-androideabi) TRIPLE=armv7a-linux-androideabi ;;
              *) TRIPLE=$T ;;
            esac
            TUP=$(echo $T | tr a-z- A-Z_)
            # cloud (static ort where a prebuilt exists)
            env CARGO_TARGET_${TUP}_LINKER="$TC/${TRIPLE}24-clang" \
                CC_$T="$TC/${TRIPLE}24-clang" AR_$T="$TC/llvm-ar" \
                cargo build --release --target $T --no-default-features --features cloud
          done
      - name: Build all iOS targets (cloud only, staticlib)
        if: "!matrix.android"
        run: |
          for T in aarch64-apple-ios aarch64-apple-ios-sim; do
            cargo build --release --target $T --no-default-features --features cloud
            # (floravox iOS builds removed — see private fork)
          done

  windows-build:
    runs-on: windows-latest
    continue-on-error: false
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Clippy (Windows features)
        run: cargo clippy --no-default-features --features sapi,cloud -- -D warnings

      - name: Build (Windows features)
        run: cargo build --no-default-features --features sapi,cloud

      - name: Run tests
        run: cargo test --no-default-features --features sapi,cloud