From 216778b9c5aea6048293d3af05f63af92f9377c8 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 24 Feb 2023 11:12:48 -0500 Subject: [PATCH] Fix SoundPlayer handling of partial reads on streams SoundPlayer assumes that a Read on a stream will return everything asked for, and that's not the case. --- .../src/System/Media/SoundPlayer.cs | 15 ++++++++++++++- .../tests/System/Media/SoundPlayerTests.cs | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs index b1ce057043369a..3d5b536895c1e1 100644 --- a/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs +++ b/src/libraries/System.Windows.Extensions/src/System/Media/SoundPlayer.cs @@ -310,7 +310,20 @@ private void LoadStream(bool loadSync) int streamLen = (int)_stream.Length; _currentPos = 0; _streamData = new byte[streamLen]; - _stream.Read(_streamData, 0, streamLen); +#if NET7_0_OR_GREATER + _stream.ReadExactly(_streamData); +#else + int totalRead = 0; + while (totalRead < streamLen) + { + int bytesRead = _stream.Read(_streamData, totalRead, streamLen - totalRead); + if (bytesRead <= 0) + { + throw new EndOfStreamException(); + } + totalRead += bytesRead; + } +#endif IsLoadCompleted = true; OnLoadCompleted(new AsyncCompletedEventArgs(null, false, null)); } diff --git a/src/libraries/System.Windows.Extensions/tests/System/Media/SoundPlayerTests.cs b/src/libraries/System.Windows.Extensions/tests/System/Media/SoundPlayerTests.cs index f3cb08fd9bc333..1fe2fe53516f31 100644 --- a/src/libraries/System.Windows.Extensions/tests/System/Media/SoundPlayerTests.cs +++ b/src/libraries/System.Windows.Extensions/tests/System/Media/SoundPlayerTests.cs @@ -293,6 +293,22 @@ public void PlayLooping_NullStream_Success() player.PlayLooping(); } + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsSoundPlaySupported))] + [MemberData(nameof(Play_String_TestData))] + [OuterLoop] + public void PlaySync_TrickledData_Success(string sourceLocation) + { + using var player = new SoundPlayer(); + player.Stream = new TrickleStream(File.ReadAllBytes(sourceLocation.Replace("file://", ""))); + player.PlaySync(); + } + + private sealed class TrickleStream : MemoryStream + { + public TrickleStream(byte[] bytes) : base(bytes) { } + public override int Read(byte[] buffer, int offset, int count) => base.Read(buffer, offset, Math.Min(count, 1)); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsSoundPlaySupported))] [OuterLoop] public void PlaySync_NullStream_Success()