How to: Run Wyoming Satellite and OpenWakeWord on Android

I did not manage to set the microphone and turn on the satellite. I will try again later.
@randomuser123 maybe you have time to look too.
I found that the wyoming sattelite GUI installer uses alsa-utils for the microphone, which, from what I found, does not work on the Lenovo TSV tablet.

The GUI most likely calls the scripts in the scripts directory. I think we should first ensure that they all work without the GUI and then check how the GUI is calling the scripts because the GUI is another point of failure and hides important information that could be crucial in finding the source of a problem.


Got another response from the Termux devs. They have provided test builds that do not require memfd: pulseaudio: disable memfd Ā· termux/termux-packages@0ae3a72 Ā· GitHub

Unfortunately, now Iā€™m getting this error on my old devices with kernel 3.10:

$ pactl load-module module-sles-source
Failure: Module initialization failed

On my newer devices with kernel 4.4 I only get this error when I donā€™t grant the microphone recording permission to Termux:API.

Iā€™ve been watching wyoming sattelite on my samsung tablet for a few days now. My finding is that it is quite stable but has a small problem. It periodically disconnects for a few seconds and then connects right back and happens to be disconnected from the server right when you you want to say a command and thatā€™s frustrating. I thought a local wake word would solve this problem and I tried to install openwakeword locally but I canā€™t solve the problem with tensor flow lite (tflite) for which I canā€™t find a compatible library. I canā€™t quite figure out if itā€™s not compatible with termux, with the too-new version of python3, or with the processor architecture. Regarding the architecture of the processor I donā€™t know what to say because it doesnā€™t work on either samsung or lenovo which have different architectures (aarch64 and armv71) and it doesnā€™t work on either. I also found that I should use an older version of Phyton3, version 3.7, but I have not been able to install such a version on termux. Maybe someone else has an idea to solve this problem.

Architecture-wise tflite-runtime is definitely available for armv7l and aarch64: tflite-runtime Ā· PyPI

But still I think these builds are not compatible with the Termux environment because itā€™s too different from standard Linux distros.
For now the most realistic way of getting this to work I think is using proot inside of Termux. Other people have managed to compile not just tflite, but the entire tensorflow module this way: Developing Tensorflow on Android Phone | by Chulayuth Asawaroengchai | Analytics Vidhya | Medium

termux:API is NOT availble in europe from the android store it seems, dunno about rest of world.
Only way was to f-droid install termux and in termux it self enter a command to install the termux:API

eitherway i got stuck on the recordingā€¦
the phone G-A70 does not asks for permssion of the mic and termux shuts down after 1 minute

I didnā€™t know that. I exclusively use F-Droid to install apps.
What you run and provide the output of termux-info?
Also, can you check in your system settings if the mic permission is already given? If it is not, you should be able to allow it manually through the system settings.
Then try again if recording works.

Works perfect on my Lenovo TSV, thanks for this!!!

I got 2 small questions (or maybe wishes? :slight_smile: )

  1. I installed termux-boot and create a script accordinly, but that does not seem to work. Did someone go that route already and has a few pointers?

  2. does anybody know if it would be somehow possible to use a different media-player for sound output? Background to this question: if my TSV is playing music, the announcement sounds as well as the potential answer from homeassistant is played mixed with the current music, if I could direct this to the mediaplayer entity that is playing music as well, it would hopefully mute music, say something, and resume?

