lots of fixes, improvements, t12 stuff
[distro-setup] / ffs
diff --git a/ffs b/ffs
index 6975d387931c6fb5b8441a270a4533874be6d547..0bb4ae7b94781a6c2792a078b91d58a0f227fc23 100755 (executable)
--- a/ffs
+++ b/ffs
@@ -24,8 +24,6 @@
 
 # todo: learn to start working in one corner of the screen.
 
-# todo: get an icecast on li.b8.nz for when i'm away from home.
-
 # potential improvement: it might be nice that we could have a tall terminal bug only use
 # the top half for a 1080p stream, this is how:
 # https://superuser.com/questions/1106674/how-to-add-blank-lines-above-the-bottom-in-terminal
@@ -130,32 +128,96 @@ shopt -s inherit_errexit 2>/dev/null ||: # ignore fail in bash < 4.4
 set -eE -o pipefail
 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" exit status: $?, PIPESTATUS: ${PIPESTATUS[*]}" >&2' ERR
 
+usage() {
+  cat <<EOF
+Usage: ${0##*/} [OPTIONS] [sysops|tech|staff]
+3 mountpoints: fsf-sysops (default, public), fsf (all staff), fsf-tech (tech team)
+
+-d    debug.
+-f    Stream full screen even high resolution.
+-t    Stream tall half screen
+-u    Undelayed. Removes 5 second video delay, and about 4 second audio delay.
+-w    do not launch watch of stream
+
+note: args duplicated in ffp
+
+
+-h|--help  Print help and exit.
 
+Note: Uses util-linux getopt option parsing: spaces between args and
+options, short options can be combined, options before args.
+EOF
+  exit $1
+}
+
+##### begin command line parsing ########
+
+# ensure we can handle args with spaces or empty.
+ret=0; getopt -T || ret=$?
+[[ $ret == 4 ]] || { echo "Install util-linux for enhanced getopt" >&2; exit 1; }
+
+ffp_args=()
 debug=false
+delay=true
 loglevel=fatal
-
-# 3 mountpoints: fsf-sysops (default, public), fsf (all staff), fsf-tech (tech team)
-# # note: duplicated in ffp
-mount_suffix=-sysops
-while [[ $1 ]]; do
+watch=true
+fullscreen=false
+tall=false
+temp=$(getopt -l help hdftuw "$@") || usage 1
+eval set -- "$temp"
+while true; do
   case $1 in
-    sysops|tech)
-      mount_suffix=-$1
-      ;;
-    staff)
-      mount_suffix=
-      ;;
     -d)
       debug=true
       loglevel=debug
+      loglevel=info
+      ffp_args+=(-d)
+      ;;
+    -f)
+      fullscreen=true
+      tall=false
+      ;;
+    -t)
+      fullscreen=false
+      tall=true
       ;;
+    -w)
+      watch=false
+      ;;
+    -u)
+      delay=false
+      ;;
+    -h|--help) usage ;;
+    --) shift; break ;;
+    *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;;
   esac
   shift
 done
 
+mount_suffix=-sysops
+case $1 in
+  sysops|tech)
+    mount_suffix=-$1
+    ;;&
+  tech)
+    delay=false
+    ;;
+  staff)
+    mount_suffix=
+    ;;
+esac
+
+if $delay; then
+  # 2500 gets us around a 4 second delay, up from 1.5s.
+  delay_arg=,tpad=start_duration=2500ms
+fi
+
+
+##### end command line parsing ########
+
 host=live.iankelling.org:8000
-if [[ $(dig +short @10.2.0.1 -x 10.2.0.2 2>&1 ||:) == kd.b8.nz. ]] \
-     && ip n show 10.2.0.1 | grep . &>/dev/null; then
+if ip n show 10.2.0.1 | grep . &>/dev/null && \
+    [[ $(dig +timeout=1 +short @10.2.0.1 -x 10.2.0.2 2>&1 ||:) == kd.b8.nz. ]]; then
   host=127.0.0.1:8000
 fi
 
@@ -167,14 +229,20 @@ xrandr >$tmpf
 
 # example xrandr output: 1280x800+0+0
 primary_res=$(awk '$2 == "connected" && $3 == "primary" { print $4 }' $tmpf | sed 's/+.*//')
-secondary_res=$(awk '$2 == "connected" && $3 != "primary" { print $3 }' $tmpf | sed 's/+.*//')
+tmp=$(awk '$2 == "connected" && $3 != "primary" { print $3 }' $tmpf | sed 's/+/ /g')
+read -r secondary_res x_offset _ <<<"$tmp"
+
 
 if [[ $secondary_res ]]; then
