Send every ready live-capture frame per tick and cap the timer's catch-up burst
A mic running faster than the 20 ms timer filled the queue until frames were dropped; live sources now drain each tick. The catch-up clamp was inverted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,15 @@ public interface Microphone {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether {@link #provide} hands out frames captured on a clock of their own, such as a sound
|
||||||
|
* card's. That clock drifts against the send timer, so each tick then sends every frame that is
|
||||||
|
* ready instead of one, keeping the drift from piling up as latency or overflowing a queue.
|
||||||
|
*/
|
||||||
|
default boolean isLiveCapture() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** How many copies follow each voice packet, {@link #getRedundancyDelay} apart. */
|
/** How many copies follow each voice packet, {@link #getRedundancyDelay} apart. */
|
||||||
default int getRedundancyCopies() {
|
default int getRedundancyCopies() {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
+8
-3
@@ -596,6 +596,7 @@ public class LocalTeamspeakClientSocket
|
|||||||
new MicrophoneTask()
|
new MicrophoneTask()
|
||||||
);
|
);
|
||||||
microphoneThread.setDaemon(true);
|
microphoneThread.setDaemon(true);
|
||||||
|
microphoneThread.setPriority(Thread.MAX_PRIORITY);
|
||||||
|
|
||||||
if (getState() != ClientConnectionState.DISCONNECTED)
|
if (getState() != ClientConnectionState.DISCONNECTED)
|
||||||
microphoneThread.start();
|
microphoneThread.start();
|
||||||
@@ -693,9 +694,11 @@ public class LocalTeamspeakClientSocket
|
|||||||
// TODO
|
// TODO
|
||||||
// Set a state and send a muted event
|
// Set a state and send a muted event
|
||||||
} else if (microphone.isReady()) {
|
} else if (microphone.isReady()) {
|
||||||
byte[] data = microphone.provide();
|
boolean live = microphone.isLiveCapture();
|
||||||
if (data.length <= 0)
|
byte[] data;
|
||||||
return;
|
do {
|
||||||
|
data = microphone.provide();
|
||||||
|
if (data.length <= 0) break;
|
||||||
|
|
||||||
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
||||||
|
|
||||||
@@ -712,7 +715,9 @@ public class LocalTeamspeakClientSocket
|
|||||||
// All we are really concerned about here is a disconnection event, in which case the loop
|
// All we are really concerned about here is a disconnection event, in which case the loop
|
||||||
// will exit.
|
// will exit.
|
||||||
getExceptionHandler().accept(e);
|
getExceptionHandler().accept(e);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
} while (live && microphone.isReady());
|
||||||
} else if (wasSendingAudio) {
|
} else if (wasSendingAudio) {
|
||||||
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
PacketBody0Voice voice = new PacketBody0Voice(getRole().getOut());
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ public class HighPrecisionTimer extends Thread {
|
|||||||
|
|
||||||
now = System.nanoTime();
|
now = System.nanoTime();
|
||||||
|
|
||||||
// Clamp the next target to the maximum "drift" allowed
|
// After a stall, catch up at most the allowed number of ticks rather than all of them
|
||||||
if (nextTarget - now > maximumDriftInNanos)
|
if (now - nextTarget > maximumDriftInNanos)
|
||||||
nextTarget = now - maximumDriftInNanos;
|
nextTarget = now - maximumDriftInNanos;
|
||||||
|
|
||||||
if (sleepFor(nextTarget - now)) {
|
if (sleepFor(nextTarget - now)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user