Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9e44dd8
feat: Initial commit
ripxorip Sep 5, 2025
a8c1260
no ping-pong
ripxorip Sep 5, 2025
c146aa6
Faster network on windows
ripxorip Sep 5, 2025
9ff4f4f
fix: Broken ping-pong
ripxorip Sep 5, 2025
e96e729
feat: (untested) Backend agnostic version
ripxorip Sep 6, 2025
b79111a
feat: Simulated backend + refined simulator for dev setup
ripxorip Sep 6, 2025
00952fe
fix: Single channel for simulated backend
ripxorip Sep 6, 2025
bd8bd3f
feat: Adds proper analysis in the simulated backend
ripxorip Sep 6, 2025
6f6d8d2
fix: Tests conditional on pipewire
ripxorip Sep 6, 2025
922617f
feat: Add Windows client simulator for PWAR protocol
ripxorip Sep 6, 2025
d6fbd8a
feat: Client simulator now works like linux
ripxorip Sep 7, 2025
fb12b64
Update default server IP and client port
ripxorip Sep 7, 2025
ff6ed81
feat: Removes oneshot mode
ripxorip Sep 8, 2025
2fcdc5e
fix: GUI shall always use pipewire
ripxorip Sep 8, 2025
51242fa
initial commit
ripxorip Sep 9, 2025
1b4d894
feat: Adds test
ripxorip Sep 10, 2025
981bcd2
feat: Working tests
ripxorip Sep 10, 2025
77122b7
feat: Simplification
ripxorip Sep 10, 2025
73c53de
feat: Simplified Windows rcv
ripxorip Sep 10, 2025
7bfadc1
feat: Simplifications
ripxorip Sep 10, 2025
a8ecae4
feat: Adds current fill level to latency statse
ripxorip Sep 10, 2025
8f6e783
Refactor UDP listener and remove router dependency
ripxorip Sep 10, 2025
58cd7a4
fix: GUI changes
ripxorip Sep 10, 2025
0810e28
feat: Common clocks to determine latency direction
ripxorip Sep 10, 2025
7e16e14
feat: Adds the device latency as well
ripxorip Sep 11, 2025
2d5d3f0
feat: Interleaved frames, chore: cleanup
ripxorip Sep 11, 2025
0969c6b
feat: Device buffers separated from windows packet size
ripxorip Sep 11, 2025
e68a86f
fix: alsa
ripxorip Sep 11, 2025
117e63f
fix: Alsa
ripxorip Sep 11, 2025
7956e03
Refactor packet handling and options in simulator and ASIO
ripxorip Sep 11, 2025
6b8e07d
Merge branch 'alsa' of https://github.com/ripxorip/PWAR into alsa
ripxorip Sep 11, 2025
a2312d0
chore: Cleanup of torture in linux
ripxorip Sep 11, 2025
4848474
fix: Pipewire crash
ripxorip Sep 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Enable testing
enable_testing()

# Platform-specific builds
if(WIN32)
# Windows-specific targets
add_subdirectory(windows/asio)
add_subdirectory(windows/torture)
add_subdirectory(windows/simulator)
else()
# Linux-specific targets
add_subdirectory(linux)