-  # assumes secondary is on the right
-  x_offset=${primary_res%%x*}
   secondary_x=${secondary_res%%x*}
   secondary_y=${secondary_res##*x}
-  stream_res=$(( secondary_x / 2 ))x$(( secondary_y / 2))
+  if $fullscreen; then
+    stream_res=$secondary_res
+  elif $tall; then
+    stream_res=$(( secondary_x / 2 ))x$secondary_y
+  else
+    stream_res=$(( secondary_x / 2 ))x$(( secondary_y / 2))
+  fi
 else
   x_offset=0
   stream_res=$primary_res
@@ -185,7 +253,12 @@ keyframe_interval=$((framerate * 2))
 
 # Monitor of default sink.
 # eg: alsa_output.usb-Audio-gd_Audio-gd-00.analog-stereo
-pa_sink=$(pacmd list-sinks | awk '/\*/ {getline; print $2}' | sed 's/^<//;s/>$//').monitor
+pa_sink=$(pactl get-default-sink).monitor
+
+# this is for ffmpeg warnings. doesnt seem to affect latency.
+# 160 was too small. at 300, it occasionally complains,
+# probably only when we are using delayed output
+thread_queue_size_arg="-thread_queue_size 500"
 
 opts=(
   # global options
@@ -194,20 +267,24 @@ opts=(
   -hide_banner
   -nostats
 
+  # tested for decreasing latency: did not help.
+  # -probesize 32
+  # tested for warning "Queue input is backward in time". did not help.
+  #-rtbufsize 500M
+
   # note: ordering of inputs also affects zmqsend commands.
 
   ## audio input options
 
   -f pulse
   -name ffs
-  # note: duplicated above
-  -thread_queue_size 160
+  # note: duplicated
+  $thread_queue_size_arg
   -fragment_size 512
   -i default
 
   -f pulse
-  # this is for ffmpeg warnings. doesnt seem to affect latency.
-  -thread_queue_size 160
+  $thread_queue_size_arg
   # pulse knows this name somewhere
   -name ffsdesktop
   # This fixes latency. i haven't tried tuning it, but going too low creates
@@ -218,6 +295,7 @@ opts=(
 
   ## video input options
   -video_size $stream_res
+  $thread_queue_size_arg
   -f x11grab
   -framerate $framerate
   -i :0.0+$x_offset.0
@@ -236,8 +314,17 @@ opts=(
   # localhost url caused an error for me.
   -filter_complex "[0]azmq,volume=precision=fixed: volume=0 [vol0];
 [1]azmq='b=tcp\://127.0.0.1\:5556',volume=precision=fixed: volume=0 [vol1];
-[vol0][vol1] amerge=inputs=2 [out];
-[2]zmq='b=tcp\://127.0.0.1\:5557',drawbox=color=0x262626,drawtext=fontsize=90: fontcolor=beige: x=40: y=40: text=''"
+[vol0][vol1] amerge=inputs=2;
+[2]zmq='b=tcp\://127.0.0.1\:5557',drawbox=color=0x262626,drawtext=fontsize=90: fontcolor=beige: x=40: y=40: text=''${delay_arg}[out]"
+
+#  [vol0][vol1] amerge=inputs=2,adelay=6000:all=1;
+
+
+  # An online source says to match a 5 second vid delay, we can do an
+  # audio delay filter: "adelay=5000|5000". However, we already get
+  # a stream delay of about 2 seconds, and having the audio be about
+  # 2 seconds ahead is fine, they do that intentionally in soccer
+  # matches.
 
   # Based on error message and poking around, it seems ffmpeg is not
   # smart enough to see that [vol0] and [vol1] are inputs to the amerge
@@ -254,7 +341,6 @@ opts=(
   # for 1080p, default 256k is poor quality. 500 is ok. 1500 is a bit better.
   -b:v 1500k
   -threads 2
-  -buffer_duration 10
   -error-resilient 1
 
   ## audio output options
@@ -274,6 +360,10 @@ rm -f /tmp/iank-ffmpeg-interlude-toggle
 # start muted
 pactl set-source-mute @DEFAULT_SOURCE@ true
 
+if pkill -f ^ffmpeg.\*icecast://source.\*/fsf; then
+  sleep 1
+fi
+
 #echo executing: ffmpeg ${opts[@]}
 
 #{ sleep 1; ffp &>/dev/null & }
@@ -283,8 +373,57 @@ if $debug; then
   exit 0
 fi
 
-# For now, we want to watch the stream and end the stream when we stop watching.
+##### begin clipboard history checkup ####
+
+# Avoid streaming with secrets in our clipboard history.  We could just
+# clear the history, but here I truncate it to a max and then show it,
+# and then I can press super+y if I want to clear it, or close the
+# window if I want to keep it.
+copyqcount=$(copyq count)
+regex='^[1-9][0-9]*$'
+if [[ $copyqcount =~ $regex ]]; then
+  # i dont want to think about more than this
+  max_rows=40
+  if (( copyqcount >= max_rows  )); then
+    rows_arg=()
+    for ((i=max_rows; i<copyqcount; i++)); do
+      rows_arg+=($i)
+    done
+    copyq remove "${rows_arg[@]}"
+  fi
+  copyq show
+  gone=false
+  for (( i=0; i<40; i++ )); do
+    if i3-msg -t get_tree | jq -e '.. | select(.class? == "copyq" and .instance? == "copyq")' &>/dev/null; then
+      sleep .5
+    else
+      gone=true
+      break
+    fi
+  done
+  if ! $gone; then
+    msg="ffs: copyq not gone. aborting. super+y = copyq-restart / clear"
+    if [[ -t 0 ]]; then
+      echo $msg
+    else
+      dunstify -u critical -h string:x-dunst-stack-tag:alert "$msg"
+    fi
+    exit 1
+  fi
+fi
+##### end clipboard history checkup ####
+
+if [[ $mount_suffix == -sysops ]]; then
+  touch $HOME/.iank-stream-on
+fi
+
+echo true >$HOME/.iank-stream-muted
+
 ffmpeg "${opts[@]}" &
-sleep 2
-ffp ||:
-kill %%
+if $watch; then
+  # watch the stream and end the stream when we stop watching.
+  sleep 2
+  ffp -d "${ffp_args[@]}" ||:
+  kill %%
+  rm -f $HOME/.iank-stream-on
+fi