mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 11:31:08 +00:00
Two opt-ins on a new Audio screen, both ported from Bannerlator's gamescope runtime where they are proven with voice in Steam's own tester. DirectAudio replaces the audio driver inside the games the client launches - Wine's mmdevapi driver, glibc build - with one that talks to a helper on the Android side over a unix socket. The client keeps PulseAudio either way: it is a native Linux program with no other way to make a sound. The helper runs here because nothing inside the session can open Android's audio: a game is a glibc process in a rootfs that binds no /system, and the uid the helper runs under is what the recording permission is checked against. The microphone is its own opt-in. The helper opens the input stream only when asked and writes it to a pipe; PulseAudio's module-pipe-source turns that into a source the client sees as DirectAudioMic. The daemon makes the pipe and the helper waits for it - the two used to race, and the module fails on EEXIST. The Proton wrappers gain Bannerlator's bl_directaudio, which adds the driver's directory to WINEDLLPATH and names the driver in the prefix, and refuses on any Proton that is not Wine 11 rather than pair a driver with an interface it was not built against, which would be silence rather than an error. bl_game_cpus comes along in the same splice and is inert until BL_GAME_CPUS is set. The driver is staged into the runtime at every launch like the session scripts; the helper ships as libdirectaudiorelay.so beside the PulseAudio daemon. Both are the binaries Bannerlator carries, built by The412Banner/directaudio's relay workflow (linux-wine11 build against ValveSoftware/wine proton_11.0).
77 lines
4.1 KiB
XML
77 lines
4.1 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
<!-- Session logs go to Downloads so a failed run can be handed over as one folder. -->
|
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
<!-- The session keeps running while the app is not on screen: a foreground service holds the
|
|
process at perceptible priority, and a high-performance WiFi lock keeps a backgrounded
|
|
download from being throttled to nothing by the radio's power-save. -->
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
|
<uses-permission android:name="android.permission.VIBRATE" />
|
|
<!-- Ends background processes of another app that holds the Steam login. GameHub starts
|
|
itself with the phone via boot receivers and signs this client out seconds after every
|
|
login; a normal permission, and it cannot touch anything in the foreground. -->
|
|
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
|
|
<!-- The microphone for the Linux session, only when the user turns it on: the DirectAudio
|
|
relay helper opens the input stream under this uid, and PulseAudio exposes it to the
|
|
Steam client as DirectAudioMic. -->
|
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
|
|
<uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" />
|
|
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
|
|
|
|
<application
|
|
android:allowBackup="false"
|
|
android:icon="@mipmap/ic_launcher"
|
|
android:label="@string/app_name"
|
|
android:theme="@style/AppTheme"
|
|
android:hardwareAccelerated="true"
|
|
android:largeHeap="true"
|
|
android:extractNativeLibs="true">
|
|
|
|
<activity
|
|
android:name=".MainActivity"
|
|
android:exported="true"
|
|
android:screenOrientation="sensorLandscape">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.MAIN" />
|
|
<category android:name="android.intent.category.LAUNCHER" />
|
|
</intent-filter>
|
|
</activity>
|
|
|
|
<!--
|
|
A session keeps a Surface, a compositor thread and a proot tree alive; a configuration
|
|
change must not tear that down and rebuild it, so the activity handles them itself.
|
|
Landscape only: gamescope is told one output size when it starts.
|
|
|
|
Resizable, deliberately: a foldable opening or closing changes the window, and the
|
|
compositor re-fits the picture with bars. Declared non-resizable, the system keeps a
|
|
fixed-shape window instead and STRETCHES it onto the other panel — the app never sees a
|
|
size change, so nothing it does can help.
|
|
-->
|
|
<activity
|
|
android:name=".SessionActivity"
|
|
android:exported="false"
|
|
android:theme="@style/SessionTheme"
|
|
android:screenOrientation="sensorLandscape"
|
|
android:resizeableActivity="true"
|
|
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboard|keyboardHidden|navigation|uiMode|density" />
|
|
|
|
<!--
|
|
Owns the session — gamescope, the Steam client, audio — so it survives the activity
|
|
going away. Without it Android demotes the process as soon as the last visible
|
|
activity goes, and the low-memory killer reaps the guest: leaving Big Picture to
|
|
answer a message would come back to a dead Steam and a half-finished download.
|
|
-->
|
|
<service
|
|
android:name=".session.SessionService"
|
|
android:exported="false"
|
|
android:stopWithTask="false" />
|
|
</application>
|
|
</manifest>
|