Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Src/Metadata/Readers/Format/Mp3Reader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ private Result ParseFrameHeader(byte[] header, SoundFormatInfo info)
new[,] { { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } };
}

info.Bitrate = layerBitrateTable[0, bitrateIndex] * 1000;
var bitrateRow = layerId == 1 ? mpegVersionIndex : 0;
info.Bitrate = layerBitrateTable[bitrateRow, bitrateIndex] * 1000;
info.SampleRate = SampleRateTable[mpegVersionIndex, sampleRateIndex];
info.ChannelCount = channelMode == 3 ? 1 : 2;

Expand Down
55 changes: 17 additions & 38 deletions Src/Providers/StreamDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,51 +123,30 @@ public StreamDataProvider(AudioEngine engine, AudioFormat format, Stream stream)
/// Gets the total length of the audio data in samples.
/// </summary>
/// <remarks>
/// Two independent length estimates are available at this layer:
/// <list type="bullet">
/// <item><c>_decoder.Length</c> — returned by the underlying codec (e.g. <c>ma_decoder_get_length_in_pcm_frames</c>).</item>
/// <item><c>FormatInfo.Duration</c> — read by <see cref="SoundMetadataReader"/> from ID3/Xing/Info tags.</item>
/// </list>
/// Both can be wrong for VBR MP3s without a Xing/Info header, but they fail independently: the metadata
/// reader and the codec use different parsing paths. When they disagree, we pick the <b>larger</b> value.
/// A too-small length is far worse than a too-large one — it makes the displayed <c>Duration</c> lie,
/// breaks seeking near the end, can trigger premature end-of-stream handling, and produces impossible
/// states like <c>Time &gt; Duration</c>
/// Prefers the decoder's reported length when available. Metadata duration is a fallback
/// estimate and can overstate the audio length, for example for VBR MP3s without a Xing header.
/// The fallback uses the decoder's output sample rate and channel count so its sample units
/// agree with decoded data, including when the source is resampled or remixed.
/// </remarks>
public int Length
{
get
{
var decoderLength = _decoder.Length;

int metadataLength;
if (FormatInfo != null
&& FormatInfo.Duration > TimeSpan.Zero
&& FormatInfo.SampleRate > 0
&& FormatInfo.ChannelCount > 0)
{
var metadataLengthSamples = FormatInfo.Duration.TotalSeconds
* FormatInfo.SampleRate
* FormatInfo.ChannelCount;

if (metadataLengthSamples is >= 0 and <= int.MaxValue)
metadataLength = (int)metadataLengthSamples;
else
metadataLength = 0;
}
else
{
metadataLength = 0;
}
if (decoderLength > 0)
return decoderLength;

return decoderLength switch
{
// Prefer the larger value when both are available. See the XML doc above for the rationale.
// Special case: if one of them is 0 (unknown), use the other.
> 0 when metadataLength > 0 => Math.Max(decoderLength, metadataLength),
> 0 => decoderLength,
_ => metadataLength
};
if (FormatInfo == null || FormatInfo.Duration <= TimeSpan.Zero
|| _decoder.SampleRate <= 0 || _decoder.Channels <= 0)
return 0;

var metadataLengthSamples = FormatInfo.Duration.TotalSeconds
* _decoder.SampleRate
* _decoder.Channels;
Comment on lines 135 to +145

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Regression checks aren't checked in

The checks described in the PR live outside the repository, so they cannot catch future changes that restore the wrong duration or seek limit. Please check in tests for the MPEG-version bitrate rows, a positive decoder length smaller than metadata, and an unknown decoder length with different source and output formats. Include invalid durations and the int.MaxValue boundary.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Src/Providers/StreamDataProvider.cs
Line: 135-145

Comment:
**Regression checks aren't checked in**

The checks described in the PR live outside the repository, so they cannot catch future changes that restore the wrong duration or seek limit. Please check in tests for the MPEG-version bitrate rows, a positive decoder length smaller than metadata, and an unknown decoder length with different source and output formats. Include invalid durations and the `int.MaxValue` boundary.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!


return metadataLengthSamples is >= 0 and <= int.MaxValue
? (int)metadataLengthSamples
: 0;
}
}

Expand Down
Loading