---
title: "Decode audio from a stream"
url: https://recursiveai.org/oneaudio/cookbook/streaming-decode/
description: "Decode audio in C# from a stream that can’t seek, such as a network response or a pipe, block by block with flat memory, with limits and typed errors for…"
version: "1.2.1"
---

# Decode audio from a stream

Decode audio in C# from a stream that can’t seek, such as a network response or a pipe, block by block with flat memory, with limits and typed errors for untrusted input.

```csharp
using System.Diagnostics;
using OneAudio;

// A stream that can't seek, like a network response or a pipe: here the
// output of `cat`.
var cat = Process.Start(new ProcessStartInfo("cat", "music.ogg")
{
    RedirectStandardOutput = true,
})!;
Stream pipe = cat.StandardOutput.BaseStream;
Console.WriteLine($"pipe: CanSeek {pipe.CanSeek}");

// Limits for input you don't trust. Sizes read from the file are checked
// before anything is allocated.
var limits = new AudioLimits { MaxChannels = 2, MaxSampleRate = 48000 };
using var cancel = new CancellationTokenSource(TimeSpan.FromSeconds(30));

using IAudioDecoder decoder = Audio.Open(pipe, leaveOpen: false, limits, cancel.Token);
int channels = decoder.Format.Channels;
Console.WriteLine($"{decoder.Format.SampleRate} Hz, {channels} ch, CanSeek {decoder.CanSeek}");

// Block by block: memory use doesn't grow with the length of the file.
float[] block = new float[1024 * channels];
long frames = 0;
double sumSquares = 0;
int read;
while ((read = decoder.Read(block)) > 0)
{
    foreach (float s in block.AsSpan(0, read * channels))
        sumSquares += s * s;
    frames += read;
}
double rms = 10 * Math.Log10(sumSquares / (frames * channels));
Console.WriteLine($"{frames} frames, RMS {rms:F1} dBFS");

try
{
    decoder.Seek(0);
}
catch (NotSupportedException)
{
    Console.WriteLine("Seek on a pipe: NotSupportedException");
}

// A file over the limits is refused with an exception that names the limit.
try
{
    using IAudioDecoder tooBig = Audio.Open("music.wav", new AudioLimits { MaxSampleRate = 32000 });
}
catch (AudioLimitExceededException e)
{
    Console.WriteLine(e.Message);
}

// Bytes that aren't audio at all.
try
{
    using IAudioDecoder notAudio = Audio.Open(new MemoryStream("not audio"u8.ToArray()));
}
catch (UnsupportedAudioFormatException e)
{
    Console.WriteLine($"{e.GetType().Name}: {e.Message}");
}
```

```text
pipe: CanSeek False
44100 Hz, 2 ch, CanSeek False
1411200 frames, RMS -24.8 dBFS
Seek on a pipe: NotSupportedException
MaxSampleRate limit exceeded: input needs 44100, limit is 32000.
UnsupportedAudioFormatException: No registered container format recognises this data.
```

## How it works

- `Audio.Open(stream)` finds the format in the first 512 bytes. A stream that can’t seek is read through a small replay buffer, so detection works on pipes and sockets too.
- The decoder reads only as much of the stream as each `Read` needs. Memory doesn’t grow with the length of the file, and no decoder allocates per read.
- `CanSeek` is false for a stream that can’t seek, and `Seek` throws `NotSupportedException`. `LengthFrames` is −1 when the length can’t be known in advance.
- `leaveOpen: false` disposes the stream with the decoder.

## Untrusted input

- `AudioLimits` caps the channel count, sample rate, packet and frame sizes, metadata, codec setup data and container elements. Every size read from the input is checked before the allocation it guards. `AudioLimits.Default` applies when you pass none.
- Every error about the data is a `OneAudioException`. `AudioFormatException` means malformed data. `UnsupportedAudioFormatException`, a subclass, means valid data in a format that isn’t registered or supported. `AudioLimitExceededException` names the limit, the maximum and what the file asked for.
- Apart from those, the library throws only argument exceptions, `NotSupportedException`, `ObjectDisposedException`, the stream’s own I/O exceptions and `OperationCanceledException`.
- Every parser and decoder is fuzzed. See [Results](https://github.com/recursive-ai-oss/oneaudio-csharp/blob/2ced4d52857c4a762b4a66e7da2885eb30f825c0/README.md#fuzzing) in the README.

For the decoder interface in full, see [Decoding](https://recursiveai.org/oneaudio/docs/api/#decoding) and [Errors and limits](https://recursiveai.org/oneaudio/docs/api/#errors-and-limits).
