diff --git a/src/engine/audio/Audio_Resampler.cpp b/src/engine/audio/Audio_Resampler.cpp index 41299c09..c9769f18 100644 --- a/src/engine/audio/Audio_Resampler.cpp +++ b/src/engine/audio/Audio_Resampler.cpp @@ -66,10 +66,13 @@ size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_ if (mDestRate == mSourceRate) { + // Pass-through, but never write past the caller's buffer: clamp to its + // capacity instead of trusting sourceLength (which is caller/file driven). assert(destCapacity >= sourceLength); - memcpy(dest, src, sourceLength); - sourceProcessed = sourceLength; - return sourceLength; + size_t copied = std::min(sourceLength, destCapacity); + memcpy(dest, src, copied); + sourceProcessed = copied; + return copied; } if (!mContext) diff --git a/src/engine/audio/Audio_WavFile.cpp b/src/engine/audio/Audio_WavFile.cpp index 8a917088..1609dc59 100644 --- a/src/engine/audio/Audio_WavFile.cpp +++ b/src/engine/audio/Audio_WavFile.cpp @@ -150,6 +150,14 @@ bool WavFileReader::open(const std::filesystem::path& p) if (mBits != 16) THROW_READERROR; + // The read path is mono-only: it divides byte counts by AUDIO_CHANNELS + // and starts the resampler with AUDIO_CHANNELS. Reject anything else - + // a multi-channel file would make read() copy more source bytes than the + // caller's (mono-sized) output buffer can hold. Also reject a zero rate, + // which would divide by zero in readRaw() / poison the resampler ratio. + if (mChannels != AUDIO_CHANNELS || mSamplerate == 0) + THROW_READERROR; + // Look for the chunk 'data' mInput->seekg(fmtStart + std::streampos(fmtSize)); diff --git a/src/engine/media/MT_SingleAudioStream.cpp b/src/engine/media/MT_SingleAudioStream.cpp index e01c5c2d..8dac1ee6 100644 --- a/src/engine/media/MT_SingleAudioStream.cpp +++ b/src/engine/media/MT_SingleAudioStream.cpp @@ -37,11 +37,14 @@ void SingleAudioStream::copyPcmTo(Audio::DataWindow& output, int needed) // Number of bytes to fill on this step auto requested = needed - output.filled(); + // requested is in bytes: 16-bit samples at AUDIO_SAMPLERATE/AUDIO_CHANNELS + constexpr int bytesPerMs = AUDIO_SAMPLERATE / 1000 * sizeof(int16_t) * AUDIO_CHANNELS; + auto options = AudioReceiver::DecodeOptions{ .mRealtimeProcessing = true, .mResampleToMainRate = true, .mSkipDecode = false, - .mElapsed = std::chrono::milliseconds(requested / (AUDIO_SAMPLERATE / 1000)) + .mElapsed = std::chrono::milliseconds(requested / bytesPerMs) }; // Try to get the data from receiver / decoder