Interface AudioSourceProvider
dtmf-io-wav,
dtmf-io-mp3, or a future FLAC/OGG module) ships exactly one
implementation of this interface and registers it via
META-INF/services/com.tino1b2be.dtmf.io.AudioSourceProvider
(Requirement 9.2, 10.2). The AudioSources facade discovers every
registered provider through ServiceLoader, asks each
one to score the input with canOpen(Path) or
canOpen(InputStream, String), and dispatches
open(Path) or open(InputStream, String) on the
provider with the strictly greatest score (Requirement 5.6).
Implementation requirements
Public no-arg constructor. Implementations must
expose a public no-argument constructor so that
ServiceLoader can instantiate them reflectively.
Providers with no state are fine; stateful providers must make their
own-state instantiation cheap, because ServiceLoader creates
one instance per classloader and caches it for the lifetime of the
loader.
Thread safety. Individual provider instances may
be called concurrently by AudioSources from multiple threads.
Implementations should keep canOpen(Path),
canOpen(InputStream, String), open(Path), and
open(InputStream, String) stateless (allocating fresh
FileChannel or
InputStream objects per call). Returned
AudioSource instances are not required to be
thread-safe — see AudioSource for that contract.
SPI Priority Score
The score returned by canOpen(...) is an integer in the
closed range [0, 100] or the sentinel value -1
(Requirement 4.4, 4.5). Higher scores indicate stronger confidence
that this provider can open the input:
100— the input's magic bytes match unambiguously (for example"RIFF" ... "WAVE"at offset 0 for WAV).0–99— a weaker signal, typically because the provider's identifying pattern is heuristic rather than magic (for example an MPEG audio frame sync pattern).-1— the provider is not applicable to this input and must not be selected, even if it is the only provider on the classpath. A-1return is also how a provider declines when asked about a non-markable stream it cannot read ahead on (seecanOpen(InputStream, String)below).
When two providers return the same positive score,
AudioSources breaks the tie with priority() (higher
wins; Requirement 4.3).
Stream ownership
open(Path) and open(InputStream, String) never
close caller-supplied InputStreams (Requirement 4.10). The
AudioSource.close() method on the returned source closes only
the resources the provider opened itself — for example a
FileChannel the provider opened on a
Path, or a BufferedInputStream the provider
wrapped internally around a caller stream. When the caller supplies
the InputStream, closing the returned AudioSource must
not close that caller stream; ownership stays with whoever
opened it.
Null parameters
Every parameter of every SPI method is non-null unless explicitly
documented otherwise. Implementations must throw
NullPointerException identifying the offending parameter when
a non-null argument is null (Requirement 4.11). The
hint parameter on canOpen(InputStream, String) and
open(InputStream, String) is the one exception: it is
explicitly nullable and implementations must tolerate null
without throwing.
- Since:
- 2.1.0
-
Method Summary
Modifier and TypeMethodDescriptionintcanOpen(InputStream stream, String hint) Score this provider's confidence that it can openstream(Requirement 4.5).intScore this provider's confidence that it can openpath(Requirement 4.4).Human-readable identifier for this provider.open(InputStream stream, String hint) Open anAudioSourcefor a markableInputStream(Requirement 4.9).Open anAudioSourceforpath(Requirement 4.8).default intpriority()Tie-breaker priority used when two providers return the same positive score fromcanOpen(Path)orcanOpen(InputStream, String)(Requirement 4.3).
-
Method Details
-
formatName
String formatName()Human-readable identifier for this provider. Returned values must be non-null and non-empty (Requirement 4.2). Typical values are short uppercase tags such as"WAV"or"MP3";AudioSources.registeredFormats()exposes the list of every registered provider's name in discovery order, andUnsupportedAudioFormatException.providerScores()keys its score map on this value, so the returned string should be stable across JVM runs and unique across the providers a caller expects to have on the classpath at the same time.- Returns:
- this provider's format name; never
null, never empty
-
priority
default int priority()Tie-breaker priority used when two providers return the same positive score fromcanOpen(Path)orcanOpen(InputStream, String)(Requirement 4.3). Higher values win. The default implementation returns0, which is the right answer for every built-in provider; a format module only overrides this when it ships two providers for overlapping inputs and wants to express a preferred order.- Returns:
- this provider's tie-break priority
-
canOpen
Score this provider's confidence that it can openpath(Requirement 4.4). Implementations typically open aFileChannelor a short-livedInputStreamon the file, read a small prefix (the WAV provider reads 12 bytes; the MP3 provider reads up to 10 KiB after any ID3v2 tag), score against that prefix, and close the channel or stream before returning. The file itself is not opened for reading beyond the prefix — that happens inopen(Path).The returned value is an SPI Priority Score: an integer in
[0, 100]or-1(see the class-level "SPI Priority Score" section). Implementations must not return any other value;AudioSourcesdoes not validate the score range and out-of-range scores will break tie-breaking.If the file cannot be read at all (for example a
NoSuchFileException, a permission error, or a disk-level I/O failure), this method propagatesIOException. TheAudioSourcesfacade catches those exceptions, treats the provider as having returned-1, logs a warning, and continues scoring the remaining providers (Requirement 5.9) — so implementations do not need to defend against "the file is unreadable" themselves.- Parameters:
path- absolute or relative path to the file to score; must be non-null- Returns:
- an SPI Priority Score in
[0, 100], or-1if this provider is not applicable - Throws:
IOException- if the file cannot be read to score itNullPointerException- ifpathisnull
-
canOpen
Score this provider's confidence that it can openstream(Requirement 4.5). Thehintparameter is an optional caller-supplied file name, URL path segment, MIME type, ornull; providers that cannot read ahead on a non-markable stream may use the hint as a fallback signal, but content-based scoring always takes precedence over any hint on a markable stream.Mark/reset contract. When
streamsupportsmark/reset, implementations callstream.mark(readLimit), read a header prefix, score against that prefix, and callstream.reset()before returning — leaving the stream positioned exactly as it was on entry so thatAudioSourcescan pass the same stream to subsequent providers and eventually toopen(InputStream, String)(Requirement 4.6).Non-markable streams. If
stream.markSupported()isfalse, implementations return-1without consuming any bytes (Requirement 4.7). Reading from a non-markable stream would leave it in a consumed state that neither the caller nor any subsequent provider can recover from. In practiceAudioSources.open(InputStream, String)guarantees the stream it forwards is always markable by wrapping non-markable inputs in aBufferedInputStreamsized for at least 16 KiB of header inspection (Requirement 5.12), so providers see a markable stream every time they are called through the facade; this branch exists for direct callers who invoke a provider without going throughAudioSources.The returned value is an SPI Priority Score: an integer in
[0, 100]or-1— seecanOpen(Path)and the class-level "SPI Priority Score" section.- Parameters:
stream- the stream to score; must be non-nullhint- an optional caller-supplied hint (file name, URL path segment, MIME type); may benull- Returns:
- an SPI Priority Score in
[0, 100], or-1if this provider is not applicable - Throws:
IOException- on I/O failure while reading the header prefixNullPointerException- ifstreamisnull
-
open
Open anAudioSourceforpath(Requirement 4.8). Callers typically reach this method indirectly throughAudioSources.open(Path), which first picks the winning provider by scoring and then delegates to itsopen(...)— but providers may be invoked directly when a caller already knows which format they have.The returned
AudioSourceowns the underlying file handle or stream the provider opened onpath:AudioSource.close()closes that handle and releases any decoder resources. Caller-supplied streams are never involved on this overload, so there is nothing for the provider to avoid closing.A non-negative score from
canOpen(Path)does not guaranteeopen(Path)will succeed: the header prefix may match but a later structural defect (for example a WAVfmtchunk declaring a compressed encoding such asμ-law; Requirement 9.10) only surfaces during the full parse. In that case implementations throwUnsupportedAudioFormatExceptionidentifying the defect; real I/O failures propagate as plainIOException.- Parameters:
path- file to open; must be non-null- Returns:
- an opened
AudioSource - Throws:
UnsupportedAudioFormatException- if the file's header matched but the full parse rejected itIOException- on any other I/O failureNullPointerException- ifpathisnull
-
open
Open anAudioSourcefor a markableInputStream(Requirement 4.9). Thehintparameter has the same semantics as oncanOpen(InputStream, String): file name, URL path segment, MIME type, ornull.This overload never closes
stream. Ownership stays with the caller (Requirement 4.10); the returnedAudioSource'sAudioSource.close()only closes resources the provider opened internally (for example aBufferedInputStreamwrapper, decoder buffers, or a spawned worker). If the caller needs the underlying stream closed, they must close it themselves after closing theAudioSource.As with
open(Path), a prior non-negativecanOpen(InputStream, String)score does not guarantee success here: structural defects past the header surface asUnsupportedAudioFormatExceptionduring the full parse.- Parameters:
stream- markable stream to open; must be non-nullhint- an optional caller-supplied hint; may benull- Returns:
- an opened
AudioSource - Throws:
UnsupportedAudioFormatException- if the stream's header matched but the full parse rejected itIOException- on any other I/O failureNullPointerException- ifstreamisnull
-