Great to hear itā€™s working for you.

  1. Is the issue that the script doesnā€™t execute at all on boot or is the issue that the script doesnā€™t execute successfully? What exactly is the content of your script, does it have a shebang? Have you made the script executable yet (using chmod)? Can you add a command like touch test-file.txt into the line below the shebang of your script, reboot the device and then check if test-file.txt has been created by the script?

  2. Sending the audio to a specific media player so that it plays two things at the same time is probably going to be very difficult and not possible with a most players. Iā€™d suggest looking into the event-commands instead. You could specify a command to execute before the announcements and another command to execute after the announcement like this:

    --tts-start-command "command to execute before" \
    --tts-stop-command "command to execute after"
    

    Emulating a system-wide media keypress for play/pause using the input would seem like an easy solution, but I think this only works over adb (adb shell input keyevent 85), not in Termux directly. Although I have seen people connecting to the phone itself from Termux using adb over wifi, but it doesnā€™t seem trivial.
    Another idea that comes to mind is sending specific intents to the app via the built-in am (activity manager) command.
    Finally, if it is an app like Spotify, you can use curl to send a pause/play request to the API.
    Oh and maybe one last idea: I think there are proprietary apps primarily focused on kiosk mode that expose more sensors and functionality of the device to HomeAssistant. This way you might be able to put the necessary play/pause logic into an HA automation.

Hi all,

iā€™m tring to run wyoming Satellite on a zenfone laser with android 10(crDroid).

it exit with ā€œ<Signals.SIGSYS: 31>ā€

this is the complete otput:

~/wyoming-satellite $ script/run   --name 'Android Satellite'   --uri 'tcp://0.0.0.0:10700'   --mic-command 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - '   --snd-command ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -'   --awake-wav ./sounds/awake.wav   --done-wav ./sounds/done.wav   --timer-finished-wav ./sounds/timer_finished.wav   --timer-finished-wav-repeat 5 0.5   --debug
DEBUG:root:Namespace(mic_uri=None, mic_command='rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ', mic_command_rate=16000, mic_command_width=2, mic_command_channels=1, mic_command_samples_per_chunk=1024, mic_volume_multiplier=1.0, mic_noise_suppression=0, mic_auto_gain=0, mic_seconds_to_mute_after_awake_wav=0.5, mic_no_mute_during_awake_wav=False, mic_channel_index=None, snd_uri=None, snd_command=' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -', snd_command_rate=22050, snd_command_width=2, snd_command_channels=1, snd_volume_multiplier=1.0, wake_uri=None, wake_word_name=[], wake_command=None, wake_command_rate=16000, wake_command_width=2, wake_command_channels=1, wake_refractory_seconds=5.0, vad=False, vad_threshold=0.5, vad_trigger_level=1, vad_buffer_seconds=2, vad_wake_word_timeout=5.0, event_uri=None, startup_command=None, detect_command=None, detection_command=None, transcript_command=None, stt_start_command=None, stt_stop_command=None, synthesize_command=None, tts_start_command=None, tts_stop_command=None, tts_played_command=None, streaming_start_command=None, streaming_stop_command=None, error_command=None, connected_command=None, disconnected_command=None, timer_started_command=None, timer_updated_command=None, timer_cancelled_command=None, timer_finished_command=None, awake_wav='./sounds/awake.wav', done_wav='./sounds/done.wav', timer_finished_wav='./sounds/timer_finished.wav', timer_finished_wav_repeat=[5.0, 0.5], uri='tcp://0.0.0.0:10700', name='Android Satellite', area=None, no_zeroconf=False, zeroconf_name=None, zeroconf_host=None, debug_recording_dir=None, debug=True, log_format='%(levelname)s:%(name)s:%(message)s')
INFO:root:Ready
DEBUG:root:Detected IP: 192.168.44.101
DEBUG:root:Zeroconf discovery enabled (name=fd68be898a09, host=None)
DEBUG:root:Connecting to mic service: ['rec', '-r', '16000', '-c', '1', '-b', '16', '-e', 'signed-integer', '-t', 'raw', '--no-show-progress', '-']
DEBUG:root:Connecting to snd service: ['play', '-r', '22050', '-c', '1', '-b', '16', '-e', 'signed-integer', '-t', 'raw', '--no-show-progress', '-']
INFO:root:Connected to services
Traceback (most recent call last):
  File "/data/data/com.termux/files/home/wyoming-satellite/script/run", line 12, in <module>
    subprocess.check_call([context.env_exe, "-m", "wyoming_satellite"] + sys.argv[1:])
  File "/data/data/com.termux/files/usr/lib/python3.12/subprocess.py", line 413, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/data/data/com.termux/files/home/wyoming-satellite/.venv/bin/python3', '-m', 'wyoming_satellite', '--name', 'Android Satellite', '--uri', 'tcp://0.0.0.0:10700', '--mic-command', 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ', '--snd-command', ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -', '--awake-wav', './sounds/awake.wav', '--done-wav', './sounds/done.wav', '--timer-finished-wav', './sounds/timer_finished.wav', '--timer-finished-wav-repeat', '5', '0.5', '--debug']' died with <Signals.SIGSYS: 31>.

