1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-10-01 08:20:47 +00:00

Enqueue audio when receiving it

While Minecraft will automatically push a new buffer when one is
exhausted, this doesn't help if there's only a single buffer in the
queue, and you end up with stutter.

By enquing a buffer when receiving sound we ensure there's always
something queued. I'm not 100% happy with this solution, but it does
alleviate some of the concerns in #993.

Also reduce the size of the client buffer to 0.5s from 1.5s. This is
still enough to ensure seamless audio when the server is running slow (I
tested at 13 tps, but should be able to go much worse).
This commit is contained in:
Jonathan Coates 2021-12-19 19:50:43 +00:00
parent 8a1067940d
commit aa36b49c50
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
7 changed files with 35 additions and 4 deletions

View File

@ -114,7 +114,9 @@ class DfpwmStream implements IAudioStream
} }
result.flip(); result.flip();
return result;
// This is naughty, but ensures we're not enqueuing empty buffers when the stream is exhausted.
return result.remaining() == 0 ? null : result;
} }
@Override @Override
@ -122,4 +124,9 @@ class DfpwmStream implements IAudioStream
{ {
buffers.clear(); buffers.clear();
} }
public boolean isEmpty()
{
return buffers.isEmpty();
}
} }

View File

@ -28,8 +28,20 @@ public class SpeakerInstance
public synchronized void pushAudio( ByteBuf buffer ) public synchronized void pushAudio( ByteBuf buffer )
{ {
if( currentStream == null ) currentStream = new DfpwmStream(); SpeakerSound sound = this.sound;
DfpwmStream stream = currentStream;
if( stream == null ) stream = currentStream = new DfpwmStream();
boolean exhausted = stream.isEmpty();
currentStream.push( buffer ); currentStream.push( buffer );
// If we've got nothing left in the buffer, enqueue an additional one just in case.
if( exhausted && sound != null && sound.stream == stream && sound.source != null )
{
sound.executor.execute( () -> {
if( !sound.source.stopped() ) sound.source.pumpBuffers( 1 );
} );
}
} }
public void playAudio( Vector3d position, float volume ) public void playAudio( Vector3d position, float volume )

View File

@ -32,6 +32,9 @@ public class SpeakerManager
event.getSource().attachBufferStream( sound.stream ); event.getSource().attachBufferStream( sound.stream );
event.getSource().play(); event.getSource().play();
sound.source = event.getSource();
sound.executor = event.getManager().executor;
} }
public static SpeakerInstance getSound( UUID source ) public static SpeakerInstance getSound( UUID source )

View File

@ -8,14 +8,18 @@ package dan200.computercraft.client.sound;
import net.minecraft.client.audio.IAudioStream; import net.minecraft.client.audio.IAudioStream;
import net.minecraft.client.audio.ITickableSound; import net.minecraft.client.audio.ITickableSound;
import net.minecraft.client.audio.LocatableSound; import net.minecraft.client.audio.LocatableSound;
import net.minecraft.client.audio.SoundSource;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3d;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.concurrent.Executor;
public class SpeakerSound extends LocatableSound implements ITickableSound public class SpeakerSound extends LocatableSound implements ITickableSound
{ {
SoundSource source;
Executor executor;
DfpwmStream stream; DfpwmStream stream;
SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vector3d position, float volume, float pitch ) SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vector3d position, float volume, float pitch )

View File

@ -28,7 +28,7 @@ class DfpwmState
* The minimum size of the client's audio buffer. Once we have less than this on the client, we should send another * The minimum size of the client's audio buffer. Once we have less than this on the client, we should send another
* batch of audio. * batch of audio.
*/ */
private static final long CLIENT_BUFFER = (long) (SECOND * 1.5); private static final long CLIENT_BUFFER = (long) (SECOND * 0.5);
private static final int PREC = 10; private static final int PREC = 10;

View File

@ -343,7 +343,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
// TODO: Use ArgumentHelpers instead? // TODO: Use ArgumentHelpers instead?
int length = audio.length(); int length = audio.length();
if( length <= 0 ) throw new LuaException( "Cannot play empty audio" ); if( length <= 0 ) throw new LuaException( "Cannot play empty audio" );
if( length > 1024 * 16 * 8 ) throw new LuaException( "Audio data is too large" ); if( length > 128 * 1024 ) throw new LuaException( "Audio data is too large" );
DfpwmState state; DfpwmState state;
synchronized( lock ) synchronized( lock )

View File

@ -2,7 +2,12 @@
public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch
public net.minecraft.client.renderer.FirstPersonRenderer func_228401_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;IFFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson public net.minecraft.client.renderer.FirstPersonRenderer func_228401_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;IFFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson
public net.minecraft.client.renderer.FirstPersonRenderer func_228403_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/util/HandSide;)V # renderArm public net.minecraft.client.renderer.FirstPersonRenderer func_228403_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/util/HandSide;)V # renderArm
# ClientTableFormatter # ClientTableFormatter
public net.minecraft.client.gui.NewChatGui func_146234_a(Lnet/minecraft/util/text/ITextComponent;I)V # printChatMessageWithOptionalDeletion public net.minecraft.client.gui.NewChatGui func_146234_a(Lnet/minecraft/util/text/ITextComponent;I)V # printChatMessageWithOptionalDeletion
public net.minecraft.client.gui.NewChatGui func_146242_c(I)V # deleteChatLine public net.minecraft.client.gui.NewChatGui func_146242_c(I)V # deleteChatLine
public net.minecraft.client.Minecraft field_71462_r # currentScreen public net.minecraft.client.Minecraft field_71462_r # currentScreen
# SpeakerInstance/SpeakerManager
public net.minecraft.client.audio.SoundSource func_216421_a(I)V # pumpBuffers
public net.minecraft.client.audio.SoundEngine field_217940_j # executor