banan-os/userspace/libraries/LibAudio/Audio.cpp

137 lines
3.2 KiB
C++

#include <BAN/ScopeGuard.h>
#include <LibAudio/Audio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/banan-os.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
namespace LibAudio
{
BAN::ErrorOr<Audio> Audio::load(BAN::StringView path)
{
Audio result(TRY(AudioLoader::load(path)));
TRY(result.initialize(256 * 1024));
return result;
}
BAN::ErrorOr<Audio> Audio::random(uint32_t samples)
{
Audio result;
TRY(result.initialize(samples));
result.m_audio_buffer->sample_rate = 48000;
result.m_audio_buffer->channels = 1;
for (size_t i = 0; i < samples - 1; i++)
result.m_audio_buffer->samples[i] = (rand() - RAND_MAX / 2) / (RAND_MAX / 2.0);
result.m_audio_buffer->head = samples - 1;
return result;
}
void Audio::clear()
{
if (m_audio_buffer)
munmap(m_audio_buffer, m_smo_size);
m_audio_buffer = nullptr;
if (m_smo_key != -1)
smo_delete(m_smo_key);
m_smo_key = -1;
if (m_server_fd != -1)
close(m_server_fd);
m_server_fd = -1;
m_audio_loader.clear();
}
Audio& Audio::operator=(Audio&& other)
{
clear();
m_server_fd = other.m_server_fd;
m_smo_key = other.m_smo_key;
m_smo_size = other.m_smo_size;
m_audio_buffer = other.m_audio_buffer;
m_audio_loader = BAN::move(other.m_audio_loader);
other.m_server_fd = -1;
other.m_smo_key = -1;
other.m_smo_size = 0;
other.m_audio_buffer = nullptr;
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);
m_smo_key = smo_create(m_smo_size, PROT_READ | PROT_WRITE);
if (m_smo_key == -1)
return BAN::Error::from_errno(errno);
m_audio_buffer = static_cast<AudioBuffer*>(smo_map(m_smo_key));
if (m_audio_buffer == nullptr)
return BAN::Error::from_errno(errno);
new (m_audio_buffer) AudioBuffer();
memset(m_audio_buffer->samples, 0, total_samples * sizeof(AudioBuffer::sample_t));
m_audio_buffer->capacity = total_samples;
if (m_audio_loader)
{
m_audio_buffer->channels = m_audio_loader->channels();
m_audio_buffer->sample_rate = m_audio_loader->sample_rate();
}
update();
sockaddr_un server_addr;
server_addr.sun_family = AF_UNIX;
strcpy(server_addr.sun_path, s_audio_server_socket.data());
m_server_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (m_server_fd == -1)
return BAN::Error::from_errno(errno);
if (connect(m_server_fd, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)) == -1)
return BAN::Error::from_errno(errno);
return {};
}
void Audio::update()
{
if (!m_audio_loader)
return;
while (m_audio_loader->samples_remaining())
{
const uint32_t next_head = (m_audio_buffer->head + 1) % m_audio_buffer->capacity;
if (next_head == m_audio_buffer->tail)
break;
m_audio_buffer->samples[m_audio_buffer->head] = m_audio_loader->get_sample();
m_audio_buffer->head = next_head;
}
}
}