Someone have idea where to look for a solution?

Thanks,

Nicola

Exit code 31 means that a system call went wrong.

I know that some Zenfones are x86 rather than arm.
So maybe letā€™s start with checking for that by running
termux-info

Letā€™s also check if the mic/speaker access is working outside of wyoming satellite by running:
(Turn your volume down a bit first)

pactl load-module module-sles-source && rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - | play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -

This should play your mic straight to your speaker. Does this work for you?

thermux info report aarch64, and I can hear the mic through the speaker


~ $ termux-info
Termux Variables:
TERMUX_API_VERSION=0.50.1
TERMUX_APK_RELEASE=F_DROID
TERMUX_APP_PACKAGE_MANAGER=apt
TERMUX_APP_PID=5417
TERMUX_IS_DEBUGGABLE_BUILD=0
TERMUX_MAIN_PACKAGE_FORMAT=debian
TERMUX_VERSION=0.118.1
TERMUX__USER_ID=0
Packages CPU architecture:
aarch64
Subscribed repositories:
# sources.list
deb https://md.mirrors.hacktegic.com/termux/termux-main stable main
Updatable packages:
All packages up to date
termux-tools version:
1.44.1
Android version:
10
Kernel build information:
Linux localhost 3.10.108-ten #1 SMP PREEMPT Sun Dec 26 02:00:36 UTC 2021 aarch64 Android
Device manufacturer:
asus
Device model:
ASUS_Z00ED
LD Variables:
LD_LIBRARY_PATH=
LD_PRELOAD=/data/data/com.termux/files/usr/lib/libtermux-exec.so
Installed termux plugins:
com.termux.api versionCode:51
com.termux.boot versionCode:1000

Very odd. Does this also happen when you chain the loading of module-sles-source and script/run together, like so?

pactl load-module module-sles-source && script/run \
  --name 'Android Satellite' \
  --uri 'tcp://0.0.0.0:10700' \
  --mic-command 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ' \
  --snd-command 'play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -' \
  --awake-wav ./sounds/awake.wav \
  --done-wav ./sounds/done.wav \
  --timer-finished-wav ./sounds/timer_finished.wav \
  --timer-finished-wav-repeat 5 0.5 \
  --debug

This would ensure that the module hasnā€™t been unloaded before the script/run starts.

Regarding the memfd error, there has been some progress on the Termux-side and there are new test builds for pulseaudio that may fix the issues:

I just havenā€™t found the time to give it a try, but I reuploaded the test builds to this location, so that you can download them without having to log into Github:

So if anyone with the memfd error would like to give it a try, you can just run:

pkg remove pulseaudio
pkg remove pulseaudio-glib
pkg install wget
export ARCH="$(termux-info | grep -A 1 "CPU architecture:" | tail -1)"
wget "https://github.com/T-vK/pulseaudio-termux-no-memfd/releases/download/1.1.0/pulseaudio_17.0-2_${ARCH}.deb"
wget "https://github.com/T-vK/pulseaudio-termux-no-memfd/releases/download/1.1.0/pulseaudio-glib_17.0-2_${ARCH}.deb"
pkg install "./pulseaudio_17.0-2_${ARCH}.deb"
pkg install "./pulseaudio-glib_17.0-2_${ARCH}.deb"

