namespace DeepDrftContent.Processors; /// /// Bounded-buffer streaming primitives shared by the audio processors on the store path. None of /// these hold the whole file in memory: copies move a fixed window at a time, and the header read /// caps its allocation regardless of file size. /// internal static class AudioStoreStream { private const int CopyBufferSize = 81920; // 80 KB — matches the controller staging copy. /// /// Bounded disk-to-disk copy of into . /// Used for passthrough formats whose stored bytes equal the source bytes. Hand-rolled rather than /// because FileStream's override writes in 128 KB /// blocks; this keeps every write at or below , so peak managed memory /// is provably O(buffer), never O(filesize). /// public static async Task CopyFileAsync(string sourcePath, Stream destination, CancellationToken ct) { await using var src = new FileStream( sourcePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: CopyBufferSize, useAsync: true); var buffer = new byte[CopyBufferSize]; int read; while ((read = await src.ReadAsync(buffer, ct)) > 0) { await destination.WriteAsync(buffer.AsMemory(0, read), ct); } } /// /// Reads at most bytes from the start of — enough /// for header/metadata parsing without loading the (potentially ~GB) body. Bounds the allocation /// at min(cap, fileLength). Size-based metadata (e.g. average bitrate) must use the true /// file length, supplied separately, not the prefix length. /// public static async Task ReadPrefixAsync(string path, long cap, CancellationToken ct) { await using var fs = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: CopyBufferSize, useAsync: true); var length = (int)Math.Min(cap, fs.Length); var buffer = new byte[length]; var total = 0; while (total < length) { var read = await fs.ReadAsync(buffer.AsMemory(total, length - total), ct); if (read == 0) break; total += read; } return total == length ? buffer : buffer[..total]; } }