mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:17:36 +00:00
LibAudio: Handle unknown-sized streams better
Especially FLAC had an issue here before, but the loader infrastructure itself wouldn't handle end of stream properly if the "available samples" information didn't match up.
This commit is contained in:
parent
e9e95b1899
commit
fc70d88367
3 changed files with 16 additions and 3 deletions
|
@ -22,6 +22,7 @@
|
||||||
#include <LibAudio/FlacTypes.h>
|
#include <LibAudio/FlacTypes.h>
|
||||||
#include <LibAudio/GenericTypes.h>
|
#include <LibAudio/GenericTypes.h>
|
||||||
#include <LibAudio/LoaderError.h>
|
#include <LibAudio/LoaderError.h>
|
||||||
|
#include <LibAudio/MultiChannel.h>
|
||||||
#include <LibAudio/Resampler.h>
|
#include <LibAudio/Resampler.h>
|
||||||
#include <LibAudio/VorbisComment.h>
|
#include <LibAudio/VorbisComment.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
|
@ -338,7 +339,7 @@ ErrorOr<Vector<FixedArray<Sample>>, LoaderError> FlacLoaderPlugin::load_chunks(s
|
||||||
{
|
{
|
||||||
ssize_t remaining_samples = static_cast<ssize_t>(m_total_samples - m_loaded_samples);
|
ssize_t remaining_samples = static_cast<ssize_t>(m_total_samples - m_loaded_samples);
|
||||||
// The first condition is relevant for unknown-size streams (total samples = 0 in the header)
|
// The first condition is relevant for unknown-size streams (total samples = 0 in the header)
|
||||||
if (m_stream->is_eof() || remaining_samples <= 0)
|
if (m_stream->is_eof() || (m_total_samples < NumericLimits<u64>::max() && remaining_samples <= 0))
|
||||||
return Vector<FixedArray<Sample>> {};
|
return Vector<FixedArray<Sample>> {};
|
||||||
|
|
||||||
size_t samples_to_read = min(samples_to_read_from_input, remaining_samples);
|
size_t samples_to_read = min(samples_to_read_from_input, remaining_samples);
|
||||||
|
|
|
@ -68,6 +68,9 @@ ErrorOr<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(NonnullO
|
||||||
|
|
||||||
LoaderSamples Loader::get_more_samples(size_t samples_to_read_from_input)
|
LoaderSamples Loader::get_more_samples(size_t samples_to_read_from_input)
|
||||||
{
|
{
|
||||||
|
if (m_plugin_at_end_of_stream)
|
||||||
|
return FixedArray<Sample> {};
|
||||||
|
|
||||||
size_t remaining_samples = total_samples() - loaded_samples();
|
size_t remaining_samples = total_samples() - loaded_samples();
|
||||||
size_t samples_to_read = min(remaining_samples, samples_to_read_from_input);
|
size_t samples_to_read = min(remaining_samples, samples_to_read_from_input);
|
||||||
auto samples = TRY(FixedArray<Sample>::create(samples_to_read));
|
auto samples = TRY(FixedArray<Sample>::create(samples_to_read));
|
||||||
|
@ -88,8 +91,10 @@ LoaderSamples Loader::get_more_samples(size_t samples_to_read_from_input)
|
||||||
while (sample_index < samples_to_read) {
|
while (sample_index < samples_to_read) {
|
||||||
auto chunk_data = TRY(m_plugin->load_chunks(samples_to_read - sample_index));
|
auto chunk_data = TRY(m_plugin->load_chunks(samples_to_read - sample_index));
|
||||||
chunk_data.remove_all_matching([](auto& chunk) { return chunk.is_empty(); });
|
chunk_data.remove_all_matching([](auto& chunk) { return chunk.is_empty(); });
|
||||||
if (chunk_data.is_empty())
|
if (chunk_data.is_empty()) {
|
||||||
|
m_plugin_at_end_of_stream = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
for (auto& chunk : chunk_data) {
|
for (auto& chunk : chunk_data) {
|
||||||
if (sample_index < samples_to_read) {
|
if (sample_index < samples_to_read) {
|
||||||
auto count = min(samples_to_read - sample_index, chunk.size());
|
auto count = min(samples_to_read - sample_index, chunk.size());
|
||||||
|
|
|
@ -91,10 +91,15 @@ public:
|
||||||
// Will only read less samples if we're at the end of the stream.
|
// Will only read less samples if we're at the end of the stream.
|
||||||
LoaderSamples get_more_samples(size_t samples_to_read_from_input = 128 * KiB);
|
LoaderSamples get_more_samples(size_t samples_to_read_from_input = 128 * KiB);
|
||||||
|
|
||||||
MaybeLoaderError reset() const { return m_plugin->reset(); }
|
MaybeLoaderError reset() const
|
||||||
|
{
|
||||||
|
m_plugin_at_end_of_stream = false;
|
||||||
|
return m_plugin->reset();
|
||||||
|
}
|
||||||
MaybeLoaderError seek(int const position) const
|
MaybeLoaderError seek(int const position) const
|
||||||
{
|
{
|
||||||
m_buffer.clear_with_capacity();
|
m_buffer.clear_with_capacity();
|
||||||
|
m_plugin_at_end_of_stream = false;
|
||||||
return m_plugin->seek(position);
|
return m_plugin->seek(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +119,8 @@ private:
|
||||||
explicit Loader(NonnullOwnPtr<LoaderPlugin>);
|
explicit Loader(NonnullOwnPtr<LoaderPlugin>);
|
||||||
|
|
||||||
mutable NonnullOwnPtr<LoaderPlugin> m_plugin;
|
mutable NonnullOwnPtr<LoaderPlugin> m_plugin;
|
||||||
|
// The plugin can signal an end of stream by returning no (or only empty) chunks.
|
||||||
|
mutable bool m_plugin_at_end_of_stream { false };
|
||||||
mutable Vector<Sample, loader_buffer_size> m_buffer;
|
mutable Vector<Sample, loader_buffer_size> m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue