Shiny.Audio.Linux
3.0.0-beta-0035
Prefix Reserved
dotnet add package Shiny.Audio.Linux --version 3.0.0-beta-0035
NuGet\Install-Package Shiny.Audio.Linux -Version 3.0.0-beta-0035
<PackageReference Include="Shiny.Audio.Linux" Version="3.0.0-beta-0035" />
<PackageVersion Include="Shiny.Audio.Linux" Version="3.0.0-beta-0035" />
<PackageReference Include="Shiny.Audio.Linux" />
paket add Shiny.Audio.Linux --version 3.0.0-beta-0035
#r "nuget: Shiny.Audio.Linux, 3.0.0-beta-0035"
#:package Shiny.Audio.Linux@3.0.0-beta-0035
#addin nuget:?package=Shiny.Audio.Linux&version=3.0.0-beta-0035&prerelease
#tool nuget:?package=Shiny.Audio.Linux&version=3.0.0-beta-0035&prerelease
Shiny.Audio
Cross-platform audio capture and playback for .NET MAUI, iOS, Mac Catalyst, macOS, Android, Windows,
Browser (WebAssembly), and Linux (via the companion Shiny.Audio.Linux package).
Shiny.Audio provides the low-level audio primitives that back Shiny.Speech,
but is usable on its own:
IAudioSource— microphone capture that streams raw PCM audio (16kHz, 16-bit, mono) via a thread-safePipeStream, with runtime permission handling (RequestAccess/AccessState) and a normalizedInputLevelChangedVU signal on every platform.IAudioPlayer— stream / file / URL playback (e.g. MP3) with optional normalizedAudioLevelChangedmetering for VU-style UI. Clips play concurrently:StartAsyncreturns anIAudioPlaybackyou can stop on its own,PlayAsyncwaits for one clip without interrupting the rest, andStopAsyncstops the lot.IAudioRecorder— record the microphone straight to a WAV file, optionally through a live effect chain, capturing the processed take, the raw one, or both.IAudioDuplex— full-duplex voice for calls: echo-cancelled mic frames out (Captured) and live network PCM in (Play) on one voice-processing session, with a jitter buffer (priming, underrun re-prime, overflow drop) and live speakerphone switching. iOS, Mac Catalyst, macOS and Android.AudioEffectChain— real-time DSP on capture (pitch shift, echo, reverb, filters, distortion, ring modulation, chorus, gain, noise gate) that you toggle and re-tune while recording.AudioLevel— the shared dBFS mapping behind every meter (FromRms/FromPcm16/FromSamples), so input and output bars read on the same scale — including PCM you meter yourself.WavWriter/WavReader— streaming RIFF/WAVE PCM I/O, plusAudioEffectProcessorfor applying an effect chain to a file that already exists.
Getting Started
using Shiny;
builder.Services.AddAudioServices(); // registers IAudioSource, IAudioPlayer, IAudioRecorder, ...
using Shiny.Audio;
public class Recorder(IAudioSource audioSource)
{
public async Task RecordAsync(CancellationToken ct)
{
if (await audioSource.RequestAccess() != AccessState.Available)
return;
var pcmStream = await audioSource.StartCaptureAsync(cancellationToken: ct);
// consume pcmStream ...
await audioSource.StopCaptureAsync();
}
}
Full-duplex voice (calls)
var session = await audio.Duplex.StartAsync(new AudioDuplexOptions { SampleRate = 16000 });
// mic -> network: one 20 ms PCM16 mono frame per item, echo-cancelled
await foreach (var frame in session.Captured.ReadAllAsync(ct))
await network.SendAsync(frame, ct);
// network -> speaker, from any thread, any size (jitter-buffered; gaps play as silence)
session.Play(received.Span);
session.Speakerphone = false; // earpiece, live
await session.StopAsync(); // restores the audio session
Defaults: 16 kHz, AudioProcessingOptions.VoiceChat, speakerphone on, 20 ms frames, 60 ms target
playback latency and 200 ms maximum (older audio is dropped). One session at a time. Not available
on Windows, Linux or the browser. On Android add MODIFY_AUDIO_SETTINGS to the manifest.
Effects & recording
Effects are caller-owned objects. Build a chain, hand it to a capture or recording session, and keep the reference — toggling an effect or moving a parameter applies on the next audio buffer, with no restart and no clicks.
using Shiny.Audio;
var chain = new AudioEffectChain();
var pitch = chain.Add(new PitchShiftEffect { Semitones = 0 });
var echo = chain.Add(new EchoEffect { Enabled = false });
await recorder.StartAsync(new AudioRecordingOptions
{
Mode = AudioRecordMode.Both, // writes the processed and the raw take
Effects = chain
});
pitch.Semitones = 5; // heard immediately
echo.Enabled = true;
chain.Enabled = false; // master bypass
var recording = await recorder.StopAsync();
Available effects: GainEffect, NoiseGateEffect, BiquadFilterEffect, DistortionEffect,
RingModEffect, EchoEffect, ChorusEffect, ReverbEffect, PitchShiftEffect — plus
AudioEffectPresets.Create(...) for ready-made combinations (Robot, Chipmunk, DeepVoice, Cathedral,
Telephone, Megaphone, Ensemble).
Choosing the microphone
IAudioDevices lists the microphones the system sees (GetInputs(), with CurrentInput the system
default) and raises Changed when one is plugged in, removed or made the default. Hand one to a
recording or a capture session; null keeps the system default.
var mic = devices.GetInputs().FirstOrDefault(x => x.Type == AudioDeviceType.Usb);
await recorder.StartAsync(new AudioRecordingOptions { InputDevice = mic });
var pcm = await audioSource.StartCaptureAsync(new AudioCaptureOptions { InputDevice = mic });
| Platform | Inputs from | Capture from a chosen input |
|---|---|---|
| macOS | CoreAudio devices with input streams (UID as Id) |
The engine input node's I/O unit |
| Windows | Device enumeration (MediaDevice.GetAudioCaptureSelector) |
AudioGraph device input node |
| Linux | PulseAudio/PipeWire sources (monitors excluded), ALSA hints | The source / PCM by name |
| iOS / Mac Catalyst | AVAudioSession.AvailableInputs |
The session's preferred input |
| Android | AudioManager input devices |
AudioRecord preferred device |
A microphone unplugged since it was listed falls back to the system default rather than failing.
Do not put effects on audio bound for speech recognition — they destroy recognition and wake-word accuracy.
| Platform | Audio Capture | Audio Playback | Full duplex (IAudioDuplex) |
|---|---|---|---|
| iOS 15+ / Mac Catalyst | AVAudioEngine | AVAudioPlayer | AVAudioEngine voice processing + AVAudioPlayerNode |
| macOS | AVAudioEngine | AVAudioPlayer | AVAudioEngine voice processing + AVAudioPlayerNode |
| Android 26+ | AudioRecord | MediaPlayer | AudioRecord + AudioTrack (voice communication) |
| Windows 10 19041+ | AudioGraph | MediaPlayer | ❌ |
| Browser (WASM) | Web Audio API (getUserMedia + ScriptProcessorNode) |
HTML5 Audio |
❌ |
| Linux | PulseAudio / PipeWire (pa_simple), ALSA fallback |
PulseAudio / PipeWire (pa_simple), ALSA fallback |
❌ |
Linux
Linux ships as a separate Shiny.Audio.Linux package (it carries a managed MP3 decoder, since
Linux has no system decoder to call). Add it and register before anything else:
builder.Services.AddLinuxAudio(); // no-op when not running on Linux
It supplies all four services — IAudioSource, IAudioPlayer, IAudioDevices and IAudioMonitor —
over PulseAudio/PipeWire, falling back to ALSA on headless systems and containers.
See https://shinylib.net/speech for full documentation.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- NLayer (>= 2.0.1)
- Shiny.Audio (>= 3.0.0-beta-0035)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-beta-0035 | 0 | 10/24/2026 |
| 3.0.0-beta-0034 | 0 | 10/23/2026 |
| 3.0.0-beta-0033 | 37 | 10/22/2026 |
| 3.0.0-beta-0032 | 39 | 10/21/2026 |
| 3.0.0-beta-0030 | 85 | 8/15/2026 |
| 3.0.0-beta-0029 | 78 | 8/8/2026 |
| 3.0.0-beta-0028 | 77 | 8/7/2026 |
| 3.0.0-beta-0027 | 69 | 8/5/2026 |
| 3.0.0-beta-0026 | 76 | 8/5/2026 |
| 3.0.0-beta-0024 | 76 | 8/5/2026 |
| 3.0.0-beta-0023 | 74 | 8/5/2026 |
| 3.0.0-beta-0022 | 81 | 8/2/2026 |
| 3.0.0-beta-0021 | 76 | 7/31/2026 |
| 3.0.0-beta-0020 | 77 | 7/30/2026 |
| 3.0.0-beta-0019 | 72 | 7/30/2026 |