Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Major features:
- [x] Built-in Virtual Display with HDR support that matches the resolution/framerate config of your client automatically
- [x] Permission management for clients
- [x] Clipboard sync
- [x] Windows remote microphone redirection through VB-CABLE with host-side debug visibility
- [x] Commands for client connection/disconnection (checkout [Auto pause/resume games](https://github.com/ClassicOldSong/Apollo/wiki/Auto-pause-resume-games))
- [x] Input only mode

Expand Down Expand Up @@ -35,6 +36,14 @@ Apollo uses SudoVDA for virtual display. It features auto resolution and framera

The virtual display works just like any physically attached monitors with SudoVDA, there's completely no need for a super complicated solution to "fix" resolution configurations for your devices. Unlike all other solutions that reuses one identity or generate a random one each time for any virtual display sessions, **Apollo assigns a fixed identity for each Artemis/Moonlight client, so your display configuration will be automatically remembered and managed by Windows natively.**

## About Remote Microphone Redirection

This fork adds a working Windows remote microphone path for compatible Moonlight/Artemis clients.

Apollo accepts the client's Opus microphone packets, decodes them on the host, and renders the audio into the VB-CABLE playback endpoint `CABLE Input`. Host applications should then select `CABLE Output` as their microphone source.

Setup and implementation notes are documented in [docs/remote_microphone.md](docs/remote_microphone.md).

## Configuration for dual GPU laptops

Apollo supports dual GPUs seamlessly.
Expand Down
4 changes: 4 additions & 0 deletions cmake/compile_definitions/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ set(PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_ram.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/display_wgc.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/audio.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/apollo_vmic.h"
"${CMAKE_SOURCE_DIR}/src/platform/windows/apollo_vmic.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/mic_write.h"
"${CMAKE_SOURCE_DIR}/src/platform/windows/mic_write.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/virtual_display.h"
"${CMAKE_SOURCE_DIR}/src/platform/windows/virtual_display.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/windows/utils.h"
Expand Down
11 changes: 6 additions & 5 deletions cmake/dependencies/Boost_Sunshine.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#
include_guard(GLOBAL)

set(BOOST_VERSION "1.89.0")
set(BOOST_MIN_VERSION "1.89.0")
set(BOOST_FETCH_VERSION "1.89.0")
set(BOOST_COMPONENTS
filesystem
locale
Expand All @@ -30,9 +31,9 @@ endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.30")
cmake_policy(SET CMP0167 NEW) # Get BoostConfig.cmake from upstream
endif()
find_package(Boost CONFIG ${BOOST_VERSION} EXACT COMPONENTS ${BOOST_COMPONENTS})
find_package(Boost CONFIG ${BOOST_MIN_VERSION} COMPONENTS ${BOOST_COMPONENTS})
if(NOT Boost_FOUND)
message(STATUS "Boost v${BOOST_VERSION} package not found in the system. Falling back to FetchContent.")
message(STATUS "Boost v${BOOST_MIN_VERSION}+ package not found in the system. Falling back to FetchContent.")
include(FetchContent)

if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
Expand All @@ -54,8 +55,8 @@ if(NOT Boost_FOUND)

# Limit boost to the required libraries only
set(BOOST_INCLUDE_LIBRARIES ${BOOST_COMPONENTS})
set(BOOST_URL "https://github.com/boostorg/boost/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
set(BOOST_HASH "SHA256=f48b48390380cfb94a629872346e3a81370dc498896f16019ade727ab72eb1ec")
set(BOOST_URL "https://github.com/boostorg/boost/releases/download/boost-${BOOST_FETCH_VERSION}/boost-${BOOST_FETCH_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
set(BOOST_HASH "SHA256=67acec02d0d118b5de9eb441f5fb707b3a1cdd884be00ca24b9a73c995511f74")

if(CMAKE_VERSION VERSION_LESS "3.24.0")
FetchContent_Declare(
Expand Down
8 changes: 8 additions & 0 deletions cmake/packaging/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ install(FILES ${VIGEMBUS_INSTALLER}
# Adding tools
install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi)
install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio)
install(TARGETS apollovmicctl RUNTIME DESTINATION "tools" COMPONENT application)

# Mandatory tools
install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT application)
Expand All @@ -29,6 +30,9 @@ install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT application)
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/drivers/sudovda"
DESTINATION "drivers"
COMPONENT sudovda)
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/drivers/vbcable"
DESTINATION "drivers"
COMPONENT vbcable)

# Mandatory scripts
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/"
Expand Down Expand Up @@ -101,6 +105,10 @@ set(CPACK_COMPONENT_SUDOVDA_DESCRIPTION "Driver required for Virtual Display to
set(CPACK_COMPONENT_SUDOVDA_GROUP "Drivers")
set(CPACK_COMPONENT_SUDOVDA_REQUIRED true)

set(CPACK_COMPONENT_VBCABLE_DISPLAY_NAME "VB-CABLE")
set(CPACK_COMPONENT_VBCABLE_DESCRIPTION "Official VB-CABLE dependency for Apollo microphone passthrough on Windows.")
set(CPACK_COMPONENT_VBCABLE_GROUP "Drivers")

# audio tool
set(CPACK_COMPONENT_AUDIO_DISPLAY_NAME "audio-info")
set(CPACK_COMPONENT_AUDIO_DESCRIPTION "CLI tool providing information about sound devices.")
Expand Down
8 changes: 8 additions & 0 deletions cmake/packaging/windows_nsis.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
nsExec::ExecToLog 'icacls \\\"$INSTDIR\\\" /reset'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" add'
nsExec::ExecToLog '\\\"$INSTDIR\\\\drivers\\\\sudovda\\\\install.bat\\\"'
IfSilent +3 0
MessageBox MB_OK|MB_ICONINFORMATION \\\"Apollo uses VB-CABLE for Windows microphone passthrough. Origin: www.vb-cable.com. VB-CABLE is a donationware, all participations are welcome.\\\"
nsExec::ExecToLog '\\\"$INSTDIR\\\\drivers\\\\vbcable\\\\install.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"'
nsExec::ExecToLog \
Expand Down Expand Up @@ -43,6 +46,11 @@ set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
/SD IDNO IDNO NoSudoVDA
nsExec::ExecToLog '\\\"$INSTDIR\\\\drivers\\\\sudovda\\\\uninstall.bat\\\"'; skipped if no
NoSudoVDA:
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove VB-CABLE used for Apollo microphone passthrough?' \
/SD IDNO IDNO NoVBCable
nsExec::ExecToLog '\\\"$INSTDIR\\\\drivers\\\\vbcable\\\\uninstall.bat\\\"'; skipped if no
NoVBCable:
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \
/SD IDNO IDNO NoDelete
Expand Down
17 changes: 14 additions & 3 deletions cmake/targets/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,18 @@ else()
endif()

#WebUI build
find_program(NPM npm REQUIRED)
if(WIN32)
unset(NODE CACHE)
unset(NPM_CLI CACHE)
find_program(NODE node.exe REQUIRED)
find_file(NPM_CLI npm-cli.js
PATHS
"${CMAKE_PREFIX_PATH}"
"C:/msys64/ucrt64/lib/node_modules/npm/bin"
REQUIRED)
else()
find_program(NPM npm REQUIRED)
endif()

if (NPM_OFFLINE)
set(NPM_INSTALL_FLAGS "--offline")
Expand All @@ -63,8 +74,8 @@ endif()
add_custom_target(web-ui ALL
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Installing NPM Dependencies and Building the Web UI"
COMMAND "$<$<BOOL:${WIN32}>:cmd;/C>" "${NPM}" install ${NPM_INSTALL_FLAGS}
COMMAND "${CMAKE_COMMAND}" -E env "SUNSHINE_BUILD_HOMEBREW=${NPM_BUILD_HOMEBREW}" "SUNSHINE_SOURCE_ASSETS_DIR=${NPM_SOURCE_ASSETS_DIR}" "SUNSHINE_ASSETS_DIR=${NPM_ASSETS_DIR}" "$<$<BOOL:${WIN32}>:cmd;/C>" "${NPM}" run build # cmake-lint: disable=C0301
COMMAND "$<$<BOOL:${WIN32}>:${NODE};${NPM_CLI}>$<$<NOT:$<BOOL:${WIN32}>>:${NPM}>" install ${NPM_INSTALL_FLAGS}
COMMAND "${CMAKE_COMMAND}" -E env "SUNSHINE_BUILD_HOMEBREW=${NPM_BUILD_HOMEBREW}" "SUNSHINE_SOURCE_ASSETS_DIR=${NPM_SOURCE_ASSETS_DIR}" "SUNSHINE_ASSETS_DIR=${NPM_ASSETS_DIR}" "$<$<BOOL:${WIN32}>:${NODE};${NPM_CLI}>$<$<NOT:$<BOOL:${WIN32}>>:${NPM}>" run build # cmake-lint: disable=C0301
COMMAND_EXPAND_LISTS
VERBATIM)

Expand Down
79 changes: 79 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,62 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>

### mic_backend

<table>
<tr>
<td>Description</td>
<td colspan="2">
Select how Apollo exposes redirected client microphone audio on Windows.
In this fork, Windows microphone redirection is standardized on the `vb_cable` backend.
Apollo renders decoded client microphone audio into the VB-CABLE playback endpoint, and host applications
should select the paired `CABLE Output` recording device.
@note{This option is currently only used on Windows hosts.}
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
vb_cable
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
mic_backend = vb_cable
@endcode</td>
</tr>
</table>

### mic_device

<table>
<tr>
<td>Description</td>
<td colspan="2">
The host-side device used for redirected client microphone audio.
On Windows, Apollo currently auto-detects the VB-CABLE render endpoint and this value is typically left unset.
On Linux and macOS this should point at the virtual device Apollo writes into.
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">Unset.</td>
</tr>
<tr>
<td>Example (Windows)</td>
<td colspan="2">@code{}
mic_device = CABLE Input (VB-Audio Virtual Cable)
@endcode</td>
</tr>
<tr>
<td>Example (Linux)</td>
<td colspan="2">@code{}
mic_device = sunshine-mic
@endcode</td>
</tr>
</table>

### stream_audio

<table>
Expand All @@ -848,6 +904,29 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>

### stream_mic

<table>
<tr>
<td>Description</td>
<td colspan="2">
Whether Apollo should accept redirected client microphone audio and inject it into a host-side microphone backend.
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
disabled
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
stream_mic = enabled
@endcode</td>
</tr>
</table>

### install_steam_audio_drivers

<table>
Expand Down
61 changes: 61 additions & 0 deletions docs/remote_microphone.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Remote Microphone Support

This fork adds a working host-side remote microphone path for Apollo, focused on Windows hosts and VB-CABLE integration.

## Overview

The microphone path is:

1. A compatible Moonlight/Artemis client captures local microphone audio.
2. The client sends encrypted or unencrypted microphone packets to Apollo on the dedicated microphone stream.
3. Apollo receives the packets, decrypts them when needed, and decodes the Opus frames on the host.
4. Apollo renders the decoded PCM into the VB-CABLE playback endpoint `CABLE Input`.
5. Host applications consume that audio from the VB-CABLE recording endpoint `CABLE Output`.

This keeps the host-side application flow simple: Apollo writes into VB-CABLE, and games, chat apps, or capture tools use `CABLE Output` as the microphone.

## What Changed

The working implementation in this fork includes:

- Dedicated microphone session handling in the stream path, including packet receive, optional decryption, and per-session lifecycle management.
- Windows microphone backend initialization and teardown that stays alive for the full remote microphone session.
- A VB-CABLE-backed Windows render path that auto-detects `CABLE Input`, creates a shared-mode WASAPI render client, decodes Opus microphone frames, and writes PCM into the render buffer.
- Host-side recovery for recoverable WASAPI failures such as device invalidation or audio service restarts.
- A Remote Microphone Debug panel in the web UI that shows packet arrival, decode status, render status, signal detection, counters, and recent mic events.

## Key Files

- `src/stream.cpp`: microphone socket handling, session startup/shutdown, and packet routing.
- `src/audio.cpp`: shared microphone debug state and persistent audio context ownership for the redirect device.
- `src/platform/windows/audio.cpp`: Windows microphone backend selection and redirect device ownership.
- `src/platform/windows/apollo_vmic.cpp`: VB-CABLE backend wrapper.
- `src/platform/windows/mic_write.cpp`: device discovery, WASAPI initialization, Opus decode, and VB-CABLE rendering.
- `src_assets/common/assets/web/configs/tabs/AudioVideo.vue`: Remote Microphone Debug UI.

## Windows Requirements

- Install VB-CABLE on the host.
- Ensure the playback endpoint `CABLE Input` exists and is enabled.
- In host applications, select `CABLE Output` as the microphone/recording source.
- Enable `stream_mic` in Apollo.
- Use a client build that supports Apollo microphone redirection.

## Configuration Notes

- `stream_mic` enables the host microphone redirect path.
- `mic_backend` defaults to `vb_cable` on Windows in this fork.
- On Windows, Apollo currently auto-detects the VB-CABLE render endpoint and standardizes on the VB-CABLE backend.
- `mic_device` is mainly relevant on non-Windows platforms. The Windows path currently targets VB-CABLE automatically.

## Debugging

The Audio/Video page on Windows exposes a Remote Microphone Debug panel that shows:

- whether the client is sending packets
- whether Apollo is decoding microphone frames
- whether Apollo is rendering into VB-CABLE
- whether non-silent input is being detected
- the most recent mic errors and recent mic events

This view is intended to quickly separate client capture problems from host decode/render problems.
Loading