From 7760c41bd96c1384a5ca4f26c27c99a6fd84d333 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Wed, 22 Nov 2017 19:35:38 +0000 Subject: [PATCH] Avoid array resizing in OpenAlAsyncLoadSound. - Where it is accessible, use the length of the stream to presize the MemoryStream to the correct size. - Instead of copying out the result via ToArray, grab the underlying buffer via GetBuffer and use that to create the sound source. This avoids extraneous copying of the array containing the audio. --- .../Primitives/ReadOnlyAdapterStream.cs | 2 +- OpenRA.Mods.Common/FileFormats/AudReader.cs | 5 ++++ OpenRA.Platforms.Default/OpenAlSoundEngine.cs | 26 +++++++++++++------ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs b/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs index 91621400e9..585d285edb 100644 --- a/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs +++ b/OpenRA.Game/Primitives/ReadOnlyAdapterStream.cs @@ -39,7 +39,7 @@ namespace OpenRA.Primitives public sealed override bool CanRead { get { return true; } } public sealed override bool CanWrite { get { return false; } } - public sealed override long Length { get { throw new NotSupportedException(); } } + public override long Length { get { throw new NotSupportedException(); } } public sealed override long Position { get { throw new NotSupportedException(); } diff --git a/OpenRA.Mods.Common/FileFormats/AudReader.cs b/OpenRA.Mods.Common/FileFormats/AudReader.cs index 5f98e5bed0..dcdaa44a81 100644 --- a/OpenRA.Mods.Common/FileFormats/AudReader.cs +++ b/OpenRA.Mods.Common/FileFormats/AudReader.cs @@ -170,6 +170,11 @@ namespace OpenRA.Mods.Common.FileFormats this.dataSize = dataSize; } + public override long Length + { + get { return outputSize; } + } + protected override bool BufferData(Stream baseStream, Queue data) { if (dataSize <= 0) diff --git a/OpenRA.Platforms.Default/OpenAlSoundEngine.cs b/OpenRA.Platforms.Default/OpenAlSoundEngine.cs index 0086be0134..c55093f649 100644 --- a/OpenRA.Platforms.Default/OpenAlSoundEngine.cs +++ b/OpenRA.Platforms.Default/OpenAlSoundEngine.cs @@ -193,7 +193,7 @@ namespace OpenRA.Platforms.Default public ISoundSource AddSoundSourceFromMemory(byte[] data, int channels, int sampleBits, int sampleRate) { - return new OpenAlSoundSource(data, channels, sampleBits, sampleRate); + return new OpenAlSoundSource(data, data.Length, channels, sampleBits, sampleRate); } public ISound Play2D(ISoundSource soundSource, bool loop, bool relative, WPos pos, float volume, bool attenuateVolume) @@ -389,11 +389,11 @@ namespace OpenRA.Platforms.Default public uint Buffer { get { return buffer; } } public int SampleRate { get; private set; } - public OpenAlSoundSource(byte[] data, int channels, int sampleBits, int sampleRate) + public OpenAlSoundSource(byte[] data, int byteCount, int channels, int sampleBits, int sampleRate) { SampleRate = sampleRate; AL10.alGenBuffers(new IntPtr(1), out buffer); - AL10.alBufferData(buffer, OpenAlSoundEngine.MakeALFormat(channels, sampleBits), data, new IntPtr(data.Length), new IntPtr(sampleRate)); + AL10.alBufferData(buffer, OpenAlSoundEngine.MakeALFormat(channels, sampleBits), data, new IntPtr(byteCount), new IntPtr(sampleRate)); } protected virtual void Dispose(bool disposing) @@ -502,7 +502,7 @@ namespace OpenRA.Platforms.Default { // Load a silent buffer into the source. Without this, // attempting to change the state (i.e. play/pause) the source fails on some systems. - var silentSource = new OpenAlSoundSource(SilentData, channels, sampleBits, sampleRate); + var silentSource = new OpenAlSoundSource(SilentData, SilentData.Length, channels, sampleBits, sampleRate); AL10.alSourcei(source, AL10.AL_BUFFER, (int)silentSource.Buffer); playTask = Task.Run(async () => @@ -510,7 +510,16 @@ namespace OpenRA.Platforms.Default MemoryStream memoryStream; using (stream) { - memoryStream = new MemoryStream(); + try + { + memoryStream = new MemoryStream((int)stream.Length); + } + catch (NotSupportedException) + { + // Fallback for stream types that don't support Length. + memoryStream = new MemoryStream(); + } + try { await stream.CopyToAsync(memoryStream, 81920, cts.Token); @@ -525,10 +534,11 @@ namespace OpenRA.Platforms.Default } } - var data = memoryStream.ToArray(); + var data = memoryStream.GetBuffer(); + var dataLength = (int)memoryStream.Length; var bytesPerSample = sampleBits / 8f; - var lengthInSecs = data.Length / (channels * bytesPerSample * sampleRate); - using (var soundSource = new OpenAlSoundSource(data, channels, sampleBits, sampleRate)) + var lengthInSecs = dataLength / (channels * bytesPerSample * sampleRate); + using (var soundSource = new OpenAlSoundSource(data, dataLength, channels, sampleBits, sampleRate)) { // Need to stop the source, before attaching the real input and deleting the silent one. AL10.alSourceStop(source);