readMp3() never down-mixes stereo - returns interleaved samples where the API contract says mono
Maintainer thường phản hồi trong vòng 2 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 25/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Đình trệ
- Công nghệ
- cpp
- Lĩnh vực
- audio-video-rtc
Hướng nghiên cứu
Bắt đầu với vòng lặp giải mã MP3 trong src/audio/audio_utils.cpp:162-209 và so sánh cách xử lý kênh của nó với đường dẫn WAV tại :123-134. Cập nhật các bài kiểm thử tiện ích âm thanh trong src/test/audio/audio_utils_test.cpp:173 và :190 để việc giải mã stereo trả về một sample cho mỗi frame, đồng thời xác minh rằng cả đường dẫn có resampling và không resampling đều sử dụng đầu ra có độ dài mono.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Describe the bug
readMp3() never down-mixes stereo input, so it returns interleaved L/R samples where the API contract says mono.
src/audio/audio_utils.hpp:35 documents readMp3() as "Decode MP3 data into mono float32 PCM samples", and line 39 says the same for readWithoutResample(). The WAV path honours that contract — src/audio/audio_utils.cpp:123-134 explicitly down-mixes the channel pair:
// convert to mono, float
...
} else {
for (uint64_t i = 0; i < n; i++) {
pcmf32[i] = float(pcm16[2 * i] + pcm16[2 * i + 1]) / 65536.0f;
}
}
The MP3 path does not. src/audio/audio_utils.cpp:194 appends every decoded channel verbatim:
pcmf32.insert(pcmf32.end(), tempBuffer, tempBuffer + framesRead * mp3.channels);
So for a 2-channel file pcmf32 holds L0,R0,L1,R1,… and is twice as long as the frame count. Stereo is an explicitly supported input — src/audio/audio_utils.cpp:162-165 only rejects channels > 2 — so this is a reachable path, not a guarded edge case.
Two consequences:
1. No-resample path. readWithoutResample() feeds the chat-completions input_audio field. src/llm/io_processing/input_processors/audio_decoding_processor.cpp:70-76 copies the returned vector straight into a 1-D f32 tensor that the pipeline treats as a mono waveform:
std::vector<float> pcm = ovms::audio_utils::readWithoutResample(...);
ov::Tensor audioTensor(ov::element::f32, ov::Shape{pcm.size()});
std::memcpy(audioTensor.data<float>(), pcm.data(), pcm.size() * sizeof(float));
The model receives an interleaved L/R stream read as mono — garbage audio at 2x the expected duration.
2. Resample path. src/audio/audio_utils.cpp:209 uses pcmf32.size() (samples, not frames) as if it were a mono sample count:
size_t outputLength = (size_t)(pcmf32.size() * targetSampleRate / mp3.sampleRate);
so the output is 2x too long and resample_audio() linearly interpolates between adjacent L and R samples.
The existing tests already record the symptom without naming it — src/test/audio/audio_utils_test.cpp:173 and :190:
// For this frame, actual decoded size is 2304 samples (stereo or decoder output)
size_t expectedDecodedSize = 2304 * sizeof(float);
2304 = 1152 frames x 2 channels, i.e. one MPEG-1 Layer III joint-stereo frame returned interleaved. The WAV equivalent would have been 1152.
To Reproduce
- Create a 2-channel MP3:
ffmpeg -f lavfi -i "sine=frequency=440:duration=3" -ac 2 stereo.mp3 - Start a servable that accepts
input_audio(audio-capable chat model). - POST a chat completion containing:
{"type":"input_audio","input_audio":{"data":"<base64 of stereo.mp3>","format":"mp3"}} - Compare with the same content converted to a stereo WAV.
The MP3 request produces a nonsense transcription of roughly double the real duration; the WAV request transcribes correctly.
Expected behavior
readMp3() down-mixes 2-channel input to mono before returning, exactly as readWav() does, so the documented "mono float32 PCM samples" contract holds for both formats and for both the resample and no-resample paths.
Logs
At --log_level DEBUG, AudioDecodingProcessor: decoded audio {} samples, format='mp3' reports twice the frame count for a stereo MP3.
Configuration
- OVMS version:
main@fadb3314 - Any audio-capable servable accepting
input_audio, or any/v3/audio/transcriptionsservable fed an MP3 - CPU
- N/A
- Any 2-channel MP3
Additional context
Suggested fix: down-mix inside the decode loop (average the channel pair per frame) rather than after it, so the streaming size guard at src/audio/audio_utils.cpp:195 keeps measuring the final buffer. Note that validateAudioFileSize(...) at :172 passes mp3.channels, while the WAV call at :110 passes 1 /*will be downmixed to mono*/ — that argument should become 1 for MP3 too once the down-mix is added.
Test to add: decode a known 2-channel MP3 frame and assert result.size() == totalPCMFrameCount (currently == 2 * totalPCMFrameCount). The existing 2304 expectations in src/test/audio/audio_utils_test.cpp become 1152.
A separate, much smaller thing noticed in the same function: the overflow branch at src/audio/audio_utils.cpp:190-193 calls drmp3_uninit(&mp3) and then throws, but the enclosing catch (...) at :197-200 calls drmp3_uninit(&mp3) again before rethrowing — a double-uninit. It is currently unreachable in practice (AUDIO_BUFFER_SIZE_LIMIT is SIZE_MAX / sizeof(float)), but it disappears naturally with the fix above.
I have a patch for this and will open a PR shortly.
- Ngôn ngữ chính
- C++
- Star
- 932
- Fork
- 278
- Merge trung bình
- 2 ngày 15 giờ
- Pull request đã merge (30 ngày)
- 60
Chuẩn bị môi trường
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của openvinotoolkit/model_server
-
bug
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 68/100
openvinotoolkit/model_server#4609 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
`/v3/models` lists every model twice when `group_name` and `--idle_unload_timeout_seconds` are combinedCó thể đã có người làm @atobiszei đã nhận 3 ngày trước. Đang mở
openvinotoolkit/model_server#4604 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Idle unload never happens again if the client disconnects while a sleeping graph is waking upCó thể đã có người làm @atobiszei đã nhận 3 ngày trước. Đang mở
openvinotoolkit/model_server#4603 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 2 ngày
-
bug
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
openvinotoolkit/model_server#4599 · 4 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 55/100
openvinotoolkit/model_server#4586 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 2 ngày
Tất cả issue của openvinotoolkit/model_server
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
grumpycoders/pcsx-redux#2171 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
bytedance/trae-agent#524 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Update OPENEXR_IMATH_TAGĐang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 84/100
AcademySoftwareFoundation/openexr#2683 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 85/100
microsoft/onnxruntime#32881 ·
Maintainer thường phản hồi trong vòng 1 ngày