Skip to content

Allow simultaneous passthrough for multiple devices#23

Merged
gdzx merged 25 commits intogdzx:masterfrom
CameronMParker:feature-multi-mic
Jun 1, 2025
Merged

Allow simultaneous passthrough for multiple devices#23
gdzx merged 25 commits intogdzx:masterfrom
CameronMParker:feature-multi-mic

Conversation

@CameronMParker
Copy link
Copy Markdown
Contributor

This PR would allow Audio Source to forward multiple Android devices to PulseAudio.

Context

Because each invocation of audiosource uses the same socket, device, and pipe names, it is only possible to connect one Android device to PulseAudio. This PR, however, adds both a random UUID to the default device name and allows the user to supply an optional device name. Both of these solutions prevent socket naming collisions and allow you to run multiple audiosource jobs at the same time.

Example

A user could connect a Galaxy device and a Pixel device and select between the two with pactl set-default-source.

$ ./audiosource run -s GALAXY_SERIAL -n galaxy 1> /dev/null &  // running each command in the background
$ ./audiosource run -s PIXEL_SERIAL -n pixel 1> /dev/null &

$ pactl set-default-source galaxy  // if you want to use the galaxy
$ pactl set-default-source pixel  // if you want to use the pixel

A user could also bounce the inputs down into one PulseAudio sink so they could monitor or record from multiple devices at the same time.

$ pactl load-module module-null-sink sink_name=devices
$ pactl load-module module-loopback source=galaxy sink=devices
$ pactl load-module module-loopback source=pixel sink=devices
$ pactl set-default-source devices.monitor

Changes

  • The default device name is now suffixed by a random UUID.
  • The variables associated with the pipe, socket, and device have been consolidated.
  • The install and run commands have been updated to use optional flags instead of positional flags.
  • The volume command now requires a device name.
  • Documentation has been updated to reflect the new flag changes as well as highlight multiple device support.

Copy link
Copy Markdown
Owner

@gdzx gdzx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this PR. That's an interesting use-case. I added a few comments. This will also fix #22.

Comment thread audiosource Outdated
Comment on lines +169 to +171
install [-s SERIAL] Install Audio Source to Android device (default: debug)
run [-s SERIAL] [-n NAME] Run Audio Source and start forwarding
volume NAME LEVEL Set volume to LEVEL (for example, 250%)
Copy link
Copy Markdown
Owner

