LibAudio/AudioServer: Add support for playing real time audio
This commit is contained in:
@@ -12,6 +12,17 @@
|
||||
namespace LibAudio
|
||||
{
|
||||
|
||||
BAN::ErrorOr<Audio> Audio::create(uint32_t channels, uint32_t sample_rate, uint32_t sample_frames)
|
||||
{
|
||||
Audio result;
|
||||
TRY(result.initialize((sample_frames + 10) * channels));
|
||||
|
||||
result.m_audio_buffer->sample_rate = sample_rate;
|
||||
result.m_audio_buffer->channels = channels;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Audio> Audio::load(BAN::StringView path)
|
||||
{
|
||||
Audio result(TRY(AudioLoader::load(path)));
|
||||
@@ -69,18 +80,6 @@ namespace LibAudio
|
||||
return *this;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Audio::start()
|
||||
{
|
||||
ASSERT(m_server_fd != -1);
|
||||
|
||||
const ssize_t nsend = send(m_server_fd, &m_smo_key, sizeof(m_smo_key), 0);
|
||||
if (nsend == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
ASSERT(nsend == sizeof(m_smo_key));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Audio::initialize(uint32_t total_samples)
|
||||
{
|
||||
m_smo_size = sizeof(AudioBuffer) + total_samples * sizeof(AudioBuffer::sample_t);
|
||||
@@ -118,11 +117,58 @@ namespace LibAudio
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Audio::start()
|
||||
{
|
||||
ASSERT(m_server_fd != -1);
|
||||
|
||||
const ssize_t nsend = send(m_server_fd, &m_smo_key, sizeof(m_smo_key), 0);
|
||||
if (nsend == -1)
|
||||
return BAN::Error::from_errno(errno);
|
||||
ASSERT(nsend == sizeof(m_smo_key));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void Audio::set_paused(bool paused)
|
||||
{
|
||||
ASSERT(m_server_fd != -1);
|
||||
|
||||
if (m_audio_buffer->paused == paused)
|
||||
return;
|
||||
m_audio_buffer->paused = paused;
|
||||
|
||||
long dummy = 0;
|
||||
send(m_server_fd, &dummy, sizeof(dummy), 0);
|
||||
}
|
||||
|
||||
size_t Audio::queue_samples(BAN::Span<const AudioBuffer::sample_t> samples)
|
||||
{
|
||||
size_t samples_queued = 0;
|
||||
|
||||
uint32_t head = m_audio_buffer->head;
|
||||
while (samples_queued < samples.size())
|
||||
{
|
||||
const uint32_t next_head = (head + 1) % m_audio_buffer->capacity;
|
||||
if (next_head == m_audio_buffer->tail)
|
||||
break;
|
||||
m_audio_buffer->samples[head] = samples[samples_queued++];
|
||||
head = next_head;
|
||||
if (samples_queued % 128 == 0)
|
||||
m_audio_buffer->head = head;
|
||||
}
|
||||
if (samples_queued % 128 != 0)
|
||||
m_audio_buffer->head = head;
|
||||
return samples_queued;
|
||||
}
|
||||
|
||||
void Audio::update()
|
||||
{
|
||||
if (!m_audio_loader)
|
||||
return;
|
||||
|
||||
if (!m_audio_loader->samples_remaining() && !is_playing())
|
||||
return set_paused(true);
|
||||
|
||||
while (m_audio_loader->samples_remaining())
|
||||
{
|
||||
const uint32_t next_head = (m_audio_buffer->head + 1) % m_audio_buffer->capacity;
|
||||
|
||||
@@ -18,6 +18,8 @@ namespace LibAudio
|
||||
uint32_t sample_rate;
|
||||
uint32_t channels;
|
||||
|
||||
BAN::Atomic<bool> paused { false };
|
||||
|
||||
uint32_t capacity;
|
||||
BAN::Atomic<uint32_t> tail { 0 };
|
||||
BAN::Atomic<uint32_t> head { 0 };
|
||||
@@ -29,6 +31,7 @@ namespace LibAudio
|
||||
BAN_NON_COPYABLE(Audio);
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<Audio> create(uint32_t channels, uint32_t sample_rate, uint32_t sample_frames);
|
||||
static BAN::ErrorOr<Audio> load(BAN::StringView path);
|
||||
static BAN::ErrorOr<Audio> random(uint32_t samples);
|
||||
~Audio() { clear(); }
|
||||
@@ -37,9 +40,13 @@ namespace LibAudio
|
||||
Audio& operator=(Audio&& other);
|
||||
|
||||
BAN::ErrorOr<void> start();
|
||||
void update();
|
||||
|
||||
void set_paused(bool paused);
|
||||
|
||||
bool is_playing() const { return m_audio_buffer->tail != m_audio_buffer->head; }
|
||||
void update();
|
||||
|
||||
size_t queue_samples(BAN::Span<const AudioBuffer::sample_t> samples);
|
||||
|
||||
private:
|
||||
Audio() = default;
|
||||
|
||||
Reference in New Issue
Block a user