blob: aa1830e2d367c1d5d323656370c79b30695f63de (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "PlaybackManager.h"
PlaybackManager::PlaybackManager(NonnullRefPtr<Audio::ConnectionToServer> connection)
: m_connection(connection)
{
// FIXME: The buffer enqueuing should happen on a wholly independent second thread.
m_timer = Core::Timer::construct(PlaybackManager::update_rate_ms, [&]() {
if (!m_loader)
return;
next_buffer();
});
m_timer->stop();
m_device_sample_rate = connection->get_sample_rate();
}
void PlaybackManager::set_loader(NonnullRefPtr<Audio::Loader>&& loader)
{
stop();
m_loader = loader;
if (m_loader) {
m_total_length = m_loader->total_samples() / static_cast<float>(m_loader->sample_rate());
m_device_samples_per_buffer = PlaybackManager::buffer_size_ms / 1000.0f * m_device_sample_rate;
m_samples_to_load_per_buffer = PlaybackManager::buffer_size_ms / 1000.0f * m_loader->sample_rate();
m_resampler = Audio::ResampleHelper<Audio::Sample>(m_loader->sample_rate(), m_device_sample_rate);
m_timer->start();
} else {
m_timer->stop();
}
}
void PlaybackManager::stop()
{
set_paused(true);
m_connection->async_clear_buffer();
m_last_seek = 0;
if (m_loader)
(void)m_loader->reset();
}
void PlaybackManager::play()
{
set_paused(false);
}
void PlaybackManager::loop(bool loop)
{
m_loop = loop;
}
void PlaybackManager::seek(int const position)
{
if (!m_loader)
return;
m_last_seek = position;
bool paused_state = m_paused;
set_paused(true);
[[maybe_unused]] auto result = m_loader->seek(position);
m_connection->clear_client_buffer();
m_connection->async_clear_buffer();
if (!paused_state)
set_paused(false);
}
void PlaybackManager::pause()
{
set_paused(true);
}
void PlaybackManager::set_paused(bool paused)
{
m_paused = paused;
if (m_paused)
m_connection->async_pause_playback();
else
m_connection->async_start_playback();
}
bool PlaybackManager::toggle_pause()
{
if (m_paused) {
play();
} else {
pause();
}
return m_paused;
}
void PlaybackManager::next_buffer()
{
if (on_update)
on_update();
if (m_paused)
return;
while (m_connection->remaining_samples() < m_device_samples_per_buffer * always_enqueued_buffer_count) {
bool all_samples_loaded = (m_loader->loaded_samples() >= m_loader->total_samples());
bool audio_server_done = (m_connection->remaining_samples() == 0);
if (all_samples_loaded && audio_server_done) {
stop();
if (on_finished_playing)
on_finished_playing();
return;
}
auto maybe_buffer = m_loader->get_more_samples(m_samples_to_load_per_buffer);
if (!maybe_buffer.is_error()) {
m_current_buffer.swap(maybe_buffer.value());
VERIFY(m_resampler.has_value());
m_resampler->reset();
// FIXME: Handle OOM better.
auto resampled = MUST(FixedArray<Audio::Sample>::try_create(m_resampler->resample(move(m_current_buffer)).span()));
m_current_buffer.swap(resampled);
MUST(m_connection->async_enqueue(m_current_buffer));
}
}
}
|