com.harryaskham.pulse · Kotlin · PulseAudio 17

PulseServer

Runs a PulseAudio 17 server as an Android app. Linux programs on the phone, such as those in Nix-on-Droid, play and record through it at 127.0.0.1:4713, and so can other machines on the same network. It routes audio between Android's outputs and microphones, Bluetooth devices, virtual devices and other PulseAudio servers, and keeps every route across restarts.

Use it on a trusted network only. The listener accepts anonymous PulseAudio clients on every IPv4 interface, so anyone who can reach the phone's port can play to it and record from any source it exposes, including microphones and captured app audio once you enable them.

Sources, routes and outputs

Sources, routes and outputs What PulseServer connects. Sources on the left: the phone's microphone and Bluetooth microphones when exposed, another app's playback after Android's capture consent, virtual sources, the monitor of any output, and sources on other PulseAudio servers through saved references. Outputs on the right: the direct hardware output, optional Android output profiles such as media, notification and alarm, Bluetooth outputs, combined outputs that play to several at once, virtual sinks, and sinks on other servers. Saved routes connect a source to an output, each with its own buffer, volume and channel setting, and are pinned so a missing endpoint makes a route wait rather than move to another speaker or microphone. phone · Bluetooth micwhen exposed an app's playbackAndroid capture consent virtual sourcevsource_<name> an output's monitor remote sourcesaved reference saved routesbuffer · volume · channelspinned to both ends hw_outputdirect hardware Android profilesmedia · notification · alarm … Bluetooth outputs combined output2–8 outputs in step remote sinksaved reference
Routes are saved, and pinned at both ends. If an endpoint disappears, its route waits for it to come back.

The app has Inputs, Outputs, Routing, Remote and Settings tabs. Each input and output is one row with mute, a default star and a volume slider; routes show as chips on the rows they connect. The Routing tab draws them as a graph: drag from an input to an output, or tap one then the other, to connect them.

Each route is a PulseAudio loopback with its own buffer (50 ms to 2 s, 100 ms by default), its own volume, and a channel setting: stereo, mono mix, left only, right only or swapped. Loopbacks are created with source_dont_move and sink_dont_move, so when a Bluetooth headset or a remote server goes away the route waits rather than switching to the phone's microphone or speaker. Named setups save every route plus the default input and output, and the first three appear as launcher shortcuts.

Virtual devices

  • Virtual sources (vsource_<name>) look like an ordinary microphone to recording programs. Routes feed them, and by default those routes only run while something is reading, so a Bluetooth headset is not held in call mode for nothing.
  • Combined outputs play to two to eight outputs at once and keep them in step.
  • Another app's playback becomes a temporary source after Android's own capture consent, on Android 10 and later.

Other PulseAudio servers

Listening to another machine's sink An example route from the README. To hear on the phone what another machine plays into one of its virtual sinks, a saved reference exposes that remote sink's monitor as a local source, and a saved route plays it to the phone's hardware output or a chosen Bluetooth output. No special remote-listening feature is involved, and changing the default output does not move this pinned route. remote sink's monitor local source reference saved route hw_output or Bluetooth

A remote server is saved with its name, address and port, and an optional 256-byte PulseAudio cookie kept in the app's private storage. Browsing it lists its sources and sinks; exposing one makes it a local source or sink that routes can use. Saved servers, references and routes never expire while a server is offline: the app retries with a back-off of up to 256 seconds and recreates the endpoints when it returns.

Android outputs

hw_output plays straight to Android's audio output. Optional profiles, off by default on a new install, ask Android for a particular kind of playback so its volume controls and policies apply:

SinkAndroid stream or usageWhat to expect
vsink_mediamusic streamMedia volume and output policy apply.
vsink_notificationnotification streamNotification volume, linked ring volume and Do Not Disturb depend on the phone.
vsink_alarmalarm streamAlarm volume and policy apply.
vsink_voicevoice-call streamDoes not itself start call mode.
vsink_assistantassistant usageA hint; often shares media volume.
vsink_gamegame usageNormally shares media volume.

Ducking lowers chosen outputs, such as music, to 10–70 % while something plays to others, such as speech, with adjustable fade-down, hold and fade-up times. It reacts to a stream playing, not to its loudness, so it never reads the audio, and a slider you move while ducked keeps your value.

Outside the app

Limits