Saturday, 27 July 2024

USB HID gadget with Raspberry Pi OS

For some reason the wifi on my PiKVM installation on my Raspberry Pi Zero 2 W described in my previous post has become unstable. Also keeping underlying Arch Linux updated with my ansible update script is a challenge due to PiKVM keeps file system read-only by default. To solve both issues I moved USB HID gadget functionality to Raspberry Pi OS. Started with flashing latest Bookworm 64 bit Lite version to my Raspberry Pi Zero 2 W. I broadly used the configuration in this post.

jordana@pi02w2:~ $ sudo nano /boot/firmware/config.txt
dtoverlay=dwc2,dr_mode=peripheral
jordana@pi02w:~ $ sudo nano /boot/firmware/cmdline.txt
modules-load=dwc2,g_hid rootwait
jordana@pi02w2:~ $ sudo nano /etc/modules
dwc2
libcomposite
jordana@pi02w2:~ $ sudo nano /usr/bin/hid_keyboard_setup.sh
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p g1
cd g1
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB
mkdir -p strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "Raspberry Pi" > strings/0x409/manufacturer
echo "Pi Zero Keyboard" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: HID Keyboard" > configs/c.1/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
echo -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
ls /sys/class/udc > UDC
jordana@pi02w2:~ $ sudo chmod +x /usr/bin/hid_keyboard_setup.sh
jordana@pi02w2:~ $ sudo nano /etc/rc.local
/usr/bin/hid_keyboard_setup.sh

I added the script with support for 0-9 numeric keys, arrow keys and mapped Enter and Esc for remotely driving UI on a STB that support USB HID keyboard to my git repository here.

UPDATE

Configuration above have been updated that supports Raspberry Pi 4 also with its OTG capability on its USB-C port. In order to connect Raspberry Pi 4 to a low power USB 2.0 keyboard port I had to provide power via GPIO. Pimoroni has a nice solution for this here

Monday, 22 July 2024

Low latency WebRTC streaming from HDMI source via zerotier

In order to achieve low latency WebRTC streaming over the Internet I found MediaMTX.

I installed it on my Raspberry Pi 4 on latest 64 bit Bookworm image as follows.

jordana@pi4g:~ $ mkdir mediamtx && cd mediamtx
jordana@pi4g:~/mediamtx $ wget https://github.com/bluenviron/mediamtx/releases/download/v1.8.4/mediamtx_v1.8.4_linux_arm64v8.tar.gz
jordana@pi4g:~/mediamtx $ tar -xvzf mediamtx_v1.8.4_linux_arm64v8.tar.gz 
jordana@pi4g:~/mediamtx $ nano mediamtx.yml
webrtcIPsFromInterfaces: no
webrtcAdditionalHosts: [zerotier_IP_of_Raspberry]
paths:
  cam:
    runOnInit: ffmpeg -f v4l2 -pix_fmt yuv420p -s:v 1280x720 -i /dev/video0 -f alsa -i hw:3,0 -filter:v fps=50 -c:v libx264 -c:a libopus -async 50 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
    runOnInitRestart: yes
jordana@pi4g:~/mediamtx $ ./mediamtx 

In order to find out the audio configuration hw:[card],[device] of the USB capture device I used arecord tool.

jordana@pi4g:~ $ arecord -l
**** List of CAPTURE Hardware Devices ****
card 3: MS2109 [MS2109], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0

To stream WebRTC from the other side of a zerotier connection I simply had to use a browser to load this URL.

http://zerotier_IP_of_Raspberry:8889/cam/

I had to use Chromium from Crostini to have a stream within a minute but once it is up&running the latency and quality is fantastic!

UPDATE

After a few days of working stable the need arose to make a service out of it as described in the MediaMTX GitHub.

jordana@pi4g:~/mediamtx $ sudo mv mediamtx /usr/local/bin/
jordana@pi4g:~/mediamtx $ sudo mv mediamtx.yml /usr/local/etc/
jordana@pi4g:~ $ sudo tee /etc/systemd/system/mediamtx.service >/dev/null << EOF
[Unit]
Wants=network.target
[Service]
ExecStart=/usr/local/bin/mediamtx /usr/local/etc/mediamtx.yml
[Install]
WantedBy=multi-user.target
EOF
jordana@pi4g:~ $ sudo systemctl daemon-reload
jordana@pi4g:~ $ sudo systemctl enable mediamtx
jordana@pi4g:~ $ sudo systemctl start mediamtx

Sunday, 14 July 2024

Finally playing with OBS an Pi KVM

I have heard about OBS several times before and I always wanted to try it. Recently I got asked by a developer to use OBS to provide remote access to an HDMI signal. I am a happy user of a cheap HDMI to USB capture card for a long time but so far I have only used it with Camera application running directly on Android or ChromeOS host where it was connected to. Fortunately OBS is supported by Raspberry Pi OS:

jordana@pi4g:~ $ apt search obs-studio
Sorting... Done
Full Text Search... Done
obs-studio/stable,now 29.0.2+dfsg-1+b1 arm64
  recorder and streamer for live video content

Here came the first issue by launching OBS I bumped into this error message:

It did not take too long to find that we need an environmental variable to set on Raspberry Pi 4 and Raspberry Pi 5 so from command line it looks like this:

jordana@pi4g:~ $ LIBGL_ALWAYS_SOFTWARE=1 obs
jordana@pi5g:~ $ MESA_GL_VERSION_OVERRIDE=3.3 obs

I have bought a new HDMI capture card for this excersize from Amazon. To make it work, I only had to add it as a v4l2 video capture device as source and restart OBS. As during first time install OBS asked for a stream key I created an account on Twitch to get a stream key. Streaming via Twitch was also working more or less - althought I had to reduce framerate and resolution and it remained barely watchable. I guess the Raspberry Pi 4 with software only encoding is struggling with Motion JPEG source from the HDMI capture card. The delay was also excessive for the use case I had hence ultimately I will not use OBS let alone streaming but it was definitely a nice encounter with OBS.

Another ask from the developer was how to extend IR remote control over the network. While I am still playing with the idea there was a nice workaround possible to extend USB keyboard over the network. After some research, it turned out that OTG functionality in Linux have a usb gadget mode that does exactly what I need here. After a couple of unsuccessful tries I found this DIY PiKVM v2 in this github repository. As I have a couple of spare pi02w that supports OTG functionality and I only needed keyboard functionality I flashed the corresponding image on an SD card and added wifi password to pikvm.txt in PIBOOT partition. Please note that I did not have to escape \ in my Wifi password as in the guide for whatever the reason is. The nice feature of a pi02w is that its power consumption during light use largely remains below 5V/500mA standard USB 2 specification hence it can be a direct substitution of a USB keyboard where pi02w is only powered via the USB port itself. I have also added remote Tailscale access for this Pi KVM project that is beautifully integrated on my Chromebook with an Android app as such can nicely co-exist with Zerotier installation in the Linux subsystem Crostini.

UPDATE

After a while I started to have instable wifi connection to my Pi Zero 2 W. I added the following one line pikvm.txt to PIBOOT:

ENABLE_OTG_SERIAL=1

This way I could connect from a Pi 4 as follows:

jordana@pi4g:~ $ minicom --device /dev/ttyACM0 --baudrate 115200

Adding one line to this config file resolved my connection issue:

[root@pikvm ~]# vi /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
network={
    ssid="broadcom"
    psk=*************
    key_mgmt=WPA-PSK-SHA256
}