We are running a GStreamer based pipeline inside balena including the hot-plugging of cameras. The container is based off balenalib and the hot-plugging part works fine with devices showing up inside the container.
GStreamer has the gst-device-monitor-1.0 -f command, which can list the current audio video devices connected as well as continuously listen on changes to the devices
The command uses the libgudev library (glib binding to libudev) to listen on udev device changes, which it then filters and acts upon.
Outside of a container this works perfectly fine. Whenever a camera is plugged in while gst-device-monitor-1.0 -f is running, it prints information about the device.
Inside the container running gst-device-monitor -f will correctly identify and analyse all currently connected devices, but it will not monitor devices as they are plugged in. Re-running it after plugging in new hardware will also work as expected.
Directly monitoring the udev events using udevadm monitor inside the container works fine.
This can be reproduced by building the following image:
Then run it as docker run --rm -ti --privileged -v /sys:/sys -e UDEV=1 gst-device-monitor-test:latest /bin/bash
Inside the container run gst-device-monitor -f and plug in some audio/video device such as a webcam.
I would like to know if there are any changes to the containers that might interfere with the libudev library and that might prevent the callbacks from being called when a device is plugged in?
It is not clear if you are running your containers on your developer machine OS or on a BalenaOS device (from your command-line with docker, I lean towards the dev machine side).
The UDEV=1 should work in a Balena project (run with the same command on you HostOS on your target device, replacing docker with balena).
If you are running on your computer, we don’t have guidance on how to use UDEV on Docker.
I will try to reproduce your behavior on one of my device to see if I am missing something.
I tried this on my device and succeed to reproduce your problem.
It turns out that you probably should install udev and start the service on your container.
I could do it with your example C code and following Dockerfile
FROM debian:bullseye
RUN apt-get update &&\
apt-get install -y build-essential libudev-dev udev
WORKDIR /test
COPY code.c .
RUN gcc -o code code.c -ludev
CMD service udev restart && ./code
I’ve patched the udev service script in the container and I get events in the container.
However, events are now continuously spamming. My camera is constantly being reported as attached and detached:
...
03.10.22 14:04:34 (+0200) dcd 0:57:32.357796800 97 0x557da72f00 INFO deepcore-daemon deepcore-daemon/src/devices.rs:115:deepcore_daemon::devices: Camera detached RealsenseD415-928222061521
03.10.22 14:04:34 (+0200) dcd 0:57:32.585963520 97 0x557da72f00 INFO deepcore-daemon deepcore-daemon/src/devices.rs:100:deepcore_daemon::devices: Camera attached RealsenseD415-928222061521
03.10.22 14:04:35 (+0200) dcd 0:57:33.711682944 97 0x557da72f00 INFO deepcore-daemon deepcore-daemon/src/devices.rs:115:deepcore_daemon::devices: Camera detached RealsenseD415-928222061521
03.10.22 14:04:35 (+0200) dcd 0:57:33.962839616 97 0x557da72f00 INFO deepcore-daemon deepcore-daemon/src/devices.rs:100:deepcore_daemon::devices: Camera attached RealsenseD415-928222061521
03.10.22 14:04:35 (+0200) dcd 0:57:34.049533024 97 0x557da72f00 INFO deepcore-daemon deepcore-daemon/src/devices.rs:115:deepcore_daemon::devices: Camera detached RealsenseD415-928222061521
...
@wolvi-lataniere Can you test the C example code in a balenalib based container that runs with UDEV=1 ? I just wonder if there is a conflict between udev and udevd when applying your suggestions to a balenalib image running udevd.
I get the signals as expected when events are occurring.
I don’t have access to a USB camera at the moment to test on a RaspberryPi with Balena OS, but I don’t think it would do any major difference on the behavior.
The problem lies with the difference between -ubuntu:focal and my -ubuntu:bionic, which we run on the Jetson devices (TX2, Nano)
Your container example works fine with focal, and exhibits my problems of udev not supported on bionic.
I will see if a backport version of udev is available and may help here.
Hi,
Thanks for the feedback.
About Focal vs Bionic, I would recommend going for the newest version whenever possible as end of life can come pretty quickly considering a standard development/deployment cycle.
As you can see here Bionic will stop receiving software update in the next 12 months. For newer development I would recommend using the latest available LTS (Currently for Ubuntu it is Jammy) to spare you some maintenance work in the near future.
I will have a look at a build with bionic to see if I can figure it out.
One more clarification on our problem: I built a container based on Bionic and then installed udev from Focal. That get’s me around the udev does not support problem.
On my laptop with the above example code and with focal I see events coming in.
I need to check again on our device.
I looked into it and the fix I proposed doesn’t work on bionic.
I managed to get the code working without starting the udev service first, but I had to use network_mode: "host" in order to allow your udev_monitor_new_from_netlink(udev, "udev"); function to grab the host netlink.
But after restarting the udev service we are stuck in a constant loop of devices being registered and unregistered. That holds for the solution by @bversluijs as well as what @wolvi-lataniere suggested.
Still stuck at this I’m afraid.
It is not enough to make the UDEV restart from within docker-compose.yml cmd’s.
This tricked me also!
You have to add the “restart” cmd into a separate start.sh file that will execute prior to your container-startup.
Inside docker-compose.yml of your service at question, add the following:
COPY start.sh /opt/
# We are running our entrypoint commands through the start.sh script
CMD ["bash", "/opt/start.sh"]
(i.e. in our case the root folder is /opt (in your case it might be a different folder)…
And the start.sh script looks as follows:
#!/bin/bash
if which udevadm >/dev/null; then
echo "Restarting UDEV Service to enable hotpluging"
set +e # Disable exit on error
service udev restart
set -e # Re-enable exit on error
echo "UDEV Service restarted"
fi
value="yarn start:docker"
echo "Starting MyContainer Service"
exec $value