[mod_silk] Bound decode loop to the codec's frame limit (#3116)

`switch_silk_decode()` ran its `do`/`while` decode loop while the SDK
kept reporting more internal frames, advancing the output pointer each
pass with no cap. The destination is a fixed-size PCM buffer, so a
stream reporting more internal frames than a conformant packet can
carry let the accumulated write run past its end.

Stop after `MAX_INPUT_FRAMES` internal frames, the most a conformant
SILK packet can hold, so the accumulated PCM stays within the
destination regardless of the bitstream.

Declare the per-pass sample count inside the loop so it resets to zero
each iteration, and advance the output pointer and length only when it
is positive. A pass that writes no samples, including a tolerated FEC
payload error that leaves the count untouched, then contributes nothing
instead of advancing on a stale count from an earlier pass or on a
negative value.
This commit is contained in:
Dmitry Verenitsin authored and GitHub committed 2026-08-09 00:05:39 +03:00
1 parent 2c8802e64b
commit bc1e992dab
1 file changed
+16 -5
+16 -5
View File
@@ -328,13 +328,13 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec,
uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag)
{
struct silk_context *context = codec->private_info;
SKP_int16 ret, len;
int16_t *target = decoded_data;
switch_core_session_t *session = codec->session;
switch_jb_t *jb = NULL;
SKP_int lost_flag = (*flag & SFF_PLC);
switch_bool_t did_lbrr = SWITCH_FALSE;
int i;
int decoded_frames = 0;
*decoded_data_len = 0;
@@ -368,6 +368,8 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec,
}
do {
SKP_int16 ret, len = 0;
ret = (SKP_int16)SKP_Silk_SDK_Decode(context->dec_state,
&context->decoder_object,
lost_flag,
@@ -379,12 +381,21 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec,
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SKP_Silk_Decode returned %d!\n", ret);
printSilkError(ret);
/* if FEC was activated, we can ignore bit errors*/
if (! (ret == SKP_SILK_DEC_PAYLOAD_ERROR && did_lbrr))
return SWITCH_STATUS_FALSE;
if (! (ret == SKP_SILK_DEC_PAYLOAD_ERROR && did_lbrr)) {
return SWITCH_STATUS_FALSE;
}
}
target += len;
*decoded_data_len += (len * 2);
if (len > 0) {
target += len;
*decoded_data_len += (len * 2);
}
/* A conformant SILK packet decodes to at most MAX_INPUT_FRAMES internal frames; stop there so
the accumulated PCM cannot run past the destination buffer regardless of the bitstream. */
if (++decoded_frames >= MAX_INPUT_FRAMES) {
break;
}
} while (context->decoder_object.moreInternalDecoderFrames);
return SWITCH_STATUS_SUCCESS;