Edit: So I got around to trying it myself now and instead of the memfd error I now get:

$ pactl load-module module-sles-source
Failure: Module initialization failed

Yes iā€™ve tried also chianing the modlue loading and the script.

May be the kernel version is to old or because is a custom ROM with a cutom kernel.

You know if there is a way to trace witch system call went wrong?

I was able to get pulseaudio working on a device without memfd :smile:

Check the latest updates on this issue:
https://github.com/termux/termux-packages/issues/21660

Thanks a ton for your work @randomuser123!

Hi there, it seems to be a really good idea for re-use old android devices!!!
I try to get it working on a Lenovo smart clock 2 which as an arm cpu but i cant launch the script you provided.

#!/bin/bash

pactl load-module module-sles-source

./script/run \
  --name 'Android Satellite' \
  --uri 'tcp://0.0.0.0:10700' \
  --mic-command 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ' \
  --snd-command ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -' \
  --awake-wav ./sounds/awake.wav \
  --done-wav ./sounds/done.wav \
  --timer-finished-wav ./sounds/timer_finished.wav \
  --timer-finished-wav-repeat 5 0.5 \
  --debug

and here is the result

~/wyoming-satellite $ ./runit.sh
17
DEBUG:root:Namespace(mic_uri=None, mic_command='rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ', mic_command_rate=16000, mic_command_width=2, mic_command_channels=1, mic_command_samples_per_chunk=1024, mic_volume_multiplier=1.0, mic_noise_suppression=0, mic_auto_gain=0, mic_seconds_to_mute_after_awake_wav=0.5, mic_no_mute_during_awake_wav=False, mic_channel_index=None, snd_uri=None, snd_command=' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -', snd_command_rate=22050, snd_command_width=2, snd_command_channels=1, snd_volume_multiplier=1.0, wake_uri=None, wake_word_name=[], wake_command=None, wake_command_rate=16000, wake_command_width=2, wake_command_channels=1, wake_refractory_seconds=5.0, vad=False, vad_threshold=0.5, vad_trigger_level=1, vad_buffer_seconds=2, vad_wake_word_timeout=5.0, event_uri=None, startup_command=None, detect_command=None, detection_command=None, transcript_command=None, stt_start_command=None, stt_stop_command=None, synthesize_command=None, tts_start_command=None, tts_stop_command=None, tts_played_command=None, streaming_start_command=None, streaming_stop_command=None, error_command=None, connected_command=None, disconnected_command=None, timer_started_command=None, timer_updated_command=None, timer_cancelled_command=None, timer_finished_command=None, awake_wav='./sounds/awake.wav', done_wav='./sounds/done.wav', timer_finished_wav='./sounds/timer_finished.wav', timer_finished_wav_repeat=[5.0, 0.5], uri='tcp://0.0.0.0:10700', name='Android Satellite', area=None, no_zeroconf=False, zeroconf_name=None, zeroconf_host=None, debug_recording_dir=None, debug=True, log_format='%(levelname)s:%(name)s:%(message)s')
INFO:root:Ready
DEBUG:root:Detected IP: 192.168.0.32
DEBUG:root:Zeroconf discovery enabled (name=4dbd7cb26e58, host=None)
DEBUG:root:Connecting to mic service: ['rec', '-r', '16000', '-c', '1', '-b', '16', '-e', 'signed-integer', '-t', 'raw', '--no-show-progress', '-']
DEBUG:root:Connecting to snd service: ['play', '-r', '22050', '-c', '1', '-b', '16', '-e', 'signed-integer', '-t', 'raw', '--no-show-progress', '-']
INFO:root:Connected to services
Traceback (most recent call last):
  File "/data/data/com.termux/files/home/wyoming-satellite/./script/run", line 12, in <module>
    subprocess.check_call([context.env_exe, "-m", "wyoming_satellite"] + sys.argv[1:])
  File "/data/data/com.termux/files/usr/lib/python3.12/subprocess.py", line 413, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/data/data/com.termux/files/home/wyoming-satellite/.venv/bin/python3', '-m', 'wyoming_satellite', '--name', 'Android Satellite', '--uri', 'tcp://0.0.0.0:10700', '--mic-command', 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ', '--snd-command', ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -', '--awake-wav', './sounds/awake.wav', '--done-wav', './sounds/done.wav', '--timer-finished-wav', './sounds/timer_finished.wav', '--timer-finished-wav-repeat', '5', '0.5', '--debug']' died with <Signals.SIGSYS: 31>.

