mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
This prevents PlaybackManager's seek while enabling an audio track from causing the AudioMixingSink to push audio blocks forward unnecessarily. Previously, the seek would cause the initial block or blocks to repeat from the perspective of AudioMixingSink, so it would think that it needs to shift the first block after the seek forward by a few samples. By moving this to the AudioDataProvider, we can clear the last sample index every time the decoder is flushed, ensuring that the block shifting always makes sense. By doing this in AudioMixingSink instead of the Decoder implementations, we avoid having to duplicate this shifting logic across multiple implementations. This also fixes an issue where multiple audio blocks occupying the same timestamp would be skipped while seeking, causing a significant break in audio.
71 lines
1.8 KiB
C++
71 lines
1.8 KiB
C++
/*
|
|
* Copyright (c) 2025, Gregory Bertilson <gregory@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/FixedArray.h>
|
|
#include <AK/Time.h>
|
|
|
|
namespace Media {
|
|
|
|
class AudioBlock {
|
|
public:
|
|
using Data = FixedArray<float>;
|
|
|
|
u32 sample_rate() const { return m_sample_rate; }
|
|
u8 channel_count() const { return m_channel_count; }
|
|
AK::Duration timestamp() const { return m_timestamp; }
|
|
i64 timestamp_in_samples() const { return m_timestamp_in_samples; }
|
|
Data& data() { return m_data; }
|
|
Data const& data() const { return m_data; }
|
|
|
|
void clear()
|
|
{
|
|
m_sample_rate = 0;
|
|
m_channel_count = 0;
|
|
m_timestamp_in_samples = 0;
|
|
m_data = Data();
|
|
}
|
|
template<typename Callback>
|
|
void emplace(u32 sample_rate, u8 channel_count, AK::Duration timestamp, Callback data_callback)
|
|
{
|
|
VERIFY(sample_rate != 0);
|
|
VERIFY(channel_count != 0);
|
|
VERIFY(m_data.is_empty());
|
|
m_sample_rate = sample_rate;
|
|
m_channel_count = channel_count;
|
|
m_timestamp = timestamp;
|
|
m_timestamp_in_samples = timestamp.to_time_units(1, sample_rate);
|
|
data_callback(m_data);
|
|
}
|
|
void set_timestamp_in_samples(i64 timestamp_in_samples)
|
|
{
|
|
VERIFY(!is_empty());
|
|
m_timestamp_in_samples = timestamp_in_samples;
|
|
m_timestamp = AK::Duration::from_time_units(timestamp_in_samples, 1, m_sample_rate);
|
|
}
|
|
bool is_empty() const
|
|
{
|
|
return m_sample_rate == 0;
|
|
}
|
|
size_t data_count() const
|
|
{
|
|
return data().size();
|
|
}
|
|
size_t sample_count() const
|
|
{
|
|
return data_count() / m_channel_count;
|
|
}
|
|
|
|
private:
|
|
u32 m_sample_rate { 0 };
|
|
u8 m_channel_count { 0 };
|
|
AK::Duration m_timestamp;
|
|
i64 m_timestamp_in_samples { 0 };
|
|
Data m_data;
|
|
};
|
|
|
|
}
|