diff --git a/Applications/Piano/Makefile b/Applications/Piano/Makefile index ed2c50af3f..1e362554df 100644 --- a/Applications/Piano/Makefile +++ b/Applications/Piano/Makefile @@ -11,7 +11,7 @@ DEFINES += -DUSERLAND all: $(APP) $(APP): $(OBJS) - $(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc + $(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc -laudio .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Applications/Piano/main.cpp b/Applications/Piano/main.cpp index b6e927f565..d453f3b5ad 100644 --- a/Applications/Piano/main.cpp +++ b/Applications/Piano/main.cpp @@ -2,6 +2,7 @@ #include "PianoWidget.h" #include #include +#include #include #include #include @@ -10,6 +11,7 @@ static int s_pipefds[2]; int main(int argc, char** argv) { + AClientConnection audio_connection; GApplication app(argc, argv); pipe(s_pipefds); diff --git a/Kernel/makeall.sh b/Kernel/makeall.sh index 5dc946ca1a..a6b33c8b50 100755 --- a/Kernel/makeall.sh +++ b/Kernel/makeall.sh @@ -24,6 +24,7 @@ build_targets="$build_targets ../Servers/WindowServer" build_targets="$build_targets ../Servers/AudioServer" build_targets="$build_targets ../Libraries/LibGUI" build_targets="$build_targets ../Libraries/LibHTML" +build_targets="$build_targets ../Libraries/LibAudio" build_targets="$build_targets ../Userland" build_targets="$build_targets ../Applications/Terminal" build_targets="$build_targets ../Applications/FontEditor" diff --git a/Libraries/LibAudio/AClientConnection.cpp b/Libraries/LibAudio/AClientConnection.cpp new file mode 100644 index 0000000000..002cc22fca --- /dev/null +++ b/Libraries/LibAudio/AClientConnection.cpp @@ -0,0 +1,26 @@ +#include "AClientConnection.h" +#include +#include + +AClientConnection::AClientConnection() +{ + m_connection.on_connected = [this] { + m_notifier = make(m_connection.fd(), CNotifier::Read); + m_notifier->on_ready_to_read = [this] { printf("AudioServer said something to us"); }; + m_connection.write("Hello, friends"); + }; + + int retries = 1000; + while (retries) { + if (m_connection.connect(CSocketAddress::local("/tmp/asportal"))) { + break; + } + +#ifdef ACLIENT_DEBUG + dbgprintf("AClientConnection: connect failed: %d, %s\n", errno, strerror(errno)); +#endif + sleep(1); + --retries; + } +} + diff --git a/Libraries/LibAudio/AClientConnection.h b/Libraries/LibAudio/AClientConnection.h new file mode 100644 index 0000000000..7df832babc --- /dev/null +++ b/Libraries/LibAudio/AClientConnection.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +class AClientConnection { +public: + AClientConnection(); + +private: + CLocalSocket m_connection; + OwnPtr m_notifier; +}; diff --git a/Libraries/LibAudio/AWavFile.cpp b/Libraries/LibAudio/AWavFile.cpp new file mode 100644 index 0000000000..ef9c77fa77 --- /dev/null +++ b/Libraries/LibAudio/AWavFile.cpp @@ -0,0 +1,2 @@ +#include "AWavFile.h" + diff --git a/Libraries/LibAudio/AWavFile.h b/Libraries/LibAudio/AWavFile.h new file mode 100644 index 0000000000..6321179363 --- /dev/null +++ b/Libraries/LibAudio/AWavFile.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +class AWavFile : public RefCounted { +public: + enum class Format { + Invalid, + PCM, + }; + + Format format() const { return m_format; } + u16 channel_count() const { return m_channel_count; } + u32 sample_rate_per_second() const { return m_sample_rate; } + u32 average_byte_rate_per_second() const { return m_byte_rate; } + u16 block_align() const { return m_block_align; } + u16 bits_per_sample() const { return m_bits_per_sample; } + const ByteBuffer& sample_data() const { return m_sample_data; } + +private: + Format m_format = Format::Invalid; + u16 m_channel_count = 0; + u32 m_sample_rate = 0; + u32 m_byte_rate = 0; + u16 m_block_align = 0; + u16 m_bits_per_sample = 0; + ByteBuffer m_sample_data; + + friend class AWavLoader; +}; diff --git a/Libraries/LibAudio/AWavLoader.cpp b/Libraries/LibAudio/AWavLoader.cpp new file mode 100644 index 0000000000..16a0a73607 --- /dev/null +++ b/Libraries/LibAudio/AWavLoader.cpp @@ -0,0 +1,166 @@ +#include + +#include "AWavLoader.h" +#include "AWavFile.h" + +static u32 read_u32(const ByteBuffer& buf, u32& off) +{ + ASSERT(buf.size() - off >= 4); + u32 b0 = buf[off + 0]; + u32 b1 = buf[off + 1]; + u32 b2 = buf[off + 2]; + u32 b3 = buf[off + 3]; + + u32 ret = 0; + ret |= (u8(b3) << 24); + ret |= (u8(b2) << 16); + ret |= (u8(b1) << 8); + ret |= (u8(b0)); + + off += 4; + return ret; +} + +static u16 read_u16(const ByteBuffer& buf, u32& off) +{ + ASSERT(buf.size() - off >= 2); + u16 b0 = buf[off + 0]; + u16 b1 = buf[off + 1]; + + u16 ret = 0; + ret |= (u8(b1) << 8); + ret |= (u8(b0)); + + off += 2; + return ret; +} + +RefPtr AWavLoader::load_wav(const StringView& path) +{ + m_error_string = {}; + + CFile wav(path); + if (!wav.open(CIODevice::ReadOnly)) { + m_error_string = String::format("Can't open file: %s", wav.error_string()); + return nullptr; + } + + const auto& contents = wav.read_all(); + return parse_wav(contents); +} + +// TODO: A streaming parser might be better than forcing a ByteBuffer +RefPtr AWavLoader::parse_wav(const ByteBuffer& buffer) +{ + u32 off = 0; + + if (buffer.size() - off < 12) { + dbgprintf("WAV is too small (no header, %d bytes)\n", buffer.size()); + return {}; + } + + dbgprintf("Trying to parse %d bytes of wav\n", buffer.size()); + +#define CHECK_OK(msg) \ + do { \ + ASSERT(ok); \ + if (!ok) { \ + m_error_string = String::format("Parsing failed: %s", msg); \ + return {}; \ + } else { \ + dbgprintf("%s is OK!\n", msg); \ + } \ + } while (0); + + bool ok = true; + u32 riff = read_u32(buffer, off); + ok = ok && riff == 0x46464952; // "RIFF" + CHECK_OK("RIFF header"); + + u32 sz = read_u32(buffer, off); + ASSERT(sz < 1024 * 1024 * 42); + ok = ok && sz < 1024 * 1024 * 42; // arbitrary + CHECK_OK("File size"); + + u32 wave = read_u32(buffer, off); + ok = ok && wave == 0x45564157; // "WAVE" + CHECK_OK("WAVE header"); + + if (buffer.size() - off < 8) { + dbgprintf("WAV is too small (no fmt, %d bytes)\n", buffer.size()); + return {}; + } + + u32 fmt_id = read_u32(buffer, off); + ok = ok && fmt_id == 0x20746D66; // "FMT" + CHECK_OK("FMT header"); + + u32 fmt_size = read_u32(buffer, off); + ok = ok && fmt_size == 16; + ASSERT(fmt_size == 16); + CHECK_OK("FMT size"); + + if (buffer.size() - off < 16) { + dbgprintf("WAV is too small (fmt chunk, %d bytes)\n", buffer.size()); + return {}; + } + + auto ret = adopt(*new AWavFile); + u16 audio_format = read_u16(buffer, off); + ok = ok && audio_format == 1; // WAVE_FORMAT_PCM + ASSERT(audio_format == 1); + CHECK_OK("Audio format"); + ret->m_format = AWavFile::Format::PCM; + + u16 num_channels = read_u16(buffer, off); + CHECK_OK("Channel count"); + ret->m_channel_count = num_channels; + + u32 sample_rate = read_u32(buffer, off); + CHECK_OK("Sample rate"); + ret->m_sample_rate = sample_rate; + + u32 byte_rate = read_u32(buffer, off); + CHECK_OK("Byte rate"); + ret->m_byte_rate = byte_rate; + + u16 block_align = read_u16(buffer, off); + CHECK_OK("Block align"); + ret->m_block_align = block_align; + + u16 bits_per_sample = read_u16(buffer, off); + ok = ok && (bits_per_sample == 8 || bits_per_sample == 16); + ASSERT(bits_per_sample == 8 || bits_per_sample == 16); + CHECK_OK("Bits per sample"); + ret->m_bits_per_sample = bits_per_sample; + + // Read chunks until we find DATA + if (off >= u32(buffer.size()) - 8) { + ok = ok && false; + ASSERT_NOT_REACHED(); + CHECK_OK("Premature EOF without DATA"); + } + + bool found_data = false; + u32 data_sz = 0; + while (off < u32(buffer.size()) - 8) { + u32 chunk_id = read_u32(buffer, off); + data_sz = read_u32(buffer, off); + if (chunk_id == 0x61746164) { // DATA + found_data = true; + break; + } + off += data_sz; + } + + ok = ok && found_data; + ASSERT(found_data); + CHECK_OK("Found no data chunk"); + + ok = ok && data_sz <= (buffer.size() - off); + CHECK_OK("Bad DATA size"); + + ret->m_sample_data = buffer.slice(off, data_sz); + return ret; +} + diff --git a/Libraries/LibAudio/AWavLoader.h b/Libraries/LibAudio/AWavLoader.h new file mode 100644 index 0000000000..be4facab45 --- /dev/null +++ b/Libraries/LibAudio/AWavLoader.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +class AWavFile; + +class AWavLoader { +public: + RefPtr load_wav(const StringView& path); + const char* error_string() { return m_error_string.characters(); } +private: + RefPtr parse_wav(const ByteBuffer& buffer); + String m_error_string; +}; diff --git a/Libraries/LibAudio/Makefile b/Libraries/LibAudio/Makefile new file mode 100644 index 0000000000..fa2c6507aa --- /dev/null +++ b/Libraries/LibAudio/Makefile @@ -0,0 +1,32 @@ +include ../../Makefile.common + +OBJS = \ + AClientConnection.o \ + AWavFile.o \ + AWavLoader.o + +LIBRARY = libaudio.a +DEFINES += -DUSERLAND + +all: $(LIBRARY) + +$(LIBRARY): $(OBJS) + @echo "LIB $@"; $(AR) rcs $@ $(OBJS) $(LIBS) + +.cpp.o: + @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< + +-include $(OBJS:%.o=%.d) + +clean: + @echo "CLEAN"; rm -f $(LIBRARY) $(OBJS) *.d + +install: $(LIBRARY) + mkdir -p ../../Root/usr/include/LibAudio + mkdir -p ../../Root/usr/include/AK + mkdir -p ../../Root/usr/lib + # Copy headers + rsync -r -a --include '*/' --include '*.h' --exclude '*' . ../../Root/usr/include/LibAudio + rsync -r -a --include '*/' --include '*.h' --exclude '*' ../../AK/ ../../Root/usr/include/AK + # Install the library + cp $(LIBRARY) ../../Root/usr/lib diff --git a/Libraries/LibCore/CEventLoop.h b/Libraries/LibCore/CEventLoop.h index 8cab0bbe99..7e3d5cb9e7 100644 --- a/Libraries/LibCore/CEventLoop.h +++ b/Libraries/LibCore/CEventLoop.h @@ -6,11 +6,11 @@ #include #include #include +#include #include #include #include -class CEvent; class CObject; class CNotifier; diff --git a/Libraries/LibCore/CLocalSocket.cpp b/Libraries/LibCore/CLocalSocket.cpp new file mode 100644 index 0000000000..20837a066f --- /dev/null +++ b/Libraries/LibCore/CLocalSocket.cpp @@ -0,0 +1,19 @@ +#include +#include + +CLocalSocket::CLocalSocket(CObject* parent) + : CSocket(CSocket::Type::Local, parent) +{ + int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) { + set_error(fd); + } else { + set_fd(fd); + set_mode(CIODevice::ReadWrite); + set_error(0); + } +} + +CLocalSocket::~CLocalSocket() +{ +} diff --git a/Libraries/LibCore/CLocalSocket.h b/Libraries/LibCore/CLocalSocket.h new file mode 100644 index 0000000000..cdb4eeba55 --- /dev/null +++ b/Libraries/LibCore/CLocalSocket.h @@ -0,0 +1,7 @@ +#include + +class CLocalSocket final : public CSocket { +public: + explicit CLocalSocket(CObject* parent = nullptr); + virtual ~CLocalSocket() override; +}; diff --git a/Libraries/LibCore/CSocket.cpp b/Libraries/LibCore/CSocket.cpp index 4479969c40..cbe2bd9dd4 100644 --- a/Libraries/LibCore/CSocket.cpp +++ b/Libraries/LibCore/CSocket.cpp @@ -35,6 +35,8 @@ bool CSocket::connect(const CSocketAddress& address, int port) { ASSERT(!is_connected()); ASSERT(address.type() == CSocketAddress::Type::IPv4); + dbgprintf("Connecting to %s...", address.to_string().characters()); + ASSERT(port > 0 && port <= 65535); struct sockaddr_in addr; @@ -47,7 +49,6 @@ bool CSocket::connect(const CSocketAddress& address, int port) m_destination_address = address; m_destination_port = port; - dbgprintf("Connecting to %s...", address.to_string().characters()); fflush(stdout); int rc = ::connect(fd(), (struct sockaddr*)&addr, sizeof(addr)); if (rc < 0) { @@ -71,6 +72,26 @@ bool CSocket::connect(const CSocketAddress& address, int port) return true; } +bool CSocket::connect(const CSocketAddress& address) +{ + ASSERT(!is_connected()); + ASSERT(address.type() == CSocketAddress::Type::Local); + dbgprintf("Connecting to %s...", address.to_string().characters()); + + sockaddr_un saddr; + saddr.sun_family = AF_LOCAL; + strcpy(saddr.sun_path, address.to_string().characters()); + + int rc = ::connect(fd(), (const sockaddr*)&saddr, sizeof(saddr)); + if (rc < 0) { + perror("connect"); + return false; + } + + m_connected = true; + return true; +} + ByteBuffer CSocket::receive(int max_size) { auto buffer = read(max_size); diff --git a/Libraries/LibCore/CSocket.h b/Libraries/LibCore/CSocket.h index 587f80f290..8521bb02f9 100644 --- a/Libraries/LibCore/CSocket.h +++ b/Libraries/LibCore/CSocket.h @@ -10,12 +10,14 @@ public: enum class Type { Invalid, TCP, - UDP + UDP, + Local, }; virtual ~CSocket() override; bool connect(const String& hostname, int port); bool connect(const CSocketAddress&, int port); + bool connect(const CSocketAddress&); ByteBuffer receive(int max_size); bool send(const ByteBuffer&); diff --git a/Libraries/LibCore/CSocketAddress.h b/Libraries/LibCore/CSocketAddress.h index 019a0869fb..b0333516bb 100644 --- a/Libraries/LibCore/CSocketAddress.h +++ b/Libraries/LibCore/CSocketAddress.h @@ -17,6 +17,14 @@ public: { } + static CSocketAddress local(const String& address) + { + CSocketAddress addr; + addr.m_type = Type::Local; + addr.m_local_address = address; + return addr; + } + Type type() const { return m_type; } bool is_valid() const { return m_type != Type::Invalid; } IPv4Address ipv4_address() const { return m_ipv4_address; } @@ -26,6 +34,8 @@ public: switch (m_type) { case Type::IPv4: return m_ipv4_address.to_string(); + case Type::Local: + return m_local_address; default: return "[CSocketAddress]"; } @@ -34,4 +44,5 @@ public: private: Type m_type { Type::Invalid }; IPv4Address m_ipv4_address; + String m_local_address; }; diff --git a/Libraries/LibCore/Makefile b/Libraries/LibCore/Makefile index e7b25671e4..2e119ee71f 100644 --- a/Libraries/LibCore/Makefile +++ b/Libraries/LibCore/Makefile @@ -5,6 +5,7 @@ OBJS = \ CIODevice.o \ CFile.o \ CSocket.o \ + CLocalSocket.o \ CTCPSocket.o \ CElapsedTimer.o \ CNotifier.o \ diff --git a/Makefile.common b/Makefile.common index af82b9c042..cbe8e38365 100644 --- a/Makefile.common +++ b/Makefile.common @@ -8,7 +8,7 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) SERENITY_BASE_DIR := $(patsubst %/,%,$(dir $(MAKEFILE_PATH))) INCLUDE_FLAGS = -I$(SERENITY_BASE_DIR) -I$(SERENITY_BASE_DIR)/Libraries -I. -I$(SERENITY_BASE_DIR)/Libraries/LibC -I$(SERENITY_BASE_DIR)/Servers -I$(SERENITY_BASE_DIR)/Libraries/LibM -LDFLAGS = -L$(SERENITY_BASE_DIR)/Libraries/LibC -L$(SERENITY_BASE_DIR)/Libraries/LibCore -L$(SERENITY_BASE_DIR)/Libraries/LibM -L$(SERENITY_BASE_DIR)/Libraries/LibGUI +LDFLAGS = -L$(SERENITY_BASE_DIR)/Libraries/LibC -L$(SERENITY_BASE_DIR)/Libraries/LibCore -L$(SERENITY_BASE_DIR)/Libraries/LibM -L$(SERENITY_BASE_DIR)/Libraries/LibGUI -L$(SERENITY_BASE_DIR)/Libraries/LibAudio CLANG_FLAGS = -Wconsumed -m32 -ffreestanding -march=i686 #SUGGEST_FLAGS = -Wsuggest-final-types -Wsuggest-final-methods -Wsuggest-override #-Wsuggest-attribute=noreturn CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(FLAVOR_FLAGS) $(ARCH_FLAGS) $(STANDARD_FLAGS) $(SUGGEST_FLAGS) $(INCLUDE_FLAGS) $(DEFINES) diff --git a/Servers/AudioServer/Makefile b/Servers/AudioServer/Makefile index 3e36a18acd..74b7b9c22d 100644 --- a/Servers/AudioServer/Makefile +++ b/Servers/AudioServer/Makefile @@ -11,7 +11,7 @@ DEFINES += -DUSERLAND all: $(APP) $(APP): $(OBJS) - $(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lc -lcore + $(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lc -lcore -laudio .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Servers/AudioServer/main.cpp b/Servers/AudioServer/main.cpp index 43cae47a15..915aad33f5 100644 --- a/Servers/AudioServer/main.cpp +++ b/Servers/AudioServer/main.cpp @@ -1,160 +1,45 @@ #include +#include +#include +#include +#include +#include -u32 read_u32(const ByteBuffer& buf, u32& off) +#include +#include +#include + +class ASEventLoop { - ASSERT(buf.size() - off >= 4); - u32 b0 = buf[off + 0]; - u32 b1 = buf[off + 1]; - u32 b2 = buf[off + 2]; - u32 b3 = buf[off + 3]; +public: + ASEventLoop(); + int exec() { return m_event_loop.exec(); } +private: + CEventLoop m_event_loop; + CLocalSocket m_server_sock; + OwnPtr m_server_notifier; - u32 ret = 0; - ret |= (u8(b3) << 24); - ret |= (u8(b2) << 16); - ret |= (u8(b1) << 8); - ret |= (u8(b0)); - - off += 4; - return ret; -} - -u16 read_u16(const ByteBuffer& buf, u32& off) -{ - ASSERT(buf.size() - off >= 2); - u16 b0 = buf[off + 0]; - u16 b1 = buf[off + 1]; - - u16 ret = 0; - ret |= (u8(b1) << 8); - ret |= (u8(b0)); - - off += 2; - return ret; -} - -ByteBuffer read_wav_data(const StringView& path) -{ - CFile wav(path); - if (!wav.open(CIODevice::ReadOnly)) { - dbgprintf("Can't open wav to dump it to audio: %s", wav.error_string()); - return {}; - } - - const auto& contents = wav.read_all(); - u32 off = 0; - - if (contents.size() - off < 12) { - dbgprintf("WAV is too small (no header, %d bytes)\n", contents.size()); - return {}; - } - - dbgprintf("Trying to parse %d bytes of wav\n", contents.size()); - -#define CHECK_OK(msg) \ - do { \ - ASSERT(ok); \ - if (!ok) { \ - dbgprintf("%s failed\n", msg); \ - return {}; \ - } else { \ - dbgprintf("%S is OK!\n", msg); \ - } \ - } while (0); - - bool ok = true; - u32 riff = read_u32(contents, off); - ok = ok && riff == 0x46464952; // "RIFF" - CHECK_OK("RIFF header"); - - u32 sz = read_u32(contents, off); - ASSERT(sz < 1024 * 1024 * 42); - ok = ok && sz < 1024 * 1024 * 42; // arbitrary - CHECK_OK("File size"); - - u32 wave = read_u32(contents, off); - ok = ok && wave == 0x45564157; // "WAVE" - CHECK_OK("WAVE header"); - - if (contents.size() - off < 8) { - dbgprintf("WAV is too small (no fmt, %d bytes)\n", contents.size()); - return {}; - } - - u32 fmt_id = read_u32(contents, off); - ok = ok && fmt_id == 0x20746D66; // "FMT" - CHECK_OK("FMT header"); - - u32 fmt_size = read_u32(contents, off); - ok = ok && fmt_size == 16; - ASSERT(fmt_size == 16); - CHECK_OK("FMT size"); - - if (contents.size() - off < 16) { - dbgprintf("WAV is too small (fmt chunk, %d bytes)\n", contents.size()); - return {}; - } - - u16 audio_format = read_u16(contents, off); - ok = ok && audio_format == 1; // WAVE_FORMAT_PCM - ASSERT(audio_format == 1); - CHECK_OK("Audio format"); - - u16 num_channels = read_u16(contents, off); - ok = ok && num_channels == 1; - ASSERT(num_channels == 1); - CHECK_OK("Channel count"); - - u32 sample_rate = read_u32(contents, off); - CHECK_OK("Sample rate"); - - off += 4; // bytes per sec: we don't care. - off += 2; // block align: we don't care. - - u16 bits_per_sample = read_u16(contents, off); - ok = ok && (bits_per_sample == 8 || bits_per_sample == 16); - ASSERT(bits_per_sample == 8 || bits_per_sample == 16); - CHECK_OK("Bits per sample"); - - dbgprintf("Read WAV of format %d with num_channels %d sample rate %d, bits per sample %d\n", audio_format, num_channels, sample_rate, bits_per_sample); - - // Read chunks until we find DATA - if (off >= u32(contents.size()) - 8) { - ok = ok && false; - ASSERT_NOT_REACHED(); - CHECK_OK("Premature EOF without DATA"); - } - - bool found_data = false; - u32 data_sz = 0; - while (off < u32(contents.size()) - 8) { - u32 chunk_id = read_u32(contents, off); - data_sz = read_u32(contents, off); - if (chunk_id == 0x61746164) { // DATA - found_data = true; - break; - } - off += data_sz; - } - - ok = ok && found_data; - ASSERT(found_data); - CHECK_OK("Found no data chunk"); - - ok = ok && data_sz <= (contents.size() - off); - CHECK_OK("Bad DATA size"); - - return contents.slice(off, data_sz); -} + void drain_server(); +}; void read_and_play_wav() { CFile audio("/dev/audio"); if (!audio.open(CIODevice::WriteOnly)) { - dbgprintf("Can't open audio device: %s", audio.error_string()); + dbgprintf("Can't open audio device: %s\n", audio.error_string()); return; } - const auto& contents = read_wav_data("/home/anon/tmp.wav"); + AWavLoader loader; + const auto& file = loader.load_wav("/home/anon/tmp.wav"); + if (!file) { + dbgprintf("Can't parse WAV: %s\n", loader.error_string()); + return; + } + + dbgprintf("Read WAV of format %d with num_channels %d sample rate %d, bits per sample %d\n", (u8)file->format(), file->channel_count(), file->sample_rate_per_second(), file->bits_per_sample()); + + auto contents = file->sample_data(); const int chunk_size = 4096; int i = 0; while (i < contents.size()) { @@ -164,8 +49,41 @@ void read_and_play_wav() } } -int main(int, char**) +ASEventLoop::ASEventLoop() { read_and_play_wav(); - return 0; + + unlink("/tmp/asportal"); + + sockaddr_un address; + address.sun_family = AF_LOCAL; + strcpy(address.sun_path, "/tmp/asportal"); + int rc = bind(m_server_sock.fd(), (const sockaddr*)&address, sizeof(address)); + ASSERT(rc == 0); + rc = listen(m_server_sock.fd(), 5); + ASSERT(rc == 0); + + m_server_notifier = make(m_server_sock.fd(), CNotifier::Read); + m_server_notifier->on_ready_to_read = [this] { drain_server(); }; +} + +void ASEventLoop::drain_server() +{ + sockaddr_un address; + socklen_t address_size = sizeof(address); + int client_fd = accept(m_server_sock.fd(), (sockaddr*)&address, &address_size); + if (client_fd < 0) { + dbgprintf("WindowServer: accept() failed: %s\n", strerror(errno)); + } else { + dbgprintf("AudioServer: accept()ed client %d\n", client_fd); + String s("hello, client!\n"); + write(client_fd, s.characters(), s.length()); + close(client_fd); + } +} + +int main(int, char**) +{ + ASEventLoop event_loop; + return event_loop.exec(); } diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp index 781695af91..58819829ac 100644 --- a/Servers/WindowServer/WSEventLoop.cpp +++ b/Servers/WindowServer/WSEventLoop.cpp @@ -26,18 +26,20 @@ WSEventLoop::WSEventLoop() unlink("/tmp/wsportal"); - m_server_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - ASSERT(m_server_fd >= 0); sockaddr_un address; address.sun_family = AF_LOCAL; strcpy(address.sun_path, "/tmp/wsportal"); - int rc = bind(m_server_fd, (const sockaddr*)&address, sizeof(address)); + int rc = bind(m_server_sock.fd(), (const sockaddr*)&address, sizeof(address)); ASSERT(rc == 0); - rc = listen(m_server_fd, 5); + rc = listen(m_server_sock.fd(), 5); ASSERT(rc == 0); + ASSERT(m_server_sock.fd() >= 0); ASSERT(m_keyboard_fd >= 0); ASSERT(m_mouse_fd >= 0); + + m_server_notifier = make(m_server_sock.fd(), CNotifier::Read); + m_server_notifier->on_ready_to_read = [this] { drain_server(); }; } WSEventLoop::~WSEventLoop() @@ -48,7 +50,7 @@ void WSEventLoop::drain_server() { sockaddr_un address; socklen_t address_size = sizeof(address); - int client_fd = accept(m_server_fd, (sockaddr*)&address, &address_size); + int client_fd = accept(m_server_sock.fd(), (sockaddr*)&address, &address_size); if (client_fd < 0) { dbgprintf("WindowServer: accept() failed: %s\n", strerror(errno)); } else { @@ -333,7 +335,6 @@ void WSEventLoop::add_file_descriptors_for_select(fd_set& fds, int& max_fd_added }; add_fd_to_set(m_keyboard_fd, fds); add_fd_to_set(m_mouse_fd, fds); - add_fd_to_set(m_server_fd, fds); WSClientConnection::for_each_client([&](WSClientConnection& client) { add_fd_to_set(client.fd(), fds); }); @@ -341,8 +342,6 @@ void WSEventLoop::add_file_descriptors_for_select(fd_set& fds, int& max_fd_added void WSEventLoop::process_file_descriptors_after_select(const fd_set& fds) { - if (FD_ISSET(m_server_fd, &fds)) - drain_server(); if (FD_ISSET(m_keyboard_fd, &fds)) drain_keyboard(); if (FD_ISSET(m_mouse_fd, &fds)) diff --git a/Servers/WindowServer/WSEventLoop.h b/Servers/WindowServer/WSEventLoop.h index 8c76a17efb..8935dd0264 100644 --- a/Servers/WindowServer/WSEventLoop.h +++ b/Servers/WindowServer/WSEventLoop.h @@ -2,6 +2,8 @@ #include #include +#include +#include class WSClientConnection; struct WSAPI_ClientMessage; @@ -25,5 +27,6 @@ private: int m_keyboard_fd { -1 }; int m_mouse_fd { -1 }; - int m_server_fd { -1 }; + CLocalSocket m_server_sock; + OwnPtr m_server_notifier; };