Skip to content

Commit

Permalink
Audio: Make ABuffer sit on top of a SharedBuffer.
Browse files Browse the repository at this point in the history
This allows us to carry the same buffer all the way from the WAV loader
to the AudioServer mixer.

This alleviates some of the stutter, but there's still a noticeable
skip when switching buffers. We're gonna need to do better. :^)
  • Loading branch information
awesomekling committed Jul 27, 2019
1 parent b805f11 commit 5e01dde
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 31 deletions.
27 changes: 20 additions & 7 deletions Libraries/LibAudio/ABuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <AK/ByteBuffer.h>
#include <AK/Types.h>
#include <AK/Vector.h>
#include <LibC/SharedBuffer.h>

// A single sample in an audio buffer.
// Values are floating point, and should range from -1.0 to +1.0
Expand Down Expand Up @@ -57,17 +58,29 @@ class ABuffer : public RefCounted<ABuffer> {
{
return adopt(*new ABuffer(move(samples)));
}
static NonnullRefPtr<ABuffer> create_with_shared_buffer(NonnullRefPtr<SharedBuffer>&& buffer)
{
return adopt(*new ABuffer(move(buffer)));
}

const Vector<ASample>& samples() const { return m_samples; }
Vector<ASample>& samples() { return m_samples; }
const void* data() const { return m_samples.data(); }
int size_in_bytes() const { return m_samples.size() * sizeof(ASample); }
const ASample* samples() const { return (const ASample*)data(); }
int sample_count() const { return m_buffer->size() / (int)sizeof(ASample); }
const void* data() const { return m_buffer->data(); }
int size_in_bytes() const { return m_buffer->size(); }
int shared_buffer_id() const { return m_buffer->shared_buffer_id(); }

private:
ABuffer(Vector<ASample>&& samples)
: m_samples(move(samples))
explicit ABuffer(Vector<ASample>&& samples)
: m_buffer(*SharedBuffer::create_with_size(samples.size() * sizeof(ASample)))
{
memcpy(m_buffer->data(), samples.data(), samples.size() * sizeof(ASample));
}

explicit ABuffer(NonnullRefPtr<SharedBuffer>&& buffer)
: m_buffer(move(buffer))
{
}

Vector<ASample> m_samples;
NonnullRefPtr<SharedBuffer> m_buffer;
int m_sample_count { 0 };
};
2 changes: 1 addition & 1 deletion Libraries/LibAudio/AWavLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,5 +254,5 @@ RefPtr<ABuffer> ABuffer::from_pcm_data(ByteBuffer& data, int num_channels, int b
// don't belong.
ASSERT(!stream.handle_read_failure());

return adopt(*new ABuffer(move(fdata)));
return ABuffer::create_with_samples(move(fdata));
}
15 changes: 5 additions & 10 deletions Servers/AudioServer/ASClientConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,11 @@ bool ASClientConnection::handle_message(const ASAPI_ClientMessage& message, cons
break;
case ASAPI_ClientMessage::Type::PlayBuffer: {
// ### ensure that the size is that of a Vector<ASample>
Vector<ASample> samples;

{
const auto& shared_buf = SharedBuffer::create_from_shared_buffer_id(message.play_buffer.buffer_id);
if (!shared_buf) {
did_misbehave();
return false;
}
samples.resize(shared_buf->size() / sizeof(ASample));
memcpy(samples.data(), shared_buf->data(), shared_buf->size());
auto shared_buffer = SharedBuffer::create_from_shared_buffer_id(message.play_buffer.buffer_id);
if (!shared_buffer) {
did_misbehave();
return false;
}

// we no longer need the buffer, so acknowledge that it's playing
Expand All @@ -59,7 +54,7 @@ bool ASClientConnection::handle_message(const ASAPI_ClientMessage& message, cons
reply.playing_buffer.buffer_id = message.play_buffer.buffer_id;
post_message(reply);

m_mixer.queue(*this, ABuffer::create_with_samples(move(samples)), message.play_buffer.buffer_id);
m_mixer.queue(*this, ABuffer::create_with_shared_buffer(*shared_buffer));
break;
}
case ASAPI_ClientMessage::Type::Invalid:
Expand Down
18 changes: 9 additions & 9 deletions Servers/AudioServer/ASMixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ ASMixer::ASMixer()
}, this);
}

void ASMixer::queue(ASClientConnection& client, const ABuffer& buffer, int buffer_id)
void ASMixer::queue(ASClientConnection& client, const ABuffer& buffer)
{
ASSERT(buffer.size_in_bytes());
CLocker lock(m_lock);
m_pending_mixing.append(ASMixerBuffer(buffer, client, buffer_id));
m_pending_mixing.append(ASMixerBuffer(buffer, client));
}

void ASMixer::mix()
Expand Down Expand Up @@ -68,19 +68,20 @@ void ASMixer::mix()
for (auto& buffer : active_mix_buffers) {
if (buffer.done)
continue;
auto& samples = buffer.buffer->samples();
auto* samples = buffer.buffer->samples();
auto sample_count = buffer.buffer->sample_count();

for (int i = 0; i < max_size && buffer.pos < samples.size(); ++buffer.pos, ++i) {
for (int i = 0; i < max_size && buffer.pos < sample_count; ++buffer.pos, ++i) {
auto& mixed_sample = mixed_buffer[i];
mixed_sample += samples[buffer.pos];
}

// clear it later
if (buffer.pos == samples.size()) {
if (buffer.m_buffer_id && buffer.m_client) {
if (buffer.pos == sample_count) {
if (buffer.m_client) {
ASAPI_ServerMessage reply;
reply.type = ASAPI_ServerMessage::Type::FinishedPlayingBuffer;
reply.playing_buffer.buffer_id = buffer.m_buffer_id;
reply.playing_buffer.buffer_id = buffer.buffer->shared_buffer_id();
buffer.m_client->post_message(reply);
}
buffer.done = true;
Expand Down Expand Up @@ -118,9 +119,8 @@ void ASMixer::mix()
}
}

ASMixer::ASMixerBuffer::ASMixerBuffer(const NonnullRefPtr<ABuffer>& buf, ASClientConnection& client, int buffer_id)
ASMixer::ASMixerBuffer::ASMixerBuffer(const NonnullRefPtr<ABuffer>& buf, ASClientConnection& client)
: buffer(buf)
, m_client(client.make_weak_ptr())
, m_buffer_id(buffer_id)
{
}
5 changes: 2 additions & 3 deletions Servers/AudioServer/ASMixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ class ASMixer : public RefCounted<ASMixer> {
public:
ASMixer();

void queue(ASClientConnection&, const ABuffer&, int buffer_id);
void queue(ASClientConnection&, const ABuffer&);

private:
struct ASMixerBuffer {
ASMixerBuffer(const NonnullRefPtr<ABuffer>&, ASClientConnection&, int buffer_id = -1);
ASMixerBuffer(const NonnullRefPtr<ABuffer>&, ASClientConnection&);
NonnullRefPtr<ABuffer> buffer;
int pos { 0 };
bool done { false };
WeakPtr<ASClientConnection> m_client;
int m_buffer_id { -1 };
};

Vector<ASMixerBuffer> m_pending_mixing;
Expand Down
2 changes: 1 addition & 1 deletion Userland/aplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int main(int argc, char **argv)
if (!samples) {
break;
}
printf("Playing %d sample(s)\n", samples->samples().size());
printf("Playing %d sample(s)\n", samples->sample_count());
a_conn.play(*samples, true);
}

Expand Down

0 comments on commit 5e01dde

Please sign in to comment.