Skip to content

Commit ae5e200

Browse files
Zaggy1024gmta
authored andcommitted
LibMedia: Move overlapping audio block correction to the data provider
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.
1 parent 7e325d6 commit ae5e200

File tree

5 files changed

+38
-21
lines changed

5 files changed

+38
-21
lines changed

Libraries/LibMedia/AudioBlock.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,36 @@ class AudioBlock {
1717

1818
u32 sample_rate() const { return m_sample_rate; }
1919
u8 channel_count() const { return m_channel_count; }
20-
AK::Duration start_timestamp() const { return m_start_timestamp; }
20+
AK::Duration timestamp() const { return m_timestamp; }
21+
i64 timestamp_in_samples() const { return m_timestamp_in_samples; }
2122
Data& data() { return m_data; }
2223
Data const& data() const { return m_data; }
2324

2425
void clear()
2526
{
2627
m_sample_rate = 0;
2728
m_channel_count = 0;
28-
m_start_timestamp = AK::Duration::zero();
29+
m_timestamp_in_samples = 0;
2930
m_data = Data();
3031
}
3132
template<typename Callback>
32-
void emplace(u32 sample_rate, u8 channel_count, AK::Duration start_timestamp, Callback data_callback)
33+
void emplace(u32 sample_rate, u8 channel_count, AK::Duration timestamp, Callback data_callback)
3334
{
3435
VERIFY(sample_rate != 0);
3536
VERIFY(channel_count != 0);
3637
VERIFY(m_data.is_empty());
3738
m_sample_rate = sample_rate;
3839
m_channel_count = channel_count;
39-
m_start_timestamp = start_timestamp;
40+
m_timestamp = timestamp;
41+
m_timestamp_in_samples = timestamp.to_time_units(1, sample_rate);
4042
data_callback(m_data);
4143
}
44+
void set_timestamp_in_samples(i64 timestamp_in_samples)
45+
{
46+
VERIFY(!is_empty());
47+
m_timestamp_in_samples = timestamp_in_samples;
48+
m_timestamp = AK::Duration::from_time_units(timestamp_in_samples, 1, m_sample_rate);
49+
}
4250
bool is_empty() const
4351
{
4452
return m_sample_rate == 0;
@@ -55,7 +63,8 @@ class AudioBlock {
5563
private:
5664
u32 m_sample_rate { 0 };
5765
u8 m_channel_count { 0 };
58-
AK::Duration m_start_timestamp;
66+
AK::Duration m_timestamp;
67+
i64 m_timestamp_in_samples { 0 };
5968
Data m_data;
6069
};
6170

Libraries/LibMedia/Providers/AudioDataProvider.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ bool AudioDataProvider::ThreadData::should_thread_exit() const
105105
return m_exit;
106106
}
107107

108+
void AudioDataProvider::ThreadData::flush_decoder()
109+
{
110+
m_decoder->flush();
111+
m_last_sample = NumericLimits<i64>::min();
112+
}
113+
114+
DecoderErrorOr<void> AudioDataProvider::ThreadData::retrieve_next_block(AudioBlock& block)
115+
{
116+
TRY(m_decoder->write_next_block(block));
117+
if (block.timestamp_in_samples() < m_last_sample)
118+
block.set_timestamp_in_samples(m_last_sample);
119+
m_last_sample = block.timestamp_in_samples() + static_cast<i64>(block.sample_count());
120+
return {};
121+
}
122+
108123
template<typename T>
109124
void AudioDataProvider::ThreadData::process_seek_on_main_thread(u32 seek_id, T&& function)
110125
{
@@ -166,7 +181,7 @@ bool AudioDataProvider::ThreadData::handle_seek()
166181
auto demuxer_seek_result = demuxer_seek_result_or_error.value_or(DemuxerSeekResult::MovedPosition);
167182

168183
if (demuxer_seek_result == DemuxerSeekResult::MovedPosition)
169-
m_decoder->flush();
184+
flush_decoder();
170185

171186
auto new_seek_id = seek_id;
172187
AudioBlock last_block;
@@ -191,7 +206,7 @@ bool AudioDataProvider::ThreadData::handle_seek()
191206

192207
while (new_seek_id == seek_id) {
193208
AudioBlock current_block;
194-
auto block_result = m_decoder->write_next_block(current_block);
209+
auto block_result = retrieve_next_block(current_block);
195210
if (block_result.is_error()) {
196211
if (block_result.error().category() == DecoderErrorCategory::EndOfStream) {
197212
resolve_seek(seek_id);
@@ -205,7 +220,7 @@ bool AudioDataProvider::ThreadData::handle_seek()
205220
return true;
206221
}
207222

208-
if (current_block.start_timestamp() > timestamp) {
223+
if (current_block.timestamp() > timestamp) {
209224
auto locker = take_lock();
210225
m_queue.clear();
211226

@@ -291,7 +306,7 @@ void AudioDataProvider::ThreadData::push_data_and_decode_a_block()
291306
}
292307

293308
auto block = AudioBlock();
294-
auto timestamp_result = m_decoder->write_next_block(block);
309+
auto timestamp_result = retrieve_next_block(block);
295310
if (timestamp_result.is_error()) {
296311
if (timestamp_result.error().category() == DecoderErrorCategory::NeedsMoreInput)
297312
break;

Libraries/LibMedia/Providers/AudioDataProvider.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class MEDIA_API AudioDataProvider : public AtomicRefCounted<AudioDataProvider> {
5353
void set_error_handler(ErrorHandler&&);
5454

5555
bool should_thread_exit() const;
56+
void flush_decoder();
57+
DecoderErrorOr<void> retrieve_next_block(AudioBlock&);
5658
bool handle_seek();
5759
template<typename T>
5860
void process_seek_on_main_thread(u32 seek_id, T&&);
@@ -80,6 +82,7 @@ class MEDIA_API AudioDataProvider : public AtomicRefCounted<AudioDataProvider> {
8082
NonnullRefPtr<MutexedDemuxer> m_demuxer;
8183
Track m_track;
8284
NonnullOwnPtr<AudioDecoder> m_decoder;
85+
i64 m_last_sample { NumericLimits<i64>::min() };
8386

8487
size_t m_queue_max_size { 8 };
8588
AudioQueue m_queue;

Libraries/LibMedia/Sinks/AudioMixingSink.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,7 @@ void AudioMixingSink::create_playback_stream(u32 sample_rate, u32 channel_count)
111111
if (new_block.is_empty())
112112
return false;
113113

114-
auto new_block_first_sample_offset = new_block.start_timestamp().to_time_units(1, sample_rate);
115-
if (!track_data.current_block.is_empty() && track_data.current_block.sample_rate() == sample_rate && track_data.current_block.channel_count() == channel_count) {
116-
auto current_block_end = track_data.current_block_first_sample_offset + static_cast<i64>(track_data.current_block.sample_count());
117-
new_block_first_sample_offset = max(new_block_first_sample_offset, current_block_end);
118-
}
119-
120114
track_data.current_block = move(new_block);
121-
track_data.current_block_first_sample_offset = new_block_first_sample_offset;
122115
return true;
123116
};
124117

@@ -137,7 +130,7 @@ void AudioMixingSink::create_playback_stream(u32 sample_rate, u32 channel_count)
137130
continue;
138131
}
139132

140-
auto first_sample_offset = track_data.current_block_first_sample_offset;
133+
auto first_sample_offset = current_block.timestamp_in_samples();
141134
if (first_sample_offset >= samples_end)
142135
break;
143136

@@ -279,10 +272,8 @@ void AudioMixingSink::set_time(AK::Duration time)
279272
self->m_next_sample_to_write = time.to_time_units(1, self->m_playback_stream_sample_rate);
280273
}
281274

282-
for (auto& [track, track_data] : self->m_track_mixing_datas) {
275+
for (auto& [track, track_data] : self->m_track_mixing_datas)
283276
track_data.current_block.clear();
284-
track_data.current_block_first_sample_offset = 0;
285-
}
286277
}
287278

288279
if (self->m_playing)

Libraries/LibMedia/Sinks/AudioMixingSink.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ class MEDIA_API AudioMixingSink final : public AudioSink {
7272

7373
NonnullRefPtr<AudioDataProvider> provider;
7474
AudioBlock current_block;
75-
i64 current_block_first_sample_offset { NumericLimits<i64>::min() };
7675
};
7776

7877
void deferred_create_playback_stream(Track const& track);

0 commit comments

Comments
 (0)