Fix some node timing errors.

This commit fixes a bug relating to nodes with a scheduled start/stop
time. Whether or not the node is considered started or stopped is being
incorrectly reported by `ma_node_get_state_by_time_range()`.

Another issue is fixed in `ma_node_read_pcm_frames()`, which is related
to the fix above, where the frame count can underflow thereby resulting
in a crash.

Public issue https://github.com/mackron/miniaudio/issues/969
This commit is contained in:
David Reid
2026-01-06 13:05:40 +10:00
parent 3b4e87848b
commit 111d620c63
+19 -9
View File
@@ -74965,12 +74965,12 @@ MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_ui
its start time not having been reached yet. Also, the stop time may have also been reached in
which case it'll be considered stopped.
*/
if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) {
return ma_node_state_stopped; /* Start time has not yet been reached. */
if (ma_node_get_state_time(pNode, ma_node_state_stopped) < globalTimeBeg) {
return ma_node_state_stopped; /* End time is before the start of the range. */
}
if (ma_node_get_state_time(pNode, ma_node_state_stopped) <= globalTimeEnd) {
return ma_node_state_stopped; /* Stop time has been reached. */
if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeEnd) {
return ma_node_state_stopped; /* Start time is after the end of the range. */
}
/* Getting here means the node is marked as started and is within its start/stop times. */
@@ -75050,14 +75050,14 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
return MA_INVALID_ARGS; /* Invalid output bus index. */
}
globalTimeBeg = globalTime;
globalTimeEnd = globalTime + frameCount;
/* Don't do anything if we're in a stopped state. */
if (ma_node_get_state_by_time_range(pNode, globalTime, globalTime + frameCount) != ma_node_state_started) {
if (ma_node_get_state_by_time_range(pNode, globalTimeBeg, globalTimeEnd) != ma_node_state_started) {
return MA_SUCCESS; /* We're in a stopped state. This is not an error - we just need to not read anything. */
}
globalTimeBeg = globalTime;
globalTimeEnd = globalTime + frameCount;
startTime = ma_node_get_state_time(pNode, ma_node_state_started);
stopTime = ma_node_get_state_time(pNode, ma_node_state_stopped);
@@ -75070,11 +75070,16 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
therefore need to offset it by a number of frames to accommodate. The same thing applies for
the stop time.
*/
timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(globalTimeEnd - startTime) : 0;
timeOffsetBeg = (globalTimeBeg < startTime) ? (ma_uint32)(startTime - globalTimeBeg) : 0;
timeOffsetEnd = (globalTimeEnd > stopTime) ? (ma_uint32)(globalTimeEnd - stopTime) : 0;
/* Trim based on the start offset. We need to silence the start of the buffer. */
if (timeOffsetBeg > 0) {
MA_ASSERT(timeOffsetBeg <= frameCount);
if (timeOffsetBeg > frameCount) {
timeOffsetBeg = frameCount;
}
ma_silence_pcm_frames(pFramesOut, timeOffsetBeg, ma_format_f32, ma_node_get_output_channels(pNode, outputBusIndex));
pFramesOut += timeOffsetBeg * ma_node_get_output_channels(pNode, outputBusIndex);
frameCount -= timeOffsetBeg;
@@ -75082,6 +75087,11 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde
/* Trim based on the end offset. We don't need to silence the tail section because we'll just have a reduced value written to pFramesRead. */
if (timeOffsetEnd > 0) {
MA_ASSERT(timeOffsetEnd <= frameCount);
if (timeOffsetEnd > frameCount) {
timeOffsetEnd = frameCount;
}
frameCount -= timeOffsetEnd;
}