audd/audd
Composer 安装命令:
composer require audd/audd
包简介
Official PHP SDK for the AudD music recognition API.
README 文档
README
Official PHP SDK 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
composer require audd/audd:^1.5.15
Get your API token at dashboard.audd.io.
Recognize from a URL:
use AudD\AudD; $audd = new AudD('your-api-token'); $result = $audd->recognize('https://audd.tech/example.mp3'); if ($result !== null) { echo $result->artist . ' — ' . $result->title; }
Recognize from a local file:
use AudD\AudD; $audd = new AudD('your-api-token'); $result = $audd->recognize('/path/to/clip.mp3'); if ($result !== null) { echo $result->artist . ' — ' . $result->title; }
recognize() accepts a URL, a filesystem path, a PSR-7 StreamInterface, a resource handle, or raw bytes wrapped via AudD::bytes($buf) — auto-detected. It returns a RecognitionResult on a match, or null when the clip isn't recognized.
For longer audio files (full-length songs, short-form videos, podcasts, broadcasts, DJ sets), use recognizeEnterprise($source, limit: ...) — it returns list<EnterpriseMatch>, one per song detected across the file.
Authentication
Pass the token as a named argument:
$audd = new AudD('your-token');
Or omit it and set AUDD_API_TOKEN in the environment — the SDK reads it on construction:
putenv('AUDD_API_TOKEN=your-token'); $audd = AudD::fromEnvironment();
AudD::fromEnvironment() is the explicit factory; plain new AudD() does the same env-var lookup but reads less obviously at the call site.
For long-running services that rotate tokens (from a secrets manager, Vault, AWS Parameter Store), call $audd->setApiToken($newToken). Subsequent requests use the new value.
What you get back
By default recognize() returns the core tags plus AudD's universal song link — no metadata-block opt-in needed:
use AudD\AudD; use AudD\StreamingProvider; $audd = new AudD(); $result = $audd->recognize('https://audd.tech/example.mp3'); if ($result === null) { exit("no match\n"); } // Core tags echo $result->artist, ' — ', $result->title, "\n"; echo $result->album, ' / ', $result->release_date, ' / ', $result->label, "\n"; // AudD's universal song page (works in any browser, links into all providers) echo $result->song_link, "\n"; // Helpers — driven off song_link, work without any return_metadata opt-in echo $result->thumbnailUrl(), "\n"; // cover-art URL, or null echo $result->streamingUrl(StreamingProvider::SPOTIFY), "\n"; // direct or lis.tn redirect print_r($result->streamingUrls()); // ["spotify" => "...", ...]
If you need provider-specific metadata blocks, opt in per call. Request only what you need — each provider you ask for adds latency:
$result = $audd->recognize( 'https://audd.tech/example.mp3', return_metadata: ['apple_music', 'spotify'], ); echo $result->apple_music->url, "\n"; // direct Apple Music link echo $result->spotify->uri, "\n"; // spotify:track:... echo $result->previewUrl(), "\n"; // first preview across requested providers, or null
Valid return_metadata values: apple_music, spotify, deezer, napster, musicbrainz. The corresponding properties ($result->apple_music, $result->spotify, …) are null when not requested.
EnterpriseMatch (returned by recognizeEnterprise) carries the same core tags plus score, isrc, upc. It also tells you where the song plays in the file: start_seconds and end_seconds are the match's position in your file, in seconds. These are precise because recognizeEnterprise requests accurate offsets by default (pass accurateOffsets: false to turn that off). Behind them, start_offset and end_offset are the raw fragment-relative offsets in milliseconds. Access to isrc, upc, and score requires a Startup plan or higher — contact us for enterprise features.
Reading additional metadata
Every typed model exposes extras carrying any fields the SDK doesn't surface as a typed property. This is the supported way to read additional fields the SDK doesn't surface as typed properties:
$result = $audd->recognize('https://example.mp3', return_metadata: ['apple_music']); // Top-level extras $genre = $result->extras['genre'] ?? null; // Nested extras inside a typed metadata block $artwork = $result->apple_music->extras['artwork'] ?? null;
Magic property access falls through to extras too — $result->genre returns the same value as $result->extras['genre']. Per-account custom fields and beta API responses surface here.
For sending arbitrary form fields the typed parameters don't cover, pass extra_parameters:
$result = $audd->recognize( '/tmp/snippet.wav', return_metadata: ['apple_music'], extra_parameters: ['my_custom_flag' => '1'], );
Typed parameters win on collision.
Errors
Every server-side error becomes a typed exception. The hierarchy lets you handle whole families with one catch:
AudDException (base)
├── AudDConnectionException network / TLS / timeout
├── AudDSerializationException malformed JSON
├── AudDConfigurationException missing or empty token
└── AudDApiException status=error from server
├── AudDAuthenticationException 900 / 901 / 903
├── AudDQuotaException 902
├── AudDSubscriptionException 904 / 905
│ └── AudDCustomCatalogAccessException 904 from customCatalog
├── AudDInvalidRequestException 50 / 51 / 600 / 601 / 602 / 700–702 / 906
├── AudDInvalidAudioException 300 / 400 / 500
├── AudDStreamLimitException 610
├── AudDRateLimitException 611
├── AudDNotReleasedException 907
├── AudDBlockedException 19 / 31337
├── AudDNeedsUpdateException 20
└── AudDServerException 100 / 1000 / unknown
Idiomatic catch:
use AudD\AudD; use AudD\Errors\AudDApiException; use AudD\Errors\AudDAuthenticationException; use AudD\Errors\AudDInvalidAudioException; try { $result = (new AudD())->recognize('https://example.mp3'); } catch (AudDAuthenticationException $e) { exit("check your token: [#{$e->errorCode}] {$e->apiMessage}\n"); } catch (AudDInvalidAudioException $e) { echo "audio rejected: {$e->apiMessage}\n"; } catch (AudDApiException $e) { // catch-all for anything the server reported echo "AudD #{$e->errorCode}: {$e->apiMessage} (request_id={$e->requestId})\n"; }
match works equally well for typed dispatch on the exception class:
catch (AudDApiException $e) { $action = match (true) { $e instanceof AudDAuthenticationException => 'reload-token', $e instanceof AudDRateLimitException => 'back-off', $e instanceof AudDInvalidAudioException => 'skip', default => 'log-and-rethrow', }; }
Every AudDApiException carries errorCode, apiMessage, httpStatus, requestId, requestedParams, requestMethod, brandedMessage, and rawResponse — enough to log a full incident or open a support ticket.
Logging (PSR-3)
The client accepts an optional Psr\Log\LoggerInterface. Pass any PSR-3 implementation — Monolog, Symfony's logger, Laravel's Log channel, or a custom one — and the SDK routes diagnostics through it. The default is NullLogger (silent), and the api_token is never written to a record.
use AudD\AudD; use Monolog\Handler\StreamHandler; use Monolog\Logger; $logger = new Logger('audd'); $logger->pushHandler(new StreamHandler('php://stderr', Logger::DEBUG)); $audd = new AudD(apiToken: 'your-token', logger: $logger);
Records emitted today: debug for onEvent hook failures (with the exception in context), warning for server-side deprecated-parameter notices (server code 51).
Configuration
use AudD\AudD; use GuzzleHttp\Client; $audd = new AudD( apiToken: 'your-token', maxRetries: 3, // per-call retry budget backoffFactor: 0.5, // initial backoff seconds (jittered) httpClient: new Client(['proxy' => 'http://corp:8080']), onEvent: fn ($e) => error_log((string) $e->method), logger: $logger, );
Custom HTTP client. httpClient accepts any Psr\Http\Client\ClientInterface. Inject a configured Guzzle client, a Symfony PSR-18 adapter, or your own transport to add proxies, mTLS, custom CA bundles, or shared connection pools.
If the client you inject is a Guzzle client, the SDK passes its timeouts as per-request options, so the timeout: argument and the built-in enterprise defaults still apply. Any other PSR-18 client has no channel for per-request timeouts — configure connect/read timeouts on that client directly, and for long enterprise uploads give it a generous read timeout, up to an hour, when you build it.
Retries. Calls are classified by cost and retried accordingly:
| Class | Endpoints | Retried on |
|---|---|---|
RECOGNITION |
recognize, recognizeEnterprise, advanced->* |
failures to establish the connection, and 5xx responses |
READ |
streams->list, streams->getCallbackUrl, longpoll |
any network error, plus 408, 429, and 5xx |
MUTATING |
streams->setCallbackUrl, streams->add, streams->delete |
failures to establish the connection — never 5xx (the change may already have been applied) |
NONE |
customCatalog->add |
never retried — the upload is metered, and re-sending it could double-bill |
RECOGNITION will not double-bill your account: any failure after the connection is up and the upload is in flight is surfaced rather than retried, because the server may already be processing the audio.
Inspection. Pass an onEvent closure to receive an AudDEvent for every request / response / exception — useful for metrics, distributed tracing, or attaching requestId to your application logs. Events never carry the api_token or request bytes; exceptions raised from the hook are swallowed and routed through the PSR-3 logger at debug level so observability can't break the request path.
use AudD\AudDEvent; use AudD\AudDEventKind; $audd = new AudD( apiToken: 'your-token', onEvent: function (AudDEvent $e): void { if ($e->kind === AudDEventKind::Response) { error_log("audd {$e->method} -> {$e->httpStatus} ({$e->elapsedMs}ms)"); } }, );
Timeouts. Defaults are 30s connect / 60s read for standard endpoints, and 30s connect / 1 hour read for the enterprise endpoint (which can legitimately process multi-hour files). Override per call with timeout: (seconds).
Streams
Real-time recognition off radio streams, broadcast feeds, and any other long-running URL. Configure once, then either receive callbacks on your server or poll for events.
$audd->streams()->setCallbackUrl('https://your.server/audd-callback'); $audd->streams()->add('https://your.stream.url/listen.m3u8', radioId: 42); foreach ($audd->streams()->list() as $stream) { echo $stream->radio_id, ' ', $stream->url, ' ', ($stream->stream_running ? 'on' : 'off'), "\n"; }
Inside your webhook handler, parse the POST body into a typed result. handleCallback() accepts a PSR-7 ServerRequestInterface, raw JSON bytes, or an already-decoded array — pick whichever your framework gives you:
use AudD\Streams; // PSR-7 request from your framework: $result = Streams::handleCallback($request); // or raw bytes: $result = Streams::handleCallback(file_get_contents('php://input')); if ($result->isMatch()) { $m = $result->match; echo $m->song->artist, ' — ', $m->song->title, "\n"; foreach ($m->alternatives as $alt) { echo " alt: ", $alt->artist, ' — ', $alt->title, "\n"; } } elseif ($result->isNotification()) { echo 'notification: ', $result->notification->notification_message, "\n"; }
Use Streams::parseCallback($array) if you already have the decoded JSON. Both methods are static.
add() accepts direct stream URLs (DASH, Icecast, HLS, m3u/m3u8) and the shortcuts twitch:<channel>, youtube:<video_id>, youtube-ch:<channel_id>.
Receiving events without a callback URL (longpoll)
If you can't expose a public callback URL, longpoll instead. AudD still requires a callback URL to be configured for the account (https://audd.tech/empty/ works as a no-op receiver), and the SDK preflights this for you — pass skipCallbackCheck: true to skip if you've already verified.
use AudD\Models\StreamCallbackMatch; use AudD\Models\StreamCallbackNotification; $radioId = 1; // any integer you choose — your handle for this stream $poll = $audd->streams()->longpoll(radioId: $radioId, timeout: 30); $poll->onMatch(function (StreamCallbackMatch $m): void { echo $m->song->artist, ' — ', $m->song->title, "\n"; }); $poll->onNotification(function (StreamCallbackNotification $n): void { echo 'notification: ', $n->notification_message, "\n"; }); $poll->onError(function (\Throwable $e) use ($poll): void { fwrite(STDERR, $e->getMessage() . "\n"); $poll->close(); }); $poll->run(); // blocks until close() or a terminal error
Keepalive responses ({"timeout":"no events before timeout"}) are silently absorbed — your onMatch/onNotification only fire on real events.
deriveLongpollCategory is a local computation: MD5(MD5(api_token) + radio_id) truncated to 9 hex chars. The category alone is sufficient to subscribe — the api_token is never sent over the wire for longpolls.
Tokenless consumers
For browser widgets, embedded extensions, or any context where shipping the api_token would leak it: derive the category server-side, ship only the category to the consumer, and have the consumer use LongpollConsumer — same callback API, no api_token required:
use AudD\LongpollConsumer; // $category was derived on your server and shared with this process. $consumer = new LongpollConsumer(category: 'abc123def'); $poll = $consumer->iterate(timeout: 30); $poll->onMatch(fn ($m) => print_r($m)); $poll->onError(fn ($e) => fwrite(STDERR, $e->getMessage())); $poll->run();
Custom catalog (advanced)
The custom-catalog endpoint is NOT how you submit audio for music recognition. For recognition, use
recognize()(orrecognizeEnterprise()for longer audio files). The custom-catalog endpoint adds songs to your private fingerprint database so futurerecognize()calls on your account can identify your own tracks. Requires special access — contact api@audd.io.
$audd->customCatalog()->add(audioId: 42, source: 'https://my.song.mp3');
License
MIT — see LICENSE.
Support
- Documentation: https://docs.audd.io
- Tokens: https://dashboard.audd.io
- Issues: https://github.com/AudDMusic/audd-php/issues
- Email: api@audd.io
audd/audd 适用场景与选型建议
audd/audd 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 19 次下载、GitHub Stars 达 1, 最近一次更新时间为 2026 年 05 月 06 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「audio」 「music」 「recognition」 「fingerprinting」 「shazam」 「audd」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 audd/audd 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 audd/audd 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 audd/audd 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Library for manipulating audio files (validating, transcoding, and tagging)
PHP wrapper for command-line fingerprint generator - fpcalc
Optical Mark Recognition from PHP
Library that obtains VK tokens that work for VK audio API. Библиотека для получения токена VK, подходящего для Audio API.
PHP-ML - Machine Learning library for PHP
A Laravel package for captcha recognition for popular services like rucaptcha.com, 2captcha.com, pixodrom.com, captcha24.com, socialink.ru, anti-captcha.com
统计信息
- 总下载量: 19
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 42
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-05-06