@gdzx gdzx May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flag should be on the root command instead of being repeated on all the subcommands (like adb [-s serial] <command>. But I think it's better to remove it entirely because it is possible to set it with ANDROID_SERIAL=whatever which is functionally equivalent to passing the -s option to adb, so this is just a matter of documenting that it works and generating a name from it.

Comment thread audiosource Outdated
AUDIOSOURCE_NAME=${AUDIOSOURCE_NAME:-android}
AUDIOSOURCE_PIPE=${AUDIOSOURCE_PIPE:-/tmp/audiosource}
AUDIOSOURCE_SOCKET=${AUDIOSOURCE_SOCKET:-audiosource}
AUDIOSOURCE_NAME=${AUDIOSOURCE_NAME:-audiosource$(uuidgen)}
Copy link
Copy Markdown
Owner

@gdzx gdzx May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name should be stable, because if you adjust the volume or other settings in pavucontrol, they would be lost if you launch it again. One way of doing that would be deriving a short identifier from the sha256 sum of the serial (e.g. audiosource-82ab264).

Comment thread README.md Outdated
Comment on lines +59 to +60
$ ./audiosource run -s SERIAL_ONE 1> /dev/null &
$ ./audiosource run -s SERIAL_TWO 1> /dev/null &
Copy link
Copy Markdown
Owner

@gdzx gdzx May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$ ./audiosource run -s SERIAL_ONE 1> /dev/null &
$ ./audiosource run -s SERIAL_TWO 1> /dev/null &
$ ANDROID_SERIAL=serial1 ./audiosource run 1> /dev/null &
$ ANDROID_SERIAL=serial2 ./audiosource run 1> /dev/null &

Comment thread audiosource Outdated
@@ -141,33 +150,31 @@ run() {

echo '[+] Forwarding audio'
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of source could be printed here.

@CameronMParker
Copy link
Copy Markdown
Contributor Author

I've updated the code according to your feedback. Let me know if there are still any changes that need to be made.

CameronMParker and others added 2 commits May 29, 2025 12:34
- Remove -n option (name can be set with $AUDIOSOURCE_NAME).
- Export $ANDROID_SERIAL and remove adb $opts.
- Add contextual usage errors.
@gdzx
Copy link
Copy Markdown
Owner

gdzx commented Jun 1, 2025

Hi @CameronMParker,

Thank you for your changes. I added a few of my own. Could you check that everything works properly for your use case?

Best regards,

@CameronMParker
Copy link
Copy Markdown
Contributor Author

Everything works great! I encountered an error while running ./audiosource run with a single device but my previous commit seems to fix the problem.

@gdzx
Copy link
Copy Markdown
Owner

gdzx commented Jun 1, 2025

What was the bug? I cannot reproduce.

Comment thread audiosource Outdated
pactl load-module module-pipe-source source_name="$AUDIOSOURCE_NAME" channels=1 format=s16 rate=44100 file="/tmp/$AUDIOSOURCE_NAME"

echo "[+] Waiting for device $ANDROID_SERIAL"
echo "[+] Waiting for device $AUDIOSOURCE_NAME"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be $ANDROID_SERIAL as it may not be obvious which device you are waiting for based on the source name if for instance you left the serial set in the environment.

@CameronMParker
Copy link
Copy Markdown
Contributor Author

If you're running the default ./audiosource run command with just one device, you will get an error saying error: device '' not found. Moving the export ANDROID_SERIAL="$serial" line to inside the case statement seems to fix this. However, another error gets thrown once you get to line 123: ./audiosource run: line 123: ANDROID_SERIAL: unbound variable.

@gdzx
Copy link
Copy Markdown
Owner

gdzx commented Jun 1, 2025

Weird, I have a completely different behavior (with adb here but it also works as expected with the script):

$ ANDROID_SERIAL='' adb shell  # no device
adb: no devices/emulators found

$ ANDROID_SERIAL='' adb shell  # single device
android:/ $

$ ANDROID_SERIAL='foo' adb shell
adb: device 'foo' not found

Can you send me the output of adb version?

@CameronMParker
Copy link
Copy Markdown
Contributor Author

$ adb version
Android Debug Bridge version 1.0.41
Version 35.0.2-android-tools
Installed as /usr/bin/adb
Running on Linux 6.14.9-arch1-1 (x86_64)

Comment thread audiosource Outdated

shift $((OPTIND-1))

export ANDROID_SERIAL="$serial"
Copy link
Copy Markdown
Owner

@gdzx gdzx Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Export conditionally like this?

ANDROID_SERIAL="$serial"
# Empty ANDROID_SERIAL seems to cause the following issue with ADB: `error: device '' not found`.
[ -n "$ANDROID_SERIAL" ] && export ANDROID_SERIAL

@gdzx
Copy link
Copy Markdown
Owner

gdzx commented Jun 1, 2025

$ adb version
Android Debug Bridge version 1.0.41
Version 35.0.2-android-tools
Installed as /usr/bin/adb
Running on Linux 6.14.9-arch1-1 (x86_64)

Same as you except the kernel version 🤷

@CameronMParker
Copy link
Copy Markdown
Contributor Author

Moving the initial declaration of $ANDROID_SERIAL to file scope seems to fix the issue.

@gdzx
Copy link
Copy Markdown
Owner

gdzx commented Jun 1, 2025

I changed to export ANDROID_SERIAL if it is not empty (with a comment because this is likely to be forgotten). If that works for you, I will merge.

@CameronMParker
Copy link
Copy Markdown
Contributor Author

Everything seems to be fine now.

@gdzx gdzx merged commit 002982c into gdzx:master Jun 1, 2025
@CameronMParker CameronMParker deleted the feature-multi-mic branch June 1, 2025 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants