killer(){ echo"Am I running?" if [ -z "$DEVICE" ]; thenprintf"Please specify a device.\n" && exit 1; fi if [ ! -e "/var/tmp/camera/${DEVICE/"/dev/"/"dev-"}" ]; thenprintf"Device ${DEVICE/"/dev/"/"dev-"} not found.\n" && exit 1; fi# [1] echo"Am I running?" _int=0 vars="$GSTLAUNCH_PID$CAPTURE_STREAM${DEFAULT_SOURCE}${ECANCEL_ID}${SINK_ID}$MODE$ADB$ADB_FLAGS$PORT"
for var in $(sed 's/;/\n/g'"/var/tmp/camera/${DEVICE/"/dev/"/"dev-"}") # [2] do echo"Am I running?" echo$_int vars[int]=var ((++_int)) done echo"Am I running?" rm"${DEVICE/"/dev/"/"dev-"}" kill$GSTLAUNCH_PID > /dev/null 2>&1 || echo"" if [ $CAPTURE_STREAM = a -o $CAPTURE_STREAM = av ]; then pactl set-default-source ${DEFAULT_SOURCE} pactl unload-module ${ECANCEL_ID} pactl unload-module ${SINK_ID} fi
# Remove the port forwarding, to avoid issues on the next run if [ $MODE = adb ]; then"$ADB"$ADB_FLAGS forward --remove tcp:$PORT; fi
printf"Disconnected from IP Webcam. Have a nice day!\n" }
Save Streamer Variable
1 2 3
if [ ! -d "/var/tmp/camera" ]; thenmkdir -p "/var/tmp/camera"; fi
that is what [3] echo, when it read by [2], the empty value part (;;;;) will be substituted for four spaces, which means to bash is a single splitter, causing values after that are assigned to the wrong keys.
So I use source later.
Audio Streaming
PulseAudio creates a Source named.monitor for sinking devices. But it won’t show up as an input on the KDE user interface. By using module-remap-source we can create a virtual input device that remaps the null-sink to a source.
But I don’t set it as default because of its latency.
1 2 3 4 5 6 7 8 9 10 11 12 13
if [ -z $SINK_ID ] ; then SINK_ID=$(pactl load-module module-null-sink \ sink_name="$SINK_NAME" \ $PA_AUDIO_CAPS \ sink_properties="device.description='IPWebCam.AudioSink'") # [1]
❯ camera --use-wifi 192.168.1.150 -d /dev/video1 IP Webcam audio is streaming through pulseaudio sink 'ipwebcam'. IP Webcam video is streaming through v4l2loopback device /dev/video1. You can now open your videochat app. ❯ camera --use-wifi 192.168.1.150 -d /dev/video2 IP Webcam audio is streaming through pulseaudio sink 'ipwebcam'. IP Webcam video is streaming through v4l2loopback device /dev/video2. You can now open your videochat app. ❯ camera --use-wifi 192.168.1.150 -d /dev/video3 IP Webcam audio is streaming through pulseaudio sink 'ipwebcam'. IP Webcam video is streaming through v4l2loopback device /dev/video3. You can now open your videochat app. ❯ camera --use-wifi 192.168.1.150 -d /dev/video1 IP Webcam audio is streaming through pulseaudio sink 'ipwebcam'. IP Webcam video is streaming through v4l2loopback device /dev/video1. You can now open your videochat app. ❯ camera --use-wifi 192.168.1.150 -d /dev/video1 -k Cleaning session(s): /var/tmp/camera/dev-video1 /var/tmp/camera/dev-video1_1 Disconnected from IP Webcam. Have a nice day! ❯ camera --use-wifi 192.168.1.150 -d /dev/video3 -k Cleaning session(s): /var/tmp/camera/dev-video3 Disconnected from IP Webcam. Have a nice day! ❯ camera --use-wifi 192.168.1.150 -d /dev/video2 -k Cleaning session(s): /var/tmp/camera/dev-video2 Disconnected from IP Webcam. Have a nice day!
However, some of these flip methods do not seem to work. In particular, those which change the picture size, such as clockwise or counterclockwise. *-flip and rotate-180 do work, though.
Execute the process in ExecStart, Execute the process in ExecStop once the main process is exited with 0.
I faced the service stop right after the start because of this.
Add RemainAfterExit=yes to prevent ExecStop from being executed after ExecStart exit, or use forking.
oneshot can have many Exec but simple don’t. oneshots were executed one by one, simples are parallel.
They both treat commands as the main process.
forking
Same as simple, but treats command as sub-process, ExecStop is only executed if every sub-process in ExecStart is exited with 0.
Howdy Integration
Because always turning on the camera generates a lot of heat, which led my phone to stop charging and drain the battery until it powers off, so I edit the pam.py to start streaming only when Howdy starts, I made this simple editing hard at first because I didn’t notice that pam.py is running on Python 2.
It seems like polkit and sddm don’t allow messages to print directly but via pam conversation, otherwise, it will fail with like Unknown Messages error.[1]
Start and Stop the Camera
pam.py
1 2 3 4 5 6 7 8 9 10 11
defcameraSwitch(pamh, arg): try: if arg == "on": pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Camera is Switching on.")) pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, subprocess.check_output("/usr/bin/camera -v -d /dev/video3 --use-wifi 192.168.1.150", shell=True, stderr=subprocess.STDOUT))) if arg == "off": pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Camera is Switching off.")) pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, subprocess.check_output("camera -k -d /dev/video3", shell=True, stderr=subprocess.STDOUT))) except subprocess.CalledProcessError: pamh.conversation(pamh.Message(pamh.PAM_ERROR_MSG, "Failure, camera switch {} fail.".format(arg))) return pamh.PAM_SYSTEM_ERR
Add Retries
compare.py
Add retries, because the camera won’t work in the meantime it connects.
1 2 3 4 5 6 7 8 9 10
ret, frame = self.internal.read() i = 0 whilenot ret and i<=5: if i == 5: #print(_("Failed to read camera specified in the 'device_path' config option, aborting")) # [1] sys.exit(1) sleep(i*.5) ret, frame = self.internal.read()
i+=1
pam.py
1 2 3 4 5 6 7 8 9
# Run compare as python3 subprocess to circumvent python version and import issues status = subprocess.call(["/usr/bin/python3", os.path.dirname(os.path.abspath(__file__)) + "/compare.py", pamh.get_user()])
i=0 while i<=5and status != 0: #pamh.conversation(pamh.Message(pamh.PAM_TEXT_INFO, "Retrying...")) status = subprocess.call(["/usr/bin/python3", os.path.dirname(os.path.abspath(__file__)) + "/compare.py", pamh.get_user()]) i+=1 if i == 5and status != 0: cameraSwitch(pamh, "off")
Hoi
I wrapped up the configurations and upload them here. Hoi.
I may make a PKGBUILD for AUR if I still have interests later.