# Protocol tests (Linux only - tests not needed on Windows)
add_subdirectory(protocol/test)
endif()
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Download the Windows ASIO driver from the [releases page](https://github.com/rip
3. **Configure settings** through the intuitive interface:
- Set your Windows host IP address
- Choose audio buffer size and sample rate
- Enable/disable oneshot mode and variable buffer sizes
- Enable/disable variable buffer sizes
4. **Start the relay** with the click of a button

### Using the Command Line
Expand All @@ -105,7 +105,7 @@ Download the Windows ASIO driver from the [releases page](https://github.com/rip
- ⚡ **Ultra-low latency**: Real-time, zero-drift audio streaming
- 🔄 **Bidirectional audio**: Stream audio both ways between Windows and Linux
- 🎛️ **Variable buffer sizes**: Runtime adjustment of buffer size and latency
- 🎯 **Oneshot mode**: Optimized single-packet transmission for minimal latency

- 🖥️ **Qt-based GUI**: Intuitive graphical interface for easy configuration
- 💻 **CLI support**: Command-line interface for headless and scripted setups
- 🪟 **ASIO driver**: Native Windows ASIO driver for maximum compatibility
Expand Down Expand Up @@ -133,16 +133,15 @@ Options:
--ip IP_ADDRESS, -i IP_ADDRESS Target Windows host IP address (default: 192.168.66.3)
--port PORT, -p PORT UDP port to use (default: 8321)
--buffer_size SIZE, -b SIZE Audio buffer size in frames (default: 64)
--oneshot Enable oneshot mode

--passthrough_test, -pt Enable passthrough test mode
```

---

## 🎛️ Key Features Explained

### Oneshot Mode
Oneshot mode optimizes for ultra-low latency by sending audio in single packets rather than streaming continuously. This significantly reduces latency but may increase CPU usage.


### Variable Buffer Sizes
Allows runtime adjustment of buffer sizes to balance between latency and stability. Smaller buffers = lower latency but require more CPU and stable network.
Expand Down Expand Up @@ -220,15 +219,15 @@ Test binaries will be in `protocol/test/build/`.

### Common Issues
- **No audio streaming**: Ensure both machines are on the same network and firewall allows UDP traffic on port 8321
- **High latency**: Try enabling oneshot mode and reducing buffer sizes
- **High latency**: Try reducing buffer sizes
- **Audio dropouts**: Increase buffer size or check network stability
- **ASIO driver not found**: Make sure you've registered the DLL with `regsvr32.exe`

### Performance Tips
- Use wired network connections for best results
- Match sample rates between Windows and Linux (48kHz recommended)
- Close unnecessary applications to reduce CPU load
- Consider using oneshot mode for minimal latency scenarios


---

Expand Down
187 changes: 127 additions & 60 deletions linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,56 +1,112 @@
# CMakeLists.txt for Linux targets
# CMakeLists.txt for Linux targets - Audio Backend Agnostic
cmake_minimum_required(VERSION 3.15)

# Find required packages
# Math library (always required)
find_library(MATH_LIB m)

# Find required packages with optional fallbacks
find_package(PkgConfig REQUIRED)
pkg_check_modules(PIPEWIRE REQUIRED libpipewire-0.3)

# Find Qt5 for GUI
find_package(Qt5 COMPONENTS Core Widgets Quick Qml QUIET)
# Try to find PipeWire (optional)
pkg_check_modules(PIPEWIRE libpipewire-0.3)
if(PIPEWIRE_FOUND)
message(STATUS "PipeWire found - PipeWire backend will be available")
set(HAVE_PIPEWIRE TRUE)
else()
message(STATUS "PipeWire not found - PipeWire backend will be disabled")
set(HAVE_PIPEWIRE FALSE)
endif()

# Math library
find_library(MATH_LIB m)
# Try to find ALSA (optional)
pkg_check_modules(ALSA alsa)
if(ALSA_FOUND)
message(STATUS "ALSA found - ALSA backend will be available")
set(HAVE_ALSA TRUE)
else()
message(STATUS "ALSA not found - ALSA backend will be disabled")
set(HAVE_ALSA FALSE)
endif()

# Ensure at least one audio backend is available
if(NOT HAVE_PIPEWIRE AND NOT HAVE_ALSA)
message(FATAL_ERROR "Neither PipeWire nor ALSA found. At least one audio backend is required.")
endif()

# Find Qt5 for GUI (optional)
find_package(Qt5 COMPONENTS Core Widgets Quick Qml QUIET)

# Include directories
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/protocol)

# Protocol sources
# Protocol sources (backend agnostic)
set(PROTOCOL_SOURCES
${CMAKE_SOURCE_DIR}/protocol/pwar_router.c
${CMAKE_SOURCE_DIR}/protocol/pwar_rcv_buffer.c
${CMAKE_SOURCE_DIR}/protocol/pwar_ring_buffer.c
${CMAKE_SOURCE_DIR}/protocol/latency_manager.c
)

# Build shared library
# Audio backend sources (conditional compilation)
set(AUDIO_BACKEND_SOURCES
audio_backend.c
simulated_backend.c # Always available for testing
)

if(HAVE_ALSA)
list(APPEND AUDIO_BACKEND_SOURCES alsa_backend.c)
endif()

if(HAVE_PIPEWIRE)
list(APPEND AUDIO_BACKEND_SOURCES pipewire_backend.c)
endif()

# Build shared library with agnostic audio backend support
add_library(pwar SHARED
libpwar.c
${PROTOCOL_SOURCES}
${AUDIO_BACKEND_SOURCES}
)

target_include_directories(pwar PRIVATE
${PIPEWIRE_INCLUDE_DIRS}
)
# Set compile definitions based on available backends
target_compile_definitions(pwar PRIVATE HAVE_SIMULATED=1) # Always available

target_link_libraries(pwar
${PIPEWIRE_LIBRARIES}
${MATH_LIB}
)
if(HAVE_ALSA)
target_compile_definitions(pwar PRIVATE HAVE_ALSA=1)
target_include_directories(pwar PRIVATE ${ALSA_INCLUDE_DIRS})
endif()

target_compile_options(pwar PRIVATE ${PIPEWIRE_CFLAGS_OTHER})
if(HAVE_PIPEWIRE)
target_compile_definitions(pwar PRIVATE HAVE_PIPEWIRE=1)
target_include_directories(pwar PRIVATE ${PIPEWIRE_INCLUDE_DIRS})
endif()

# Link libraries conditionally
target_link_libraries(pwar ${MATH_LIB} pthread)

if(HAVE_ALSA)
target_link_libraries(pwar ${ALSA_LIBRARIES})
target_compile_options(pwar PRIVATE ${ALSA_CFLAGS_OTHER})
endif()

# CLI executable
if(HAVE_PIPEWIRE)
target_link_libraries(pwar ${PIPEWIRE_LIBRARIES})
target_compile_options(pwar PRIVATE ${PIPEWIRE_CFLAGS_OTHER})
endif()

# CLI executable (agnostic)
add_executable(pwar_cli
pwar_cli.c
)

target_link_libraries(pwar_cli
pwar
${PIPEWIRE_LIBRARIES}
${MATH_LIB}
)
target_link_libraries(pwar_cli pwar)

target_compile_options(pwar_cli PRIVATE ${PIPEWIRE_CFLAGS_OTHER})
# Set compile definitions for CLI based on available backends
if(HAVE_ALSA)
target_compile_definitions(pwar_cli PRIVATE HAVE_ALSA=1)
endif()

if(HAVE_PIPEWIRE)
target_compile_definitions(pwar_cli PRIVATE HAVE_PIPEWIRE=1)
endif()

# GUI executable (only if Qt5 is found)
if(Qt5_FOUND)
Expand All @@ -74,52 +130,36 @@ if(Qt5_FOUND)
Qt5::Widgets
Qt5::Quick
Qt5::Qml
${PIPEWIRE_LIBRARIES}
${MATH_LIB}
)

target_compile_options(pwar_gui PRIVATE ${PIPEWIRE_CFLAGS_OTHER})
# Set compile definitions for GUI based on available backends
if(HAVE_ALSA)
target_compile_definitions(pwar_gui PRIVATE HAVE_ALSA=1)
endif()

if(HAVE_PIPEWIRE)
target_compile_definitions(pwar_gui PRIVATE HAVE_PIPEWIRE=1)
endif()

message(STATUS "Qt5 found - building GUI application")
else()
message(STATUS "Qt5 not found - skipping GUI application")
endif()

# Torture test executable
add_executable(pwar_torture
torture.c
)

target_include_directories(pwar_torture PRIVATE
${PIPEWIRE_INCLUDE_DIRS}
)

target_link_libraries(pwar_torture
${PIPEWIRE_LIBRARIES}
${MATH_LIB}
)

target_compile_options(pwar_torture PRIVATE ${PIPEWIRE_CFLAGS_OTHER})

# Windows simulator executable
add_executable(windows_sim
windows_sim.c
# Client simulator executable (agnostic)
add_executable(client_simulator
client_simulator.c
${PROTOCOL_SOURCES}
)

target_include_directories(windows_sim PRIVATE
${PIPEWIRE_INCLUDE_DIRS}
)

target_link_libraries(windows_sim
${PIPEWIRE_LIBRARIES}
${MATH_LIB}
)

target_compile_options(windows_sim PRIVATE ${PIPEWIRE_CFLAGS_OTHER})
target_link_libraries(client_simulator pwar)

# Integration test subdirectory
add_subdirectory(test)
# Integration test subdirectory (only if PipeWire is available)
if(HAVE_PIPEWIRE)
add_subdirectory(test)
else()
message(STATUS "PipeWire not found - skipping integration tests")
endif()

# Install targets
install(TARGETS pwar pwar_cli DESTINATION bin)
Expand All @@ -141,3 +181,30 @@ add_custom_target(install-local
COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR} --prefix ${CMAKE_SOURCE_DIR}/install
COMMENT "Installing to local directory for testing"
)

# Print build configuration summary
message(STATUS "=== PWAR Build Configuration ===")
message(STATUS "Audio Backends:")
if(HAVE_ALSA)
message(STATUS " ALSA: ENABLED")
else()
message(STATUS " ALSA: DISABLED (not found)")
endif()

if(HAVE_PIPEWIRE)
message(STATUS " PipeWire: ENABLED")
else()
message(STATUS " PipeWire: DISABLED (not found)")
endif()

message(STATUS " Simulated: ENABLED (always available for testing)")

message(STATUS "Executables:")
message(STATUS " pwar_cli: YES (agnostic)")
if(Qt5_FOUND)
message(STATUS " pwar_gui: YES (agnostic)")
else()
message(STATUS " pwar_gui: NO (Qt5 not found)")
endif()
message(STATUS " client_simulator: YES (agnostic)")
message(STATUS "================================")
Loading