From 0a4969ffe24ffede557b6bc79515fb506eab408b Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Tue, 19 Aug 2025 23:06:28 +0200 Subject: [PATCH] feat: add configurable TLS backend selection with native-tls as default (#1541) Add support for choosing between native-tls and rustls-tls backends through feature flags, with native-tls as the default for maximum platform compatibility. Key changes: - Add mutually exclusive native-tls and rustls-tls feature flags - Use conditional compilation to select TLS implementation - Configure rustls-tls with platform certificate verifier - Refactor to workspace-based dependency management - Update CI workflows with improved cross-compilation support - Add comprehensive TLS backend documentation The native-tls backend uses system TLS libraries (OpenSSL on Linux, Secure Transport on macOS, SChannel on Windows) while rustls-tls provides a pure Rust implementation with platform certificate stores. --- .devcontainer/Dockerfile | 1 - .devcontainer/Dockerfile.alpine | 1 - .devcontainer/devcontainer.json | 34 ++-- .github/workflows/build.yml | 99 +++++++++ .github/workflows/cross-compile.yml | 78 +++++++ .github/workflows/quality.yml | 79 ++++++++ .github/workflows/test.yml | 281 -------------------------- CHANGELOG.md | 2 +- COMPILING.md | 71 ++++++- Cargo.lock | 212 +++++++++++++++++-- Cargo.toml | 224 +++++++++++++------- Cross.toml | 12 ++ README.md | 10 +- audio/Cargo.toml | 24 ++- audio/src/fetch/mod.rs | 10 +- connect/Cargo.toml | 34 ++-- core/Cargo.toml | 76 ++++--- core/src/http_client.rs | 21 +- discovery/Cargo.toml | 36 ++-- discovery/examples/discovery.rs | 2 +- discovery/examples/discovery_group.rs | 2 +- metadata/Cargo.toml | 31 +-- metadata/src/lib.rs | 2 +- metadata/src/request.rs | 2 +- oauth/Cargo.toml | 28 ++- oauth/examples/oauth_async.rs | 2 +- oauth/examples/oauth_sync.rs | 2 +- oauth/src/lib.rs | 41 +++- playback/Cargo.toml | 76 ++++--- playback/src/mixer/mappings.rs | 2 +- protocol/Cargo.toml | 10 +- 31 files changed, 928 insertions(+), 577 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/cross-compile.yml create mode 100644 .github/workflows/quality.yml delete mode 100644 .github/workflows/test.yml create mode 100644 Cross.toml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d7594a55..9860815f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -8,7 +8,6 @@ ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL="sparse" ENV RUST_BACKTRACE=1 ENV RUSTFLAGS="-D warnings" - RUN apt-get update && \ apt-get install -y --no-install-recommends \ git \ diff --git a/.devcontainer/Dockerfile.alpine b/.devcontainer/Dockerfile.alpine index bec4bb71..2d949ad6 100644 --- a/.devcontainer/Dockerfile.alpine +++ b/.devcontainer/Dockerfile.alpine @@ -7,7 +7,6 @@ ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL="sparse" ENV RUST_BACKTRACE=1 ENV RUSTFLAGS="-D warnings -C target-feature=-crt-static" - RUN apk add --no-cache \ git \ nano\ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c3ab756a..73fa03f4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,24 +1,20 @@ { "name": "Librespot Devcontainer", "dockerFile": "Dockerfile.alpine", - // Use 'postCreateCommand' to run commands after the container is created. - //"postCreateCommand": "", - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - "settings": { - "dev.containers.copyGitConfig": true - }, - "extensions": [ - "eamodio.gitlens", - "github.vscode-github-actions", - "rust-lang.rust-analyzer" - ] - } - }, + "_postCreateCommand_comment": "Uncomment 'postCreateCommand' to run commands after the container is created.", + "_postCreateCommand": "", + "customizations": { + "_comment": "Configure properties specific to VS Code.", + "vscode": { + "settings": { + "dev.containers.copyGitConfig": true + }, + "extensions": ["eamodio.gitlens", "github.vscode-github-actions", "rust-lang.rust-analyzer"] + } + }, "containerEnv": { "GIT_EDITOR": "nano" - } - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" - } + }, + "_remoteUser_comment": "Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root", + "_remoteUser": "root" +} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..dd5e18e7 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ +--- +# Note, this is used in the badge URL! +name: build + +"on": + push: + branches: [dev, master] + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + - "publish.sh" + - "test.sh" + pull_request: + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + - "publish.sh" + - "test.sh" + schedule: + # Run CI every week + - cron: "00 01 * * 0" + +env: + RUST_BACKTRACE: 1 + RUSTFLAGS: -D warnings + +jobs: + test: + name: cargo +${{ matrix.toolchain }} test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + toolchain: + - "1.85" # MSRV (Minimum supported rust version) + - stable + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.toolchain }} + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install developer package dependencies (Linux) + if: runner.os == 'Linux' + run: > + sudo apt-get update && sudo apt-get install -y + libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev + gstreamer1.0-dev libgstreamer-plugins-base1.0-dev + libavahi-compat-libdnssd-dev + + - name: Fetch dependencies + run: cargo fetch --locked + + - name: Build workspace with examples + run: cargo build --frozen --workspace --examples + + - name: Run tests + run: cargo test --workspace + + - name: Install cargo-hack + uses: taiki-e/install-action@cargo-hack + + - name: Check packages without TLS requirements + run: cargo hack check -p librespot-protocol --each-feature + + - name: Check workspace with native-tls + run: > + cargo hack check -p librespot --each-feature --exclude-all-features + --include-features native-tls --exclude-features rustls-tls + + - name: Check workspace with rustls-tls + run: > + cargo hack check -p librespot --each-feature --exclude-all-features + --include-features rustls-tls --exclude-features native-tls + + - name: Build binary with default features + run: cargo build --frozen + + - name: Upload debug artifacts + uses: actions/upload-artifact@v4 + with: + name: librespot-${{ matrix.os }}-${{ matrix.toolchain }} + path: > + target/debug/librespot${{ runner.os == 'Windows' && '.exe' || '' }} + if-no-files-found: error diff --git a/.github/workflows/cross-compile.yml b/.github/workflows/cross-compile.yml new file mode 100644 index 00000000..f5befd82 --- /dev/null +++ b/.github/workflows/cross-compile.yml @@ -0,0 +1,78 @@ +--- +name: cross-compile + +"on": + push: + branches: [dev, master] + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + pull_request: + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + +env: + RUST_BACKTRACE: 1 + RUSTFLAGS: -D warnings + +jobs: + cross-compile: + name: cross +${{ matrix.toolchain }} build ${{ matrix.platform.target }} + runs-on: ${{ matrix.platform.runs-on }} + continue-on-error: false + strategy: + matrix: + platform: + - arch: armv7 + runs-on: ubuntu-latest + target: armv7-unknown-linux-gnueabihf + + - arch: aarch64 + runs-on: ubuntu-latest + target: aarch64-unknown-linux-gnu + + - arch: riscv64gc + runs-on: ubuntu-latest + target: riscv64gc-unknown-linux-gnu + + toolchain: + - "1.85" # MSRV (Minimum Supported Rust Version) + - stable + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Build binary with default features + if: matrix.platform.target != 'riscv64gc-unknown-linux-gnu' + uses: houseabsolute/actions-rust-cross@v1 + with: + command: build + target: ${{ matrix.platform.target }} + toolchain: ${{ matrix.toolchain }} + args: --locked --verbose + + - name: Build binary with rustls-tls and no default features + if: matrix.platform.target == 'riscv64gc-unknown-linux-gnu' + uses: houseabsolute/actions-rust-cross@v1 + with: + command: build + target: ${{ matrix.platform.target }} + toolchain: ${{ matrix.toolchain }} + args: --locked --verbose --no-default-features --features rustls-tls + + - name: Upload debug artifacts + uses: actions/upload-artifact@v4 + with: + name: librespot-${{ matrix.platform.runs-on }}-${{ matrix.platform.arch }}-${{ matrix.toolchain }} # yamllint disable-line rule:line-length + path: target/${{ matrix.platform.target }}/debug/librespot + if-no-files-found: error diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 00000000..7b42d163 --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,79 @@ +--- +name: code-quality + +"on": + push: + branches: [dev, master] + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + pull_request: + paths-ignore: + - "**.md" + - "docs/**" + - "contrib/**" + - "LICENSE" + - "*.sh" + - "**/Dockerfile*" + schedule: + # Run CI every week + - cron: "00 01 * * 0" + +env: + RUST_BACKTRACE: 1 + RUSTFLAGS: -D warnings + +jobs: + fmt: + name: cargo fmt + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Check formatting + run: cargo fmt --all -- --check + + clippy: + needs: fmt + name: cargo clippy + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install developer package dependencies + run: > + sudo apt-get update && sudo apt-get install -y + libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev + gstreamer1.0-dev libgstreamer-plugins-base1.0-dev + libavahi-compat-libdnssd-dev + + - name: Install cargo-hack + uses: taiki-e/install-action@cargo-hack + + - name: Run clippy on packages without TLS requirements + run: cargo hack clippy -p librespot-protocol --each-feature + + - name: Run clippy with native-tls + run: > + cargo hack clippy -p librespot --each-feature --exclude-all-features + --include-features native-tls --exclude-features rustls-tls + + - name: Run clippy with rustls-tls + run: > + cargo hack clippy -p librespot --each-feature --exclude-all-features + --include-features rustls-tls --exclude-features native-tls diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 04332316..00000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,281 +0,0 @@ -# Note, this is used in the badge URL! -name: test - -on: - push: - branches: [dev, master] - paths: - [ - "**.rs", - "Cargo.toml", - "Cargo.lock", - "rustfmt.toml", - ".github/workflows/*", - "!*.md", - "!contrib/*", - "!docs/*", - "!LICENSE", - "!*.sh", - ] - pull_request: - paths: - [ - "**.rs", - "Cargo.toml", - "Cargo.lock", - "rustfmt.toml", - ".github/workflows/*", - "!*.md", - "!contrib/*", - "!docs/*", - "!LICENSE", - "!*.sh", - ] - schedule: - # Run CI every week - - cron: "00 01 * * 0" - -env: - RUST_BACKTRACE: 1 - RUSTFLAGS: -D warnings - -# The layering here is as follows: -# 1. code formatting -# 2. absence of lints -# 3. absence of errors and warnings on Linux/x86 -# 4. cross compilation on Windows and Linux/ARM - -jobs: - fmt: - name: cargo fmt - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - name: Install toolchain - run: curl https://sh.rustup.rs -sSf | sh -s -- --profile default --default-toolchain stable -y - - run: cargo fmt --all -- --check - - clippy: - needs: fmt - name: cargo +${{ matrix.toolchain }} clippy (${{ matrix.os }}) - runs-on: ${{ matrix.os }} - continue-on-error: false - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - toolchain: [stable] - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install toolchain - run: curl https://sh.rustup.rs -sSf | sh -s -- --profile default --default-toolchain ${{ matrix.toolchain }} -y - - - name: Get Rustc version - id: get-rustc-version - run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT - shell: bash - - - name: Cache Rust dependencies - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git - target - key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - - - name: Install developer package dependencies - run: sudo apt-get update && sudo apt install -y libunwind-dev && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavahi-compat-libdnssd-dev - - - run: cargo install cargo-hack - - run: cargo hack --workspace --remove-dev-deps - - run: cargo clippy -p librespot-core --no-default-features - - run: cargo clippy -p librespot-core - - run: cargo hack clippy --each-feature -p librespot-discovery - - run: cargo hack clippy --each-feature -p librespot-playback - - run: cargo hack clippy --each-feature - - test-linux: - name: cargo +${{ matrix.toolchain }} check (${{ matrix.os }}) - runs-on: ${{ matrix.os }} - continue-on-error: ${{ matrix.experimental }} - needs: clippy - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - toolchain: - - "1.85" # MSRV (Minimum supported rust version) - - stable - experimental: [false] - # Ignore failures in beta - include: - - os: ubuntu-latest - toolchain: beta - experimental: true - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Install toolchain - run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y - - - name: Get Rustc version - id: get-rustc-version - run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT - shell: bash - - - name: Cache Rust dependencies - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git - target - key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - - - name: Install developer package dependencies - run: sudo apt-get update && sudo apt install -y libunwind-dev && sudo apt-get install libpulse-dev portaudio19-dev libasound2-dev libsdl2-dev gstreamer1.0-dev libgstreamer-plugins-base1.0-dev libavahi-compat-libdnssd-dev - - - run: cargo fetch --locked - - run: cargo build --frozen --workspace --examples - - run: cargo test --workspace - - - run: cargo install cargo-hack - - run: cargo hack --workspace --remove-dev-deps - - run: cargo check -p librespot-core --no-default-features - - run: cargo check -p librespot-core - - run: cargo hack check --each-feature -p librespot-discovery - - run: cargo hack check --each-feature -p librespot-playback - - run: cargo hack check --each-feature - - test-windows: - needs: clippy - name: cargo +${{ matrix.toolchain }} check (${{ matrix.os }}) - runs-on: ${{ matrix.os }} - continue-on-error: false - strategy: - fail-fast: false - matrix: - os: [windows-latest] - toolchain: - - "1.85" # MSRV (Minimum supported rust version) - - stable - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Install toolchain - run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y - - - name: Get Rustc version - id: get-rustc-version - run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT - shell: bash - - - name: Cache Rust dependencies - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git - target - key: ${{ runner.os }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - - - run: cargo fetch --locked - - run: cargo build --frozen --workspace --examples - - run: cargo test --workspace - - - run: cargo install cargo-hack - - run: cargo hack --workspace --remove-dev-deps - - run: cargo check --no-default-features - - run: cargo check - - test-cross-linux: - name: cross +${{ matrix.toolchain }} build ${{ matrix.target }} - needs: clippy - runs-on: ${{ matrix.os }} - continue-on-error: false - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - target: - - armv7-unknown-linux-gnueabihf - - aarch64-unknown-linux-gnu - - riscv64gc-unknown-linux-gnu - toolchain: - - "1.85" # MSRV (Minimum supported rust version) - - stable - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Install toolchain - run: curl https://sh.rustup.rs -sSf | sh -s -- --profile minimal --default-toolchain ${{ matrix.toolchain }} -y - - - name: Get Rustc version - id: get-rustc-version - run: echo "version=$(rustc -V)" >> $GITHUB_OUTPUT - shell: bash - - - name: Cache Rust dependencies - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git - target - key: ${{ runner.os }}-${{ matrix.target }}-${{ steps.get-rustc-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - - - name: Install the cross compiler rust targets - run: rustup target add ${{ matrix.target }} - - - name: Update and Install dependencies - run: sudo apt-get update && sudo apt-get install -y build-essential cmake libclang1 - - - name: Install bindgen-cli - run: cargo install --force --locked bindgen-cli - - - name: Install cross compiler - run: | - if [ ${{ matrix.target }} = "armv7-unknown-linux-gnueabihf" ]; then - sudo apt-get install -y gcc-arm-linux-gnueabihf - fi - if [ ${{ matrix.target }} = "aarch64-unknown-linux-gnu" ]; then - sudo apt-get install -y gcc-aarch64-linux-gnu - fi - if [ ${{ matrix.target }} = "riscv64gc-unknown-linux-gnu" ]; then - sudo apt-get install -y gcc-riscv64-linux-gnu - fi - - - name: Set target link compiler - run: | - # Convert target to uppercase and replace - with _ - target=${{ matrix.target }} - target=${target^^} - target=${target//-/_} - if [ ${{ matrix.target }} = "armv7-unknown-linux-gnueabihf" ]; then - echo "CARGO_TARGET_${target}_LINKER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV - fi - if [ ${{ matrix.target }} = "aarch64-unknown-linux-gnu" ]; then - echo "CARGO_TARGET_${target}_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV - fi - if [ ${{ matrix.target }} = "riscv64gc-unknown-linux-gnu" ]; then - echo "CARGO_TARGET_${target}_LINKER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV - fi - - - name: Fetch - run: cargo fetch --locked - - name: Build - run: cargo build --frozen --verbose --target ${{ matrix.target }} --no-default-features - - - name: Check binary - run: file target/${{ matrix.target }}/debug/librespot diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bef11c9..5c843571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [core] MSRV is now 1.85 with Rust edition 2024 (breaking) - [core] AP connect and handshake have a combined 5 second timeout. - [core] `stream_from_cdn` now accepts the URL as `TryInto` instead of `CdnUrl` (breaking) -- [core] Moved from native TLS to ring and webpki on all platforms +- [core] Add TLS backend selection with native-tls and rustls-tls options, defaulting to native-tls - [connect] Replaced `has_volume_ctrl` with `disable_volume` in `ConnectConfig` (breaking) - [connect] Changed `initial_volume` from `Option` to `u16` in `ConnectConfig` (breaking) - [connect] Replaced `SpircLoadCommand` with `LoadRequest`, `LoadRequestOptions` and `LoadContextOptions` (breaking) diff --git a/COMPILING.md b/COMPILING.md index 4d238862..8eedca49 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -67,6 +67,63 @@ Depending on the chosen backend, specific development libraries are required. |dns_sd | `libavahi-compat-libdnssd-dev pkg-config` | `avahi-compat-libdns_sd-devel` | | |libmdns (default) | | | | +### TLS library dependencies +librespot requires a TLS implementation for secure connections to Spotify's servers. You can choose between two mutually exclusive options: + +#### native-tls (default) +Uses your system's native TLS implementation: +- **Linux**: OpenSSL +- **macOS**: Secure Transport (Security.framework) +- **Windows**: SChannel (Windows TLS) + +This is the **default choice** and provides the best compatibility. It integrates with your system's certificate store and is well-tested across platforms. + +**When to choose native-tls:** +- You want maximum compatibility +- You're using system-managed certificates +- You're on a standard Linux distribution with OpenSSL +- You're deploying on platforms where OpenSSL is already present + +**Dependencies:** +On Debian/Ubuntu: +```shell +sudo apt-get install libssl-dev pkg-config +``` + +On Fedora: +```shell +sudo dnf install openssl-devel pkg-config +``` + +#### rustls-tls +Uses a Rust-based TLS implementation with `rustls-platform-verifier` for certificate authority (CA) verification: +- **Linux**: Uses system ca-certificates package +- **macOS**: Uses Security.framework for CA verification +- **Windows**: Uses Windows certificate store + +**When to choose rustls-tls:** +- You want to avoid external OpenSSL dependencies +- You're building for reproducible/deterministic builds +- You're targeting platforms where OpenSSL is unavailable or problematic (musl, embedded, static linking) +- You're cross-compiling and want to avoid OpenSSL build complexity +- You prefer having cryptographic operations implemented in Rust + +**No additional system dependencies required** - rustls is implemented in Rust (with some assembly for performance-critical cryptographic operations) and doesn't require external libraries like OpenSSL. + +#### Building with specific TLS backends +```bash +# Default (native-tls) +cargo build + +# Explicitly use native-tls +cargo build --no-default-features --features "native-tls rodio-backend with-libmdns" + +# Use rustls-tls instead +cargo build --no-default-features --features "rustls-tls rodio-backend with-libmdns" +``` + +**Important:** The TLS backends are mutually exclusive. Attempting to enable both will result in a compile-time error. + ### Getting the Source The recommended method is to first fork the repo, so that you have a copy that you have read/write access to. After that, it’s a simple case of cloning your fork. @@ -95,19 +152,21 @@ cargo build --release You will most likely want to build debug builds when developing, as they compile faster, and more verbose, and as the name suggests, are for the purposes of debugging. When submitting a bug report, it is recommended to use a debug build to capture stack traces. -There are also a number of compiler feature flags that you can add, in the event that you want to have certain additional features also compiled. The list of these is available on the [wiki](https://github.com/librespot-org/librespot/wiki/Compiling#addition-features). +There are also a number of compiler feature flags that you can add, in the event that you want to have certain additional features also compiled. All available features and their descriptions are documented in the main [Cargo.toml](Cargo.toml) file. Additional platform-specific information is available on the [wiki](https://github.com/librespot-org/librespot/wiki/Compiling#addition-features). -By default, librespot compiles with the ```rodio-backend``` and ```with-libmdns``` features. To compile without default features, you can run with: +By default, librespot compiles with the ```native-tls```, ```rodio-backend```, and ```with-libmdns``` features. + +**Note:** librespot requires at least one TLS backend to function. Building with `--no-default-features` alone will fail compilation. For custom feature selection, you must specify at least one TLS backend along with your desired audio and discovery backends. +For example, to build with the ALSA audio, libmdns discovery, and native-tls backends: ```bash -cargo build --no-default-features +cargo build --no-default-features --features "native-tls alsa-backend with-libmdns" ``` -Note that this will also disable zeroconf discovery backends for Spotify Connect. For normal use cases, select at least one audio and discovery backend. -For example, to build with the ALSA audio and libmdns discovery backend: +Or to use rustls-tls with ALSA: ```bash -cargo build --no-default-features --features "alsa-backend with-libmdns" +cargo build --no-default-features --features "rustls-tls alsa-backend with-libmdns" ``` ### Running diff --git a/Cargo.lock b/Cargo.lock index cf103a10..1408822f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -369,6 +369,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -735,6 +745,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1289,13 +1314,16 @@ dependencies = [ "http", "hyper", "hyper-rustls 0.26.0", + "hyper-tls", "hyper-util", + "native-tls", "pin-project-lite", + "rustls-native-certs 0.7.3", "tokio", + "tokio-native-tls", "tokio-rustls 0.25.0", "tower-service", "webpki", - "webpki-roots 0.26.11", ] [[package]] @@ -1310,12 +1338,11 @@ dependencies = [ "hyper-util", "log", "rustls 0.22.4", - "rustls-native-certs", + "rustls-native-certs 0.7.3", "rustls-pki-types", "tokio", "tokio-rustls 0.25.0", "tower-service", - "webpki-roots 0.26.11", ] [[package]] @@ -1327,13 +1354,29 @@ dependencies = [ "http", "hyper", "hyper-util", - "log", "rustls 0.23.31", "rustls-pki-types", + "rustls-platform-verifier", "tokio", "tokio-rustls 0.26.2", "tower-service", - "webpki-roots 1.0.2", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] @@ -1866,6 +1909,7 @@ dependencies = [ "hyper", "hyper-proxy2", "hyper-rustls 0.27.7", + "hyper-tls", "hyper-util", "librespot-oauth", "librespot-protocol", @@ -1885,7 +1929,6 @@ dependencies = [ "rand 0.9.2", "rand_distr", "rsa", - "rustls 0.23.31", "serde", "serde_json", "sha1", @@ -1970,7 +2013,6 @@ dependencies = [ "alsa", "cpal", "futures-util", - "glib", "gstreamer", "gstreamer-app", "gstreamer-audio", @@ -2109,6 +2151,23 @@ dependencies = [ "serde", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.9.0" @@ -2304,9 +2363,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" dependencies = [ "objc2-encode", ] @@ -2425,12 +2484,50 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-operations" version = "0.5.0" @@ -2917,15 +3014,16 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "http-body-util", "hyper", "hyper-rustls 0.27.7", + "hyper-tls", "hyper-util", "js-sys", "log", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -2936,6 +3034,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls 0.26.2", "tower", "tower-http", @@ -2944,7 +3043,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 1.0.2", + "webpki-roots", ] [[package]] @@ -3050,7 +3149,6 @@ version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ - "log", "once_cell", "ring", "rustls-pki-types", @@ -3069,7 +3167,19 @@ dependencies = [ "rustls-pemfile", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.3.0", ] [[package]] @@ -3091,6 +3201,33 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.4", + "security-framework 3.3.0", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.102.8" @@ -3179,7 +3316,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -3548,7 +3698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3734,6 +3884,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.25.0" @@ -3774,12 +3934,13 @@ checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" dependencies = [ "futures-util", "log", + "native-tls", "rustls 0.23.31", "rustls-pki-types", "tokio", + "tokio-native-tls", "tokio-rustls 0.26.2", "tungstenite", - "webpki-roots 0.26.11", ] [[package]] @@ -3922,6 +4083,7 @@ dependencies = [ "http", "httparse", "log", + "native-tls", "rand 0.9.2", "rustls 0.23.31", "rustls-pki-types", @@ -4006,6 +4168,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "vergen" version = "9.0.6" @@ -4198,12 +4366,12 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.26.11" +name = "webpki-root-certs" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" dependencies = [ - "webpki-roots 1.0.2", + "rustls-pki-types", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2bdcbb9a..14b72db4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,123 @@ [package] name = "librespot" +version.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +description = "An open source client library for Spotify, with support for Spotify Connect" +keywords = ["audio", "spotify", "music", "streaming", "connect"] +categories = ["multimedia::audio"] +repository.workspace = true +readme = "README.md" +edition.workspace = true +include = [ + "src/**/*", + "audio/**/*", + "connect/**/*", + "core/**/*", + "discovery/**/*", + "metadata/**/*", + "oauth/**/*", + "playback/**/*", + "protocol/**/*", + "Cargo.toml", + "README.md", + "LICENSE", + "COMPILING.md", + "CONTRIBUTING.md", +] + +[workspace.package] version = "0.6.0-dev" rust-version = "1.85" authors = ["Librespot Org"] license = "MIT" -description = "An open source client library for Spotify, with support for Spotify Connect" -keywords = ["spotify"] repository = "https://github.com/librespot-org/librespot" -readme = "README.md" edition = "2024" -[workspace] +[features] +default = ["native-tls", "rodio-backend", "with-libmdns"] + +# TLS backends (mutually exclusive - compile-time checks in oauth/src/lib.rs) +# Note: Feature validation is in oauth crate since it's compiled first in the dependency tree. +# See COMPILING.md for more details on TLS backend selection. + +# native-tls: Uses the system's native TLS stack (OpenSSL on Linux, Secure Transport on macOS, +# SChannel on Windows). This is the default as it's well-tested, widely compatible, and integrates +# with system certificate stores. Choose this for maximum compatibility and when you want to use +# system-managed certificates. +native-tls = ["librespot-core/native-tls", "librespot-oauth/native-tls"] + +# rustls-tls: Uses the Rust-based rustls TLS implementation with platform certificate verification. +# This provides a Rust TLS stack (with assembly optimizations) that uses rustls-platform-verifier to +# automatically select the appropriate certificate authority (CA) certificates from your system's +# trust store. Choose this for avoiding external OpenSSL dependencies, reproducible builds, or when +# targeting platforms where native TLS dependencies are unavailable or problematic (musl, embedded, +# static linking). On Linux it uses ca-certificates, on macOS it uses Security.framework, and on +# Windows it uses the Windows certificate store. +rustls-tls = ["librespot-core/rustls-tls", "librespot-oauth/rustls-tls"] + +# Audio backends - see README.md for audio backend selection guide +# Cross-platform backends: + +# rodio-backend: Cross-platform audio backend using Rodio (default). Provides good cross-platform +# compatibility with automatic backend selection. Uses ALSA on Linux, WASAPI on Windows, CoreAudio +# on macOS. +rodio-backend = ["librespot-playback/rodio-backend"] + +# rodiojack-backend: Rodio backend with JACK support for professional audio setups. +rodiojack-backend = ["librespot-playback/rodiojack-backend"] + +# gstreamer-backend: Uses GStreamer multimedia framework for audio output. +# Provides extensive audio processing capabilities. +gstreamer-backend = ["librespot-playback/gstreamer-backend"] + +# portaudio-backend: Cross-platform audio I/O library backend. +portaudio-backend = ["librespot-playback/portaudio-backend"] + +# sdl-backend: Simple DirectMedia Layer audio backend. +sdl-backend = ["librespot-playback/sdl-backend"] + +# Platform-specific backends: + +# alsa-backend: Advanced Linux Sound Architecture backend (Linux only). +# Provides low-latency audio output on Linux systems. +alsa-backend = ["librespot-playback/alsa-backend"] + +# pulseaudio-backend: PulseAudio backend (Linux only). +# Integrates with the PulseAudio sound server for advanced audio routing. +pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] + +# jackaudio-backend: JACK Audio Connection Kit backend. +# Professional audio backend for low-latency, high-quality audio routing. +jackaudio-backend = ["librespot-playback/jackaudio-backend"] + +# Network discovery backends - choose one for Spotify Connect device discovery +# See COMPILING.md for dependencies and platform support. + +# with-libmdns: Pure-Rust mDNS implementation (default). +# No external dependencies, works on all platforms. Choose this for simple deployments or when +# avoiding system dependencies. +with-libmdns = ["librespot-discovery/with-libmdns"] + +# with-avahi: Uses Avahi daemon for mDNS (Linux only). +# Integrates with system's Avahi service for network discovery. Choose this when you want to +# integrate with existing Avahi infrastructure or need advanced mDNS features. Requires +# libavahi-client-dev. +with-avahi = ["librespot-discovery/with-avahi"] + +# with-dns-sd: Uses DNS Service Discovery (cross-platform). +# On macOS uses Bonjour, on Linux uses Avahi compatibility layer. Choose this for tight system +# integration on macOS or when using Avahi's dns-sd compatibility mode on Linux. +with-dns-sd = ["librespot-discovery/with-dns-sd"] + +# Audio processing features: + +# passthrough-decoder: Enables direct passthrough of Ogg Vorbis streams without decoding. +# Useful for custom audio processing pipelines or when you want to handle audio decoding +# externally. When enabled, audio is not decoded by librespot but passed through as raw Ogg Vorbis +# data. +passthrough-decoder = ["librespot-playback/passthrough-decoder"] [lib] name = "librespot" @@ -21,40 +128,26 @@ name = "librespot" path = "src/main.rs" doc = false -[dependencies.librespot-audio] -path = "audio" -version = "0.6.0-dev" - -[dependencies.librespot-connect] -path = "connect" -version = "0.6.0-dev" - -[dependencies.librespot-core] -path = "core" -version = "0.6.0-dev" - -[dependencies.librespot-discovery] -path = "discovery" -version = "0.6.0-dev" -default-features = false - -[dependencies.librespot-metadata] -path = "metadata" -version = "0.6.0-dev" - -[dependencies.librespot-playback] -path = "playback" -version = "0.6.0-dev" - -[dependencies.librespot-protocol] -path = "protocol" -version = "0.6.0-dev" - -[dependencies.librespot-oauth] -path = "oauth" -version = "0.6.0-dev" +[workspace.dependencies] +librespot-audio = { path = "audio", default-features = false } +librespot-connect = { path = "connect", default-features = false } +librespot-core = { path = "core", default-features = false } +librespot-discovery = { path = "discovery", default-features = false } +librespot-metadata = { path = "metadata", default-features = false } +librespot-oauth = { path = "oauth", default-features = false } +librespot-playback = { path = "playback", default-features = false } +librespot-protocol = { path = "protocol", default-features = false } [dependencies] +librespot-audio.workspace = true +librespot-connect.workspace = true +librespot-core.workspace = true +librespot-discovery.workspace = true +librespot-metadata.workspace = true +librespot-oauth.workspace = true +librespot-playback.workspace = true +librespot-protocol.workspace = true + data-encoding = "2.5" env_logger = { version = "0.11.2", default-features = false, features = [ "color", @@ -77,53 +170,30 @@ tokio = { version = "1", features = [ ] } url = "2.2" -[features] -alsa-backend = ["librespot-playback/alsa-backend"] -portaudio-backend = ["librespot-playback/portaudio-backend"] -pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] -jackaudio-backend = ["librespot-playback/jackaudio-backend"] -rodio-backend = ["librespot-playback/rodio-backend"] -rodiojack-backend = ["librespot-playback/rodiojack-backend"] -sdl-backend = ["librespot-playback/sdl-backend"] -gstreamer-backend = ["librespot-playback/gstreamer-backend"] - -with-avahi = ["librespot-discovery/with-avahi"] -with-dns-sd = ["librespot-discovery/with-dns-sd"] -with-libmdns = ["librespot-discovery/with-libmdns"] - -passthrough-decoder = ["librespot-playback/passthrough-decoder"] - -default = ["rodio-backend", "with-libmdns"] - [package.metadata.deb] -maintainer = "librespot-org" -copyright = "2018 Paul Liétar" +maintainer = "Librespot Organization " +copyright = "2015, Paul Liétar" license-file = ["LICENSE", "4"] depends = "$auto" +recommends = "avahi-daemon" extended-description = """\ librespot is an open source client library for Spotify. It enables applications \ -to use Spotify's service, without using the official but closed-source \ -libspotify. Additionally, it will provide extra features which are not \ -available in the official library.""" +to use Spotify's service to control and play music via various backends, and to \ +act as a Spotify Connect receiver. It is an alternative to the official and now \ +deprecated closed-source libspotify. Additionally, it provides extra features \ +which are not available in the official library. +. +This package provides the librespot binary for headless Spotify Connect playback. \ +. +Note: librespot only works with Spotify Premium accounts.""" section = "sound" priority = "optional" assets = [ - [ - "target/release/librespot", - "usr/bin/", - "755", - ], - [ - "contrib/librespot.service", - "lib/systemd/system/", - "644", - ], - [ - "contrib/librespot.user.service", - "lib/systemd/user/", - "644", - ], + # Main binary + ["target/release/librespot", "usr/bin/", "755"], + # Documentation + ["README.md", "usr/share/doc/librespot/", "644"], + # Systemd services + ["contrib/librespot.service", "lib/systemd/system/", "644"], + ["contrib/librespot.user.service", "lib/systemd/user/", "644"], ] - -[workspace.package] -rust-version = "1.85" diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 00000000..879c5b10 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,12 @@ +[build] +pre-build = [ + "dpkg --add-architecture $CROSS_DEB_ARCH", + "apt-get update", + "apt-get --assume-yes install libssl-dev:$CROSS_DEB_ARCH libasound2-dev:$CROSS_DEB_ARCH", +] + +[target.riscv64gc-unknown-linux-gnu] +# RISC-V: Uses rustls-tls (no system dependencies needed) +# Building with --no-default-features --features rustls-tls +# No pre-build steps required - rustls is pure Rust +pre-build = [] diff --git a/README.md b/README.md index 3ccb19cf..caa00ea0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://github.com/librespot-org/librespot/workflows/test/badge.svg)](https://github.com/librespot-org/librespot/actions) +[![Build Status](https://github.com/librespot-org/librespot/workflows/build/badge.svg)](https://github.com/librespot-org/librespot/actions) [![Gitter chat](https://badges.gitter.im/librespot-org/librespot.png)](https://gitter.im/librespot-org/spotify-connect-resources) [![Crates.io](https://img.shields.io/crates/v/librespot.svg)](https://crates.io/crates/librespot) @@ -62,13 +62,15 @@ SDL Pipe Subprocess ``` -Please check the corresponding [Compiling](https://github.com/librespot-org/librespot/wiki/Compiling#general-dependencies) entry on the wiki for backend specific dependencies. +Please check [COMPILING.md](COMPILING.md) for detailed information on TLS, audio, and discovery backend dependencies, or the [Compiling](https://github.com/librespot-org/librespot/wiki/Compiling#general-dependencies) entry on the wiki for additional backend specific dependencies. -Once you've installed the dependencies and cloned this repository you can build *librespot* with the default backend using Cargo. +Once you've installed the dependencies and cloned this repository you can build *librespot* with the default features using Cargo. ```shell cargo build --release ``` +By default, this builds with native-tls (system TLS), rodio audio backend, and libmdns discovery. See [COMPILING.md](COMPILING.md) for information on selecting different TLS, audio, and discovery backends. + # Packages librespot is also available via official package system on various operating systems such as Linux, FreeBSD, NetBSD. [Repology](https://repology.org/project/librespot/versions) offers a good overview. @@ -115,6 +117,6 @@ This is a non exhaustive list of projects that either use or have modified libre - [librespot-java](https://github.com/devgianlu/librespot-java) - A Java port of librespot. - [ncspot](https://github.com/hrkfdn/ncspot) - Cross-platform ncurses Spotify client. - [ansible-role-librespot](https://github.com/xMordax/ansible-role-librespot/tree/master) - Ansible role that will build, install and configure Librespot. -- [Spot](https://github.com/xou816/spot) - Gtk/Rust native Spotify client for the GNOME desktop. +- [Spot](https://github.com/xou816/spot) - Gtk/Rust native Spotify client for the GNOME desktop. - [Snapcast](https://github.com/badaix/snapcast) - synchronised multi-room audio player that uses librespot as its source for Spotify content - [MuPiBox](https://mupibox.de/) - Portable music box for Spotify and local media based on Raspberry Pi. Operated via touchscreen. Suitable for children and older people. diff --git a/audio/Cargo.toml b/audio/Cargo.toml index e1d24352..217cdfcb 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -1,25 +1,31 @@ [package] name = "librespot-audio" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Lietar "] +license.workspace = true description = "The audio fetching logic for librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true -[dependencies.librespot-core] -path = "../core" -version = "0.6.0-dev" +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["native-tls"] + +# TLS backend propagation +native-tls = ["librespot-core/native-tls"] +rustls-tls = ["librespot-core/rustls-tls"] [dependencies] +librespot-core.workspace = true + aes = "0.8" bytes = "1" ctr = "0.9" futures-util = "0.3" -hyper = "1.6" -hyper-util = { version = "0.1", features = ["client"] } http-body-util = "0.1" +hyper = { version = "1.6", features = ["http1", "http2"] } +hyper-util = { version = "0.1", features = ["client", "http2"] } log = "0.4" parking_lot = { version = "0.12", features = ["deadlock_detection"] } tempfile = "3" diff --git a/audio/src/fetch/mod.rs b/audio/src/fetch/mod.rs index cd117731..781e8a32 100644 --- a/audio/src/fetch/mod.rs +++ b/audio/src/fetch/mod.rs @@ -162,7 +162,7 @@ impl StreamLoaderController { } pub fn range_available(&self, range: Range) -> bool { - let available = if let Some(ref shared) = self.stream_shared { + if let Some(ref shared) = self.stream_shared { let download_status = shared.download_status.lock(); range.length @@ -171,9 +171,7 @@ impl StreamLoaderController { .contained_length_from_value(range.start) } else { range.length <= self.len() - range.start - }; - - available + } } pub fn range_to_end_available(&self) -> bool { @@ -397,12 +395,12 @@ impl AudioFile { pub fn get_stream_loader_controller(&self) -> Result { let controller = match self { - AudioFile::Streaming(ref stream) => StreamLoaderController { + AudioFile::Streaming(stream) => StreamLoaderController { channel_tx: Some(stream.stream_loader_command_tx.clone()), stream_shared: Some(stream.shared.clone()), file_size: stream.shared.file_size, }, - AudioFile::Cached(ref file) => StreamLoaderController { + AudioFile::Cached(file) => StreamLoaderController { channel_tx: None, stream_shared: None, file_size: file.metadata()?.len() as usize, diff --git a/connect/Cargo.toml b/connect/Cargo.toml index 216842aa..3da9195b 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -1,14 +1,26 @@ [package] name = "librespot-connect" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Lietar "] -description = "The discovery and Spotify Connect logic for librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +license.workspace = true +description = "The Spotify Connect logic for librespot" +repository.workspace = true +edition.workspace = true + +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["native-tls"] + +# TLS backend propagation +native-tls = ["librespot-core/native-tls", "librespot-playback/native-tls"] +rustls-tls = ["librespot-core/rustls-tls", "librespot-playback/rustls-tls"] [dependencies] +librespot-core.workspace = true +librespot-playback.workspace = true +librespot-protocol.workspace = true + futures-util = "0.3" log = "0.4" protobuf = "3.7" @@ -18,15 +30,3 @@ thiserror = "2" tokio = { version = "1", features = ["macros", "parking_lot", "sync"] } tokio-stream = "0.1" uuid = { version = "1.18", features = ["v4"] } - -[dependencies.librespot-core] -path = "../core" -version = "0.6.0-dev" - -[dependencies.librespot-playback] -path = "../playback" -version = "0.6.0-dev" - -[dependencies.librespot-protocol] -path = "../protocol" -version = "0.6.0-dev" diff --git a/core/Cargo.toml b/core/Cargo.toml index 8d2159be..161ac5e9 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,27 +1,43 @@ [package] name = "librespot-core" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Lietar "] -build = "build.rs" +license.workspace = true description = "The core functionality provided by librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true +build = "build.rs" -[dependencies.librespot-oauth] -path = "../oauth" -version = "0.6.0-dev" +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["native-tls"] -[dependencies.librespot-protocol] -path = "../protocol" -version = "0.6.0-dev" +# TLS backends (mutually exclusive - see oauth/src/lib.rs for compile-time checks) +# Note: Validation is in oauth since it's compiled first in the dependency tree. +native-tls = [ + "dep:hyper-tls", + "hyper-proxy2/tls", + "librespot-oauth/native-tls", + "tokio-tungstenite/native-tls", +] +rustls-tls = [ + "dep:hyper-rustls", + "hyper-proxy2/rustls", + "librespot-oauth/rustls-tls", + "tokio-tungstenite/__rustls-tls", +] [dependencies] +librespot-oauth.workspace = true +librespot-protocol.workspace = true + aes = "0.8" base64 = "0.22" byteorder = "1.5" bytes = "1" +data-encoding = "2.9" +flate2 = "1.1" form_urlencoded = "1.2" futures-core = "0.3" futures-util = { version = "0.3", features = [ @@ -37,9 +53,22 @@ governor = { version = "0.10", default-features = false, features = [ hmac = "0.12" httparse = "1.10" http = "1.3" -hyper = { version = "1.6", features = ["http1", "http2"] } -hyper-util = { version = "0.1", features = ["client"] } http-body-util = "0.1" +hyper = { version = "1.6", features = ["http1", "http2"] } +hyper-proxy2 = { version = "0.1", default-features = false } +hyper-rustls = { version = "0.27", default-features = false, features = [ + "http1", + "http2", + "ring", + "rustls-platform-verifier", + "tls12", +], optional = true } +hyper-tls = { version = "0.6", optional = true } +hyper-util = { version = "0.1", default-features = false, features = [ + "client", + "http1", + "http2", +] } log = "0.4" nonzero_ext = "0.3" num-bigint = "0.4" @@ -51,6 +80,7 @@ pbkdf2 = { version = "0.12", default-features = false, features = ["hmac"] } pin-project-lite = "0.2" priority-queue = "2.5" protobuf = "3.7" +protobuf-json-mapping = "3.7" quick-xml = { version = "0.38", features = ["serialize"] } rand = "0.9" rsa = "0.9" @@ -71,28 +101,10 @@ tokio = { version = "1", features = [ "time", ] } tokio-stream = "0.1" +tokio-tungstenite = { version = "0.27", default-features = false } tokio-util = { version = "0.7", features = ["codec"] } url = "2" uuid = { version = "1", default-features = false, features = ["v4"] } -data-encoding = "2.9" -flate2 = "1.1" -protobuf-json-mapping = "3.7" -rustls = { version = "0.23", default-features = false, features = ["ring"] } - -hyper-proxy2 = { version = "0.1", default-features = false, features = [ - "rustls-webpki", -] } -hyper-rustls = { version = "0.27", default-features = false, features = [ - "ring", - "http1", - "logging", - "tls12", - "webpki-tokio", - "http2", -] } -tokio-tungstenite = { version = "0.27", default-features = false, features = [ - "rustls-tls-webpki-roots", -] } [build-dependencies] rand = "0.9" diff --git a/core/src/http_client.rs b/core/src/http_client.rs index a35fa9aa..27d0da92 100644 --- a/core/src/http_client.rs +++ b/core/src/http_client.rs @@ -13,7 +13,6 @@ use http::{Uri, header::HeaderValue}; use http_body_util::{BodyExt, Full}; use hyper::{HeaderMap, Request, Response, StatusCode, body::Incoming, header::USER_AGENT}; use hyper_proxy2::{Intercept, Proxy, ProxyConnector}; -use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; use hyper_util::{ client::legacy::{Client, ResponseFuture, connect::HttpConnector}, rt::TokioExecutor, @@ -23,6 +22,11 @@ use parking_lot::Mutex; use thiserror::Error; use url::Url; +#[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))] +use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; +#[cfg(all(feature = "native-tls", not(feature = "rustls-tls")))] +use hyper_tls::HttpsConnector; + use crate::{ Error, config::{OS, os_version}, @@ -145,14 +149,15 @@ impl HttpClient { fn try_create_hyper_client(proxy_url: Option<&Url>) -> Result { // configuring TLS is expensive and should be done once per process - let _ = rustls::crypto::ring::default_provider() - .install_default() - .map_err(|e| { - Error::internal(format!("unable to install default crypto provider: {e:?}")) - }); - let tls = HttpsConnectorBuilder::new().with_webpki_roots(); - let https_connector = tls.https_or_http().enable_http1().enable_http2().build(); + #[cfg(all(feature = "rustls-tls", not(feature = "native-tls")))] + let https_connector = { + let tls = HttpsConnectorBuilder::new().with_platform_verifier(); + tls.https_or_http().enable_http1().enable_http2().build() + }; + + #[cfg(all(feature = "native-tls", not(feature = "rustls-tls")))] + let https_connector = HttpsConnector::new(); // When not using a proxy a dummy proxy is configured that will not intercept any traffic. // This prevents needing to carry the Client Connector generics through the whole project diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml index 8cfbfa3a..59b1eb32 100644 --- a/discovery/Cargo.toml +++ b/discovery/Cargo.toml @@ -1,14 +1,29 @@ [package] name = "librespot-discovery" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Lietar "] +license.workspace = true description = "The discovery logic for librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true + +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["with-libmdns", "native-tls"] + +# Discovery backends +with-avahi = ["dep:serde", "dep:zbus"] +with-dns-sd = ["dep:dns-sd"] +with-libmdns = ["dep:libmdns"] + +# TLS backend propagation +native-tls = ["librespot-core/native-tls"] +rustls-tls = ["librespot-core/rustls-tls"] [dependencies] +librespot-core.workspace = true + aes = "0.8" base64 = "0.22" bytes = "1" @@ -18,13 +33,13 @@ form_urlencoded = "1.2" futures-core = "0.3" futures-util = "0.3" hmac = "0.12" +http-body-util = "0.1" hyper = { version = "1.6", features = ["http1"] } hyper-util = { version = "0.1", features = [ "server-auto", "server-graceful", "service", ] } -http-body-util = "0.1" libmdns = { version = "0.9", optional = true } log = "0.4" rand = "0.9" @@ -40,18 +55,7 @@ zbus = { version = "5", default-features = false, features = [ "tokio", ], optional = true } -[dependencies.librespot-core] -path = "../core" -version = "0.6.0-dev" - [dev-dependencies] futures = "0.3" hex = "0.4" tokio = { version = "1", features = ["macros", "parking_lot", "rt"] } - -[features] -with-avahi = ["zbus", "serde"] -with-dns-sd = ["dns-sd"] -with-libmdns = ["libmdns"] - -default = ["with-libmdns"] diff --git a/discovery/examples/discovery.rs b/discovery/examples/discovery.rs index 0b9b5b24..6d41563e 100644 --- a/discovery/examples/discovery.rs +++ b/discovery/examples/discovery.rs @@ -16,6 +16,6 @@ async fn main() { .unwrap(); while let Some(x) = server.next().await { - println!("Received {:?}", x); + println!("Received {x:?}"); } } diff --git a/discovery/examples/discovery_group.rs b/discovery/examples/discovery_group.rs index e98b1536..3022781a 100644 --- a/discovery/examples/discovery_group.rs +++ b/discovery/examples/discovery_group.rs @@ -17,6 +17,6 @@ async fn main() { .unwrap(); while let Some(x) = server.next().await { - println!("Received {:?}", x); + println!("Received {x:?}"); } } diff --git a/metadata/Cargo.toml b/metadata/Cargo.toml index bbb2cd0a..27d94724 100644 --- a/metadata/Cargo.toml +++ b/metadata/Cargo.toml @@ -1,27 +1,30 @@ [package] name = "librespot-metadata" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Lietar "] +license.workspace = true description = "The metadata logic for librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true + +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["native-tls"] + +# TLS backend propagation +native-tls = ["librespot-core/native-tls"] +rustls-tls = ["librespot-core/rustls-tls"] [dependencies] +librespot-core.workspace = true +librespot-protocol.workspace = true + async-trait = "0.1" bytes = "1" log = "0.4" protobuf = "3.7" -thiserror = "2" -uuid = { version = "1", default-features = false } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" - -[dependencies.librespot-core] -path = "../core" -version = "0.6.0-dev" - -[dependencies.librespot-protocol] -path = "../protocol" -version = "0.6.0-dev" +thiserror = "2" +uuid = { version = "1", default-features = false } diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index d4cbd4ec..1bb5b9f3 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -50,7 +50,7 @@ pub trait Metadata: Send + Sized + 'static { async fn get(session: &Session, id: &SpotifyId) -> Result { let response = Self::request(session, id).await?; let msg = Self::Message::parse_from_bytes(&response)?; - trace!("Received metadata: {:#?}", msg); + trace!("Received metadata: {msg:#?}"); Self::parse(&msg, id) } diff --git a/metadata/src/request.rs b/metadata/src/request.rs index fc2c998f..720c3836 100644 --- a/metadata/src/request.rs +++ b/metadata/src/request.rs @@ -21,7 +21,7 @@ pub trait MercuryRequest { let _ = write!(metrics_uri, "&product={product}"); } - trace!("Requesting {}", metrics_uri); + trace!("Requesting {metrics_uri}"); let request = session.mercury().get(metrics_uri)?; let response = request.await?; diff --git a/oauth/Cargo.toml b/oauth/Cargo.toml index dd514b00..88e042c9 100644 --- a/oauth/Cargo.toml +++ b/oauth/Cargo.toml @@ -1,23 +1,31 @@ [package] name = "librespot-oauth" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Nick Steel "] +license.workspace = true description = "OAuth authorization code flow with PKCE for obtaining a Spotify access token" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true + +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["native-tls"] + +# TLS backends (mutually exclusive - compile-time checks in src/lib.rs) +native-tls = ["oauth2/native-tls", "reqwest/native-tls"] +rustls-tls = ["oauth2/rustls-tls", "reqwest/rustls-tls"] [dependencies] log = "0.4" -oauth2 = { version = "5.0", features = ["reqwest", "reqwest-blocking"] } -reqwest = { version = "0.12", default-features = false, features = [ - "blocking", - "http2", - "rustls-tls", - "system-proxy", +oauth2 = { version = "5.0", default-features = false, features = [ + "reqwest", + "reqwest-blocking", ] } open = "5.3" +reqwest = { version = "0.12", default-features = false, features = [ + "system-proxy", +] } thiserror = "2" url = "2.5" diff --git a/oauth/examples/oauth_async.rs b/oauth/examples/oauth_async.rs index a8b26799..4d357535 100644 --- a/oauth/examples/oauth_async.rs +++ b/oauth/examples/oauth_async.rs @@ -42,7 +42,7 @@ async fn main() { { Ok(client) => client, Err(err) => { - eprintln!("Unable to build an OAuth client: {}", err); + eprintln!("Unable to build an OAuth client: {err}"); return; } }; diff --git a/oauth/examples/oauth_sync.rs b/oauth/examples/oauth_sync.rs index af773d20..c052faac 100644 --- a/oauth/examples/oauth_sync.rs +++ b/oauth/examples/oauth_sync.rs @@ -41,7 +41,7 @@ fn main() { { Ok(client) => client, Err(err) => { - eprintln!("Unable to build an OAuth client: {}", err); + eprintln!("Unable to build an OAuth client: {err}"); return; } }; diff --git a/oauth/src/lib.rs b/oauth/src/lib.rs index dca85528..1bbe1188 100644 --- a/oauth/src/lib.rs +++ b/oauth/src/lib.rs @@ -11,23 +11,42 @@ //! a spawned http server (mimicking Spotify's client), or manually via stdin. The latter //! is appropriate for headless systems. -use log::{error, info, trace}; -use oauth2::basic::BasicTokenType; -use oauth2::{ - AuthUrl, AuthorizationCode, ClientId, CsrfToken, EndpointNotSet, EndpointSet, - PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, TokenUrl, basic::BasicClient, -}; -use oauth2::{EmptyExtraTokenFields, PkceCodeVerifier, RefreshToken, StandardTokenResponse}; -use std::io; -use std::sync::mpsc; -use std::time::{Duration, Instant}; use std::{ - io::{BufRead, BufReader, Write}, + io::{self, BufRead, BufReader, Write}, net::{SocketAddr, TcpListener}, + sync::mpsc, + time::{Duration, Instant}, }; + +use oauth2::{ + AuthUrl, AuthorizationCode, ClientId, CsrfToken, EmptyExtraTokenFields, EndpointNotSet, + EndpointSet, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, + StandardTokenResponse, TokenResponse, TokenUrl, basic::BasicClient, basic::BasicTokenType, +}; + +use log::{error, info, trace}; use thiserror::Error; use url::Url; +// TLS Feature Validation +// +// These compile-time checks are placed in the oauth crate rather than core for a specific reason: +// oauth is at the bottom of the dependency tree (even librespot-core depends on librespot-oauth), +// which means it gets compiled first. This ensures TLS feature conflicts are detected early in +// the build process, providing immediate feedback to users rather than failing later during +// core compilation. +// +// The dependency chain is: workspace -> core -> oauth +// So oauth's feature validation runs before core's, catching configuration errors quickly. + +#[cfg(all(feature = "native-tls", feature = "rustls-tls"))] +compile_error!("Features 'native-tls' and 'rustls-tls' are mutually exclusive. Enable only one."); + +#[cfg(not(any(feature = "native-tls", feature = "rustls-tls")))] +compile_error!( + "Either feature \"native-tls\" (default) or \"rustls-tls\" must be enabled for this crate." +); + /// Possible errors encountered during the OAuth authentication flow. #[derive(Debug, Error)] pub enum OAuthError { diff --git a/playback/Cargo.toml b/playback/Cargo.toml index c87d7f9d..6d98fac9 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -1,26 +1,51 @@ [package] name = "librespot-playback" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Sasha Hilton "] +license.workspace = true description = "The audio playback logic for librespot" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true -[dependencies.librespot-audio] -path = "../audio" -version = "0.6.0-dev" +[features] +# Refer to the workspace Cargo.toml for the list of features +default = ["rodio-backend", "native-tls"] -[dependencies.librespot-core] -path = "../core" -version = "0.6.0-dev" +# Audio backends +alsa-backend = ["dep:alsa"] +gstreamer-backend = [ + "dep:gstreamer", + "dep:gstreamer-app", + "dep:gstreamer-audio", +] +jackaudio-backend = ["dep:jack"] +portaudio-backend = ["dep:portaudio-rs"] +pulseaudio-backend = ["dep:libpulse-binding", "dep:libpulse-simple-binding"] +rodio-backend = ["dep:cpal", "dep:rodio"] +rodiojack-backend = ["dep:rodio", "cpal/jack"] +sdl-backend = ["dep:sdl2"] -[dependencies.librespot-metadata] -path = "../metadata" -version = "0.6.0-dev" +# Audio processing features +passthrough-decoder = ["dep:ogg"] + +# TLS backend propagation +native-tls = [ + "librespot-core/native-tls", + "librespot-audio/native-tls", + "librespot-metadata/native-tls", +] +rustls-tls = [ + "librespot-core/rustls-tls", + "librespot-audio/rustls-tls", + "librespot-metadata/rustls-tls", +] [dependencies] +librespot-audio.workspace = true +librespot-core.workspace = true +librespot-metadata.workspace = true + portable-atomic = "1" futures-util = "0.3" log = "0.4" @@ -37,21 +62,24 @@ zerocopy = { version = "0.8", features = ["derive"] } # Backends alsa = { version = "0.9", optional = true } -portaudio-rs = { version = "0.3", optional = true } -libpulse-binding = { version = "2", optional = true, default-features = false } -libpulse-simple-binding = { version = "2", optional = true, default-features = false } jack = { version = "0.13", optional = true } +portaudio-rs = { version = "0.3", optional = true } sdl2 = { version = "0.38", optional = true } + +# GStreamer dependencies gstreamer = { version = "0.24", optional = true } gstreamer-app = { version = "0.24", optional = true } gstreamer-audio = { version = "0.24", optional = true } -glib = { version = "0.21", optional = true } + +# PulseAudio dependencies +libpulse-binding = { version = "2", optional = true, default-features = false } +libpulse-simple-binding = { version = "2", optional = true, default-features = false } # Rodio dependencies +cpal = { version = "0.16", optional = true } rodio = { version = "0.21", optional = true, default-features = false, features = [ "playback", ] } -cpal = { version = "0.16", optional = true } # Container and audio decoder symphonia = { version = "0.5", default-features = false, features = [ @@ -66,15 +94,3 @@ ogg = { version = "0.9", optional = true } # Dithering rand = { version = "0.9", features = ["small_rng"] } rand_distr = "0.5" - -[features] -alsa-backend = ["alsa"] -portaudio-backend = ["portaudio-rs"] -pulseaudio-backend = ["libpulse-binding", "libpulse-simple-binding"] -jackaudio-backend = ["jack"] -rodio-backend = ["rodio", "cpal"] -rodiojack-backend = ["rodio", "cpal/jack"] -sdl-backend = ["sdl2"] -gstreamer-backend = ["gstreamer", "gstreamer-app", "gstreamer-audio"] - -passthrough-decoder = ["ogg"] diff --git a/playback/src/mixer/mappings.rs b/playback/src/mixer/mappings.rs index bb740997..cb238a21 100644 --- a/playback/src/mixer/mappings.rs +++ b/playback/src/mixer/mappings.rs @@ -81,7 +81,7 @@ impl MappedCtrl for VolumeCtrl { fn set_db_range(&mut self, new_db_range: f64) { match self { - Self::Cubic(ref mut db_range) | Self::Log(ref mut db_range) => *db_range = new_db_range, + Self::Cubic(db_range) | Self::Log(db_range) => *db_range = new_db_range, _ => error!("Invalid to set dB range for volume control type {self:?}"), } diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index e2143782..8ae4b70a 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "librespot-protocol" -version = "0.6.0-dev" +version.workspace = true rust-version.workspace = true authors = ["Paul Liétar "] -build = "build.rs" +license.workspace = true description = "The protobuf logic for communicating with Spotify servers" -license = "MIT" -repository = "https://github.com/librespot-org/librespot" -edition = "2021" +repository.workspace = true +edition.workspace = true +build = "build.rs" [dependencies] protobuf = "3.7"