Index: multimedia/webcamd/files/webcamd.in =================================================================== --- multimedia/webcamd/files/webcamd.in (revision 361799) +++ multimedia/webcamd/files/webcamd.in (working copy) @@ -1,45 +1,542 @@ #!/bin/sh -# $FreeBSD$ +# $FreeBSD: head/multimedia/webcamd/files/webcamd.in 353901 2014-05-12 22:01:10Z nox $ # # PROVIDE: webcamd -# REQUIRE: DAEMON +# REQUIRE: DAEMON LOGIN +# KEYWORD: shutdown # -# Add the following line to /etc/rc.conf[.local] to enable webcamd: +# ================================================================ +# Webcamd is enabled by adding the following line to /etc/rc.conf: +# ================================================================ # # webcamd_enable="YES" # -# Optional: -# webcamd_flags="-m v4l2-dev.vflip=1" +# ================================================================ +# By default webcamd instances are invoked by the devd(8) system +# daemon. You do not normally need to do any extra configuraion. +# ================================================================ +# +# ================================================================ +# Webcamd flags can be set in general using this variable: +# ================================================================ +# # webcamd_flags="-m v4l2-dev.hflip=1" +# +# ================================================================ +# If devd is not working (devd_enable="NO"), then you must tell +# webcamd which devices you have explicitly with "_device_N_name" +# as printed out when running the command "usbconfig". +# +# Index "N" is a sequentially increasing number starting from "0". +# e.g. 0,1,2,3 etc... You must not skip any index numbers. +# ================================================================ +# +# webcamd_device_0_name="Acer Crystal Eye webcam SuYin" +# +# ================================================================ +# If you have multiple identical devices, then they can also be +# distinguished by serial number, as found with these commands: +# $ usbconfig && usbconfig dump_string 0x03 +# This setting is only needed when "device_0_name"="device_1_name" +# AND you need to set *different* flags for each inividual device. +# ================================================================ +# +# webcamd_device_0_serial="CN0314-SN30-OV03-VA-R02.03.02" +# +# ================================================================ +# You may set individual flags on a per USB device basis with +# "_device_N_flags", along with a matching "_device_N_name" and +# "_device_N_serial" as above. This works for devd invokations too. +# ================================================================ # +# webcamd_device_0_flags="-L 127.0.0.1:5100:-1" +# +# ================================================================ +# Or can specify manually, each seperate custom webcamd instances +# with this index being seperate from the auto-name finding. +# This is useful when you cannot specify by name and serial number +# and wish to specify by hard-coded USB device number instead. +# Or when you need to start a vtuner client instance ("-D" option). +# ================================================================ +# +# webcamd_custom_flags_0="-D 127.0.0.1:5100:-1" +# webcamd_custom_flags_1="-d ugen2.2 127.0.0.1:5100:-1" +# +# ================================================================ +# Additional Webcamd flags: +# ================================================================ +# +# webcamd_startup_delay= +# webcamd_user= +# webcamd_group= +# -webcamd_enable=${webcamd_enable-"NO"} -hald_enable=${hald_enable-"NO"} - . /etc/rc.subr name=webcamd rcvar=webcamd_enable -iface=${3-0} +load_rc_config $name + +: ${webcamd_enable:=NO} +: ${hald_enable:=NO} + +: ${webcamd_user=webcamd} +: ${webcamd_group=webcamd} +: ${webcamd_startup_delay=1} +: ${webcamd_devd_starts_custom=YES} + +# If invoked automatically by devd, we receive additional arguments +devd_device=${2} +devd_interface=${3-0} + command=%%PREFIX%%/sbin/webcamd -command_args="-B -U webcamd -G webcamd" +command_args="-B -U ${webcamd_user} -G ${webcamd_group}" -start_precmd="${name}_prestart" +start_cmd="${name}_start" +stop_cmd="${name}_stop" +status_cmd="${name}_status" -webcamd_prestart() +webcamd_pids() { + pids=$(pgrep -d ' ' $name) + pids=${pids% } + printf "${pids}" +} + +webcamd_set_vars() +{ + # Whether or not we will start all custom instances, or just the vtuner client ones ("-D") + if checkyesno devd_enable && checkyesno webcamd_devd_starts_custom ; then + devd_starts_custom="true" + else + unset devd_starts_custom + fi + + # Whether or not we will use the 'hald' service if checkyesno hald_enable ; then - command_args="$command_args -H" + command_args="$command_args -H" fi + + # Whether or not we start all of our USB devices from this script, and can report certain errors + if checkyesno devd_enable && [ ! "$rc_force" ]; then + unset not_devd + else + not_devd="true" + fi } -pidfile="/var/run/webcamd.*.$iface.pid" +webcamd_start() +{ + # Set configuration variables that we need for later on + webcamd_set_vars; -load_rc_config $name + # If this rc.d script was invoked by devd + if [ "$devd_device" ]; then + # Then start the device ugenX.X, as provied in the argv $2, $3 + webcamd_start_devd; -if [ $# -gt 1 ]; then - pidfile="webcamd.dummy" - command_args="$command_args -d $2 -i $iface" - # Only run the rc command if the appropriate arguments are specified: - run_rc_command $1 -fi + else + # Count the number of webcamd instances we will start + webcamd_count_instances; + + if [ "$num_instances_remaining" -gt 0 ]; then + echo "Starting ${name}." + + # If custom instance config lines were found + if [ "$webcamd_custom_flags_0" ]; then + + if [ "$devd_starts_custom" ]; then + # Start only the vtuner client custom instances (the others are started by devd) + webcamd_start_by_vtuner_client_flags; + else + # Start each specified custom instances + webcamd_start_by_custom_flags; + fi + fi + + if [ "$num_found_by_name_serial" -gt "0" ]; then + # If we found any devices matching a specified USB name, USB serial number, we must start them + webcamd_start_by_usb_name_serial; + fi + + # Check that webcamd started up (didn't quit unexpectedly or error out) + webcamd_check_started; + + # Skip this error message if we are starting our devices from devd + elif [ "$not_devd" ]; then + + # Display an appropriate error message to explain why webcamd could not be started + if [ "$device_names" ]; then + warn "failed to start ${name}." + echo "No connected devices found of type: ${device_names#, }." + return 1 + + else + warn "failed to start ${name}." + echo "webcamd settings need to be configured in /etc/rc.conf." + echo "See %%PREFIX%%/etc/rc.d/${name} for more info." + return 1 + fi + fi + + fi +} + +webcamd_find_devd_flags_by_custom_flags() +{ + # Find matching flags in any custom instances + n=0 + while [ "$n" -lt "100" ] + do + custom_flags=$(eval "echo \$webcamd_custom_flags_${n}") + if [ "$custom_flags" ]; then + + # GREP the devd USB device number against this line of custom instance flags + d_flag_match=$(echo "$custom_flags" | grep -o "\-d *[[:alpha:]]*${devd_device#ugen}") + if [ "$d_flag_match" ]; then + + if [ "$devd_starts_custom" ]; then + # Remember / store these custom flags + devd_custom_flags=$(echo "$custom_flags" | sed -e "s/$d_flag_match *//") + + else + # This particular devd invokation will be ignored, and we exit this script immediately. + # Because custom_flags_N are instead started during the normal webcamd rc.d startup. + exit 0 + fi + break + fi + + n=$(expr $n + 1) + else + break + fi + done +} + +webcamd_find_devd_flags_by_usb_name_serial() +{ + # Lookup the names and serial numbers of USB devices + usbconfig_names=$(usbconfig) + usbconfig_serials=$(usbconfig dump_string 0x03) + usbconfig_line=$(echo "$usbconfig_names" | grep -n "^ugen${devd_device#ugen}") + usbconfig_line_num="$(echo "$usbconfig_line" | cut -d ':' -f 1)" + + # Determine the USB device name and serial number + devd_usb_name=$(echo "$usbconfig_line" | sed -e 's/.*: at .*//') + devd_usb_serial=$(echo "$usbconfig_serials" | sed -n "${usbconfig_line_num}p" | sed -e 's/.* = .*//') + + # Find any flags matching the USB name / USB serial number + n=0 + while [ "$n" -lt "100" ] + do + device_name=$(eval "echo \$webcamd_device_${n}_name") + + if [ "$device_name" ]; then + if [ "$device_name" = "$devd_usb_name" ]; then + + # If serial numbers are also specified in config + name_serial=$(eval "echo \$webcamd_device_${n}_serial") + if [ "$name_serial" ]; then + + # if matches a USB name AND by USB serial number + if [ "$name_serial" = "$devd_usb_serial" ]; then + # remember / store these custom flags + devd_name_serial_flags=$(eval "echo \$webcamd_device_${n}_flags") + break + fi + + else + # We have match by USB name only, no serial + devd_name_serial_flags=$(eval "echo \$webcamd_device_${n}_flags") + break + fi + fi + n=$(expr $n + 1) + else + break + fi + done +} + +webcamd_start_devd() +{ + # Start a single USB device, as this rc.d script was invoked by devd with extra arguments + + # First check for any custom flags that + + if [ "$webcamd_custom_flags_0" ]; then + # that were specified as custom instance flags + webcamd_find_devd_flags_by_custom_flags; + fi + + if [ "$webcamd_device_0_name" ]; then + # that were specified by the USB device name, USB serial number + webcamd_find_devd_flags_by_usb_name_serial; + fi + + # Start the connected USB device, with any matching custom flags that were found + echo "Starting ${name} -d ${devd_device} -i ${devd_interface} ${devd_custom_flags} ${devd_name_serial_flags} ${webcamd_flags} ${command_args}" | tr -s ' ' + ${command} -d ${devd_device} -i ${devd_interface} ${devd_custom_flags} ${devd_name_serial_flags} ${webcamd_flags} ${command_args} +} + +webcamd_count_instances() +{ + # This variable keeps track of how many instances we will start + num_instances_remaining=0 + num_found_by_name_serial=0 + + if [ "$devd_starts_custom" ]; then + # Count the number of vtuner client custom instances we will start + webcamd_count_custom_instances_vtuner_client; + + else + # Count the number of custom instances we will start + webcamd_count_custom_instances_all; + fi + + # Skip this part if we are starting our devices from devd + if [ "$not_devd" ]; then + + # Error out if webcamd is already running + pids=$(webcamd_pids) + if [ "$pids" ]; then + echo "${name} already running? (pid=${pids})." + exit 1 + fi + + if [ "$webcamd_device_0_name" ]; then + # Find and count the number of devices that match specified USB names and USB serial numbers + webcamd_find_count_by_usb_name_serial; + fi + fi +} + +webcamd_find_count_by_usb_name_serial() +{ + # Gather data about all connected USB devices from usbconfig + usbconfig_devices=$(usbconfig) + usbconfig_serials=$(usbconfig dump_string 0x03) + + # Find connected devices by USB name / USB serial number + n=0 + while [ "$n" -lt "100" ] + do + device_name=$(eval "echo \$webcamd_device_${n}_name") + + if [ "$device_name" ]; then + + # If the config line also has a USB serial number specified + device_serial=$(eval "echo \$webcamd_device_${n}_serial") + if [ "$device_serial" ]; then + + # find the first connected device that matches USB name AND USB serial number + usbconfig_line_num="$(echo "$usbconfig_serials" | grep --max-count=1 -n "$device_serial" | cut -d ':' -f 1)" + if [ "$usbconfig_line_num" ]; then + found_usb_devices=$(echo "$usbconfig_devices" | sed -n "${usbconfig_line_num}p" | cut -d ':' -f 1) + fi + # Remember text string for possible error message later on + device_names="$device_names, $device_name (with serial: $device_serial)" + + else + # match by USB name only + found_usb_devices=$(echo "$usbconfig_devices" | grep "$device_name" | cut -d ':' -f 1) + + # Remember text string for possible error message later on + device_names="$device_names, $device_name" + fi + + # Store for later + eval "webcamd_device_${n}_devices=$found_usb_devices" + num_found_this_loop=$(echo "$found_usb_devices" | wc -w | grep -o -E "[0-9]+") + num_found_by_name_serial=$(expr $num_found_by_name_serial + $num_found_this_loop) + n=$(expr $n + 1) + else + break + fi + done + num_instances_remaining=$(expr $num_instances_remaining + $num_found_by_name_serial) +} + +webcamd_start_by_usb_name_serial() +{ + # Start any devices that were found by USB name / USB serial number + n=0 + while [ "$n" -lt "100" ] + do + device_name=$(eval "echo \$webcamd_device_${n}_name") + + if [ "$device_name" ]; then + # Any connected USB devices that match the specified USB name, USB serial number ? + devices=$(eval "echo \$webcamd_device_${n}_devices") + if [ "$devices" ]; then + + for device in $devices + do + device_flags=$(eval "echo \$webcamd_device_${n}_flags") + + # Launch an instance of webcamd for this device + ${command} -d ${device} ${device_flags} ${webcamd_flags} ${command_args} + num_instances_remaining=$(expr $num_instances_remaining - 1) + + # Wait n seconds until launching the next instance for the next device + if [ "$num_instances_remaining" -gt 0 ]; then + sleep $webcamd_startup_delay + fi + done + fi + n=$(expr $n + 1) + else + break + fi + done +} + +webcamd_count_custom_instances_vtuner_client() +{ + # count the number of vtuner client instances to be launched + + n=0 # outer loop - all custom instances + i=0 # inner loop - vclient instances ('-D') + + while [ "$n" -lt "100" ] + do + custom_flags=$(eval "echo \$webcamd_custom_flags_${n}") + if [ "$custom_flags" ]; then + + # If this custom_flags line is for a virtual device ('-D') + if [ "$(echo "$custom_flags" | grep "\-D *")" ]; then + + # Copy to the array webcamd_vtuner_client_${n}_flags + eval "webcamd_vtuner_client_${i}_flags=\$custom_flags" + i=$(expr $i + 1) + fi + n=$(expr $n + 1) + else + break + fi + done + num_instances_remaining=$(expr $num_instances_remaining + $i) +} + +webcamd_start_by_vtuner_client_flags() +{ + # Start any vtuner client instances + n=0 + while [ "$n" -lt "100" ] + do + vtuner_client_flags=$(eval "echo \$webcamd_vtuner_client_${n}_flags") + + if [ "$vtuner_client_flags" ]; then + # Launch an instance of webcamd with these specific vtuner client ('-D') flags + ${command} ${vtuner_client_flags} ${webcamd_flags} ${command_args} + + # increment the counters + num_instances_remaining=$(expr $num_instances_remaining - 1) + n=$(expr $n + 1) + + # Wait n seconds until launching the next instance for the next device + if [ "$num_instances_remaining" -gt 0 ]; then + sleep $webcamd_startup_delay + fi + else + break + fi + done +} + +webcamd_count_custom_instances_all() +{ + # count the number of instances to be launched + n=0 + while [ "$n" -lt "100" ] + do + if [ "$(eval "echo \$webcamd_custom_flags_${n}")" ]; then + n=$(expr $n + 1) + else + break + fi + done + num_instances_remaining=$(expr $num_instances_remaining + $n) +} + +webcamd_start_by_custom_flags() +{ + # Start any custom instances + n=0 + while [ "$n" -lt "100" ] + do + custom_flags=$(eval "echo \$webcamd_custom_flags_${n}") + + if [ "$custom_flags" ]; then + # Launch a custom instance of webcamd with these specific custom flags + ${command} ${custom_flags} ${webcamd_flags} ${command_args} + + # increment the counters + num_instances_remaining=$(expr $num_instances_remaining - 1) + n=$(expr $n + 1) + + # Wait n seconds until launching the next instance for the next device + if [ "$num_instances_remaining" -gt 0 ]; then + sleep $webcamd_startup_delay + fi + else + break + fi + done +} + +webcamd_check_started() +{ + # Check that at least 1+ webcamd processes are persistent + + if [ "$webcamd_startup_delay" -gt 0 ]; then + # but not if doing "fast-start". When webcamd_startup_delay = 0 seconds + sleep 1 + pids=$(webcamd_pids) + if [ "${pids}" ]; then + echo "${name} is running as pid ${pids}." + else + if [ "$webcamd_devices" ]; then + warn "webcamd not started." + warn "Invalid configuration or USB devices not recognized: ${webcamd_devices% }." + else + warn "webcamd not started. Invalid configuration?" + fi + return 1 + fi + fi +} + +webcamd_stop() +{ + pids=$(webcamd_pids) + if [ "${pids}" ]; then + echo "Stopping ${name}." + echo "Waiting for PIDs: ${pids}" + for signal in TERM INT QUIT KILL HUP + do + kill -s ${signal} ${pids} + sleep 1; + pids=$(webcamd_pids) + [ "${pids}" ] || break; + done + else + echo "${name} is not running." + return 1 + fi +} + +webcamd_status() +{ + pids=$(webcamd_pids) + + if [ "${pids}" ]; then + echo "${name} is running as pid ${pids}." + else + echo "${name} is not running." + return 1 + fi +} + +run_rc_command "$1"