audd-rust
Official Rust crate for music recognition API: identify music from a short audio clip, a long audio file, or a live stream.
The API itself is so simple that it can easily be used even without an SDK: docs.audd.io.
Quickstart
[]
= "1.4"
= { = "1", = ["rt-multi-thread", "macros"] }
Get your API token at dashboard.audd.io.
Recognize from a URL:
use AudD;
async
Recognize from a local file:
use ;
use PathBuf;
async
recognize takes anything Into<Source> — &str (URL or path, auto-detected), PathBuf, Vec<u8>, or Source::Reader(Box<dyn AsyncRead + ...>) for an arbitrary async reader. It returns Ok(None) when the server reports no match.
cargo run --example recognize_url exercises the URL hello-world end-to-end against the live API.
Authentication
Pass the token as a string literal:
# use AudD;
let audd = new;
# let _ = audd;
Or set AUDD_API_TOKEN in the environment and let the SDK pick it up:
# use AudD;
let audd = from_env?; // errors if AUDD_API_TOKEN is unset
# Ok::
For long-running services that rotate credentials, swap the token in place — the standard and enterprise transports both pick up the new value on their next request:
# use AudD;
#
What you get back
recognize returns Option<RecognitionResult>. None means no match; Some(r) carries the typed metadata. By default you get the core tags plus AudD's universal song link — no metadata-block opt-in needed:
use ;
async
If you need provider-specific metadata blocks, opt in per call. Request only what you need — each provider you ask for adds latency:
# use AudD;
# async
Valid return values: apple_music, spotify, deezer, napster, musicbrainz. The corresponding fields (r.apple_music, r.spotify, r.deezer, r.napster, r.musicbrainz) are None when not requested.
For long files (hours, days), use recognize_enterprise — it returns every match across every chunk:
# use ;
# async
Each EnterpriseMatch carries the same core tags plus score, start_offset, end_offset, isrc, upc. Access to isrc, upc, and score requires a Startup plan or higher — contact us for enterprise features.
Reading additional metadata
Every typed model carries an extras: HashMap<String, serde_json::Value> populated via #[serde(flatten)]. It's the supported way to read undocumented metadata, beta fields, and any provider blocks the typed shape doesn't yet expose:
# use AudD;
# async
Because every public model derives Serialize and Deserialize, you can round-trip recognition results through your own logs, queues, or columnar stores without losing typed fields or extras:
# use RecognitionResult;
#
Errors
Every fallible method returns Result<T, AudDError>. The error type is a single enum with five variants — Api, Server, Connection, Serialization, Source, Configuration — propagate with ? and dispatch on category via the helper predicates rather than matching on numeric error codes:
use AudD;
# async
The full predicate set: is_authentication, is_quota, is_subscription, is_custom_catalog_access, is_invalid_request, is_invalid_audio, is_rate_limit, is_stream_limit, is_not_released, is_blocked, is_needs_update, is_api. AudDError::Api carries code, message, kind, http_status, request_id, requested_params, request_method, branded_message, and the unparsed raw_response for advanced inspection.
Configuration
AudD::new covers the common case. Use AudD::builder to tune retries, swap in a configured reqwest::Client (corp proxies, mTLS, custom CA bundles, observability sidecars), or override base URLs for testing:
use AudD;
let client = builder
.proxy
.build.unwrap;
let audd = builder
.max_attempts // retry budget per call (default 3; set to 1 to disable)
.backoff_factor // initial backoff seconds, jittered (default 0.5)
.reqwest_client // shared by standard + enterprise endpoints
.build
.unwrap;
# let _ = audd;
Default timeouts: 30 s connect / 60 s read on standard endpoints, 30 s connect / 1 h read on the enterprise endpoint. Override per call with EnterpriseOptions { timeout: Some(_), .. }.
Choosing a TLS backend
The default build is rustls with the Mozilla CA bundle — pure-Rust, no system deps, the right choice for almost everyone. Switch to native-tls when you need OpenSSL (custom CA trust stores, OpenSSL FIPS, regulated environments) or vendored-openssl when the build host lacks libssl-dev / openssl-devel but you still want the OpenSSL stack at runtime.
| Feature | Default | What it does |
|---|---|---|
rustls-tls |
yes | Pure-Rust TLS via rustls + Mozilla roots |
native-tls |
no | Platform-native TLS — OpenSSL on Linux, SecureTransport on macOS, SChannel on Windows |
vendored-openssl |
no | OpenSSL via native-tls, statically linked from a vendored source build |
Pick exactly one. To opt out of rustls and use OpenSSL:
[]
= { = "1.4", = false, = ["native-tls"] }
Streams
Stream recognition turns AudD into a continuous monitor for an audio stream (internet radio, Twitch, YouTube live, raw HLS/Icecast) and notifies you for every recognized song. Set up streams once, then either receive matches via a callback URL or poll for them.
# use AudD;
# async
Inside your callback receiver, parse the POST body into a typed event. The SDK is web-framework-agnostic — pull the body bytes from your framework of choice (axum, actix-web, rocket, hyper, …) and pass them to handle_callback:
use ;
#
handle_callback(bytes) accepts anything AsRef<[u8]>. If you already have parsed JSON (queue consumer, replay tool), use parse_callback(value) instead.
See examples/streams_callback_handler and examples/streams_setup for runnable code.
Receiving events without a callback URL (longpoll)
If hosting a callback receiver isn't an option, longpoll for events from the client side. The poll handle exposes three typed Streams — matches, notifications, errors — drive them with a tokio::select! loop. Server keepalive ticks are silently absorbed:
# use ;
use StreamExt;
# async
For browser widgets, embedded UIs, or anywhere you need to consume a category without leaking the API token, use the tokenless variant — same LongpollPoll handle, same select loop:
use ;
use StreamExt;
# async
audd::derive_longpoll_category(token, radio_id) is also available as a free function for computing categories on a server and shipping them to a frontend that runs LongpollConsumer.
Custom catalog (advanced)
The custom-catalog endpoint is not how you submit audio for recognition. For recognition, use [
AudD::recognize] or [AudD::recognize_enterprise]. The custom-catalog endpoint adds songs to your private fingerprint database for your account, and requires separate access — contact api@audd.io if you need it.
# use AudD;
# async
License
MIT — see LICENSE.
Support
- Documentation: https://docs.audd.io
- Tokens: https://dashboard.audd.io
- Email: api@audd.io