when i try this command you provided rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - | play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - it works but with a faster voice when it played back.

here is a uname -a result
uname -a
Linux localhost 4.14.141+ #1 SMP PREEMPT Wed Jan 5 03:00:27 UTC 2022 armv7l Android
I use sshd from termux because its a very small screen

Thanks, I can confirm itā€™s working for me too now.

I updated the instructions in the first post to simplify the entire process.
I also added support for Termux:Boot, allowing Wyoming Satellite to automatically start when the device is powered on.

The new simplified instructions that should work on all devices are:

  • Install Termux (open source terminal emulator app)
  • Install Termux:API (necessary to get mic access)
  • (Optional) Install Termux:Boot and open it once (only required if you want Wyoming Satellite to autostart when your device restarts)
  • Open Termux and run:
    bash <(wget -qO- https://raw.githubusercontent.com/T-vK/wyoming-satellite-termux/refs/heads/main/install.sh)
    

For more information see: wyoming-satellite-termux

I tried and the installation looks to be working but in the 1st post you have some spaces in the url
ā€œwget -qO- https://raw.githubusercontent.com/T-vK/wyoming-satellite-termux/refs/ heads/main/install.sh | bashā€
Unfortunately i still have some problems when i try to launch the script with the subprocess.check_call

Traceback (most recent call last):
  File "/data/data/com.termux/files/home/wyoming-satellite/./script/run", line 12, in <module>
    subprocess.check_call([context.env_exe, "-m", "wyoming_satellite"] + sys.argv[1:])
  File "/data/data/com.termux/files/usr/lib/python3.12/subprocess.py", line 413, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/data/data/com.termux/files/home/wyoming-satellite/.venv/bin/python3', '-m', 'wyoming_satellite', '--name', 'Android Satellite', '--uri', 'tcp://0.0.0.0:10700', '--mic-command', 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ', '--snd-command', ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -', '--awake-wav', './sounds/awake.wav', '--done-wav', './sounds/done.wav', '--timer-finished-wav', './sounds/timer_finished.wav', '--timer-finished-wav-repeat', '5', '0.5', '--debug']' died with <Signals.SIGSYS: 31>.

i think im pretty close but i donā€™t know where to look at

Unfortunately I canā€™t reproduce this bug on any of my devices.

Maybe we can convince the subprocess to print a stack trace before it exits with signal SIGSYS 31.
Try editing ~/wyoming-satellite/wyoming_satellite/__main__.py.
At line ~38 , right before the line _LOGGER = logging.getLogger(), add the following lines:

import faulthandler
import signal

faulthandler.register(signal.SIGSYS)

Then try running it again.

And we can also try if strace can provide any useful information:

pactl load-module module-sles-source && \
strace -ff -o strace_output python3 ./script/run \
  --name 'Android Satellite' \
  --uri 'tcp://0.0.0.0:10700' \
  --mic-command 'rec -r 16000 -c 1 -b 16 -e signed-integer -t raw --no-show-progress - ' \
  --snd-command ' play -r 22050 -c 1 -b 16 -e signed-integer -t raw --no-show-progress -' \
  --awake-wav ./sounds/awake.wav \
  --done-wav ./sounds/done.wav \
  --timer-finished-wav ./sounds/timer_finished.wav \
  --timer-finished-wav-repeat 5 0.5 \
  --debug

Once it crashes, run cat ./strace_output to review the strace output.

Thanks for the notice regarding the broken URL in the first post. I fixed that now.