#!/bin/bash

# Script for using IP Webcam as a microphone/webcam in Debian Jessie,
# Ubuntu 13.04, 14.04, 16.04 and Arch Linux

# Copyright (C) 2011-2021 Antonio García Domínguez
# Copyright (C) 2016 C.J. Adams-Collier
# Copyright (C) 2016 Laptander
# Licensed under GPLv3

# Usage: ./run-videochat.sh [flip method]
#
# [flip method] is "none" by default. Here are some values you can try
# out (from gst/videofilter/gstvideoflip.c):
#
# - clockwise: clockwise 90 degrees
# - rotate-180: 180 degrees
# - counterclockwise: counter-clockwise 90 degrees
# - horizontal-flip: flip horizontally
# - vertical-flip: flip vertically
# - upper-left-diagonal: flip across upper-left/lower-right diagonal
# - upper-right-diagonal: flip across upper-right/lower-left diagonal
#
# To be able to use audio from your phone as a virtual microphone, open pavucontrol,
# then open Playback tab and choose 'IP Webcam' for gst-launch-1.0 playback Stream.
# Then to use audio stream in Audacity, open it and press record button or click on
# the Recording Meter Toolbar to start monitoring, then go to pavucontrol's Recording tab
# and choose "Monitor of IP Webcam" for ALSA plug-in [audacity].
#
# If you want to be able to hear other applications sounds, for example from web-browser,
# then while it is playing some sound, go to pavucontrol's Playback tab and choose your
# default sound card for web-browser.

# --
#
# Last tested with:
# - souphttpsrc version 1.0.6
# - v4l2sink version 1.0.6
# - v4l2loopback version 0.7.0

### FUNCTIONS

show_help() {
    echo "Usage:"
    echo " $0 [options]"
    echo
    echo "Script for using IP Webcam as a microphone/webcam."
    echo
    echo "Options:"
    echo " -a, --audio             capture only audio"
    echo " -b, --adb-path <path>   set adb location if not in PATH"
    echo " -C, --no-echo-cancel    do not set up echo cancellation"
    echo " -d, --device <device>   force video device to use"
    echo " -f, --flip <flip>       flip image"
    echo " -F, --fps <fps>         video framerate (fractional) (default 30/1)"
    echo " -h, --height <height>   set image height (default 480)"
    echo " -l, --adb-flags <id>    adb flags to specify device id"
    echo " -i, --use-wifi <ip>     use wi-fi mode with specified ip"
    echo " -p, --port <port>       port on which IP Webcam is listening (default 8080)"
    echo " -P, --password <pass>   password for accesing the IP Webcam"
    echo " -s, --no-sync           No force syncing to timestamps"
    echo " -t, --with-tee          adds the 'tee' multiplexer to the pipeline, to workaround 'single-frame' capture issue (see issue #97)"
    echo " -u, --username <user>   username for accesing the IP Webcam"
    echo " -v, --video             capture only video"
    echo " -w, --width <width>     set image width (default 640)"
    echo " -x, --no-proxy          disable proxy while acessing IP"
    echo "     --crop-left <px>    crop the image by <px> pixels from left"
    echo "     --crop-right <px>   crop the image by <px> pixels from right"
    echo "     --crop-top <px>     crop the image by <px> pixels from top"
    echo "     --crop-bottom <px>  crop the image by <px> pixels from bottom"
    echo "     --help              show this help"
}
check_os_version() {
    # checks if the OS version can use newer GStreamer version
    DIST="$1"
    RELEASE="$2"

    case "$DIST" in
        "Debian")       return "`echo "$RELEASE < 8.0"   | bc`" ;;
        "Ubuntu")       return "`echo "$RELEASE < 14.04" | bc`" ;;
        "LinuxMint")    return "`echo "$RELEASE < 14.04" | bc`" ;;
        "Arch")         return 0 ;;
    esac
    # assume other Distributions are also new enough, by now
    return 0
}

error() {
    zenity --error --no-wrap --text "$@" > /dev/null 2>&1
    exit 1
}

warning() {
    zenity --warning --no-wrap --text "$@" > /dev/null 2>&1
}

info() {
    zenity --info --no-wrap --text "$@" > /dev/null 2>&1
}

confirm() {
    zenity --question --no-wrap --text "$@" > /dev/null 2>&1
}

can_run() {
    # It's either the path to a file, or the name of an executable in $PATH
    which "$1" >/dev/null 2>/dev/null
}

start_adb() {
    can_run "$ADB" && "$ADB" $ADB_FLAGS start-server
}

phone_plugged() {
    test "$("$ADB" $ADB_FLAGS get-state 2>/dev/null)" = "device"
}

url_reachable() {
    CURL_OPTIONS=""
    if [ $DISABLE_PROXY = 1 ]; then
        CURL_OPTIONS+="--noproxy $IP"
    fi

    if [[ $USERNAME != "" && $PASSWORD != "" ]]; then
        CURL_OPTIONS+="-u $USERNAME:$PASSWORD"
    fi
    # -f produces a non-zero status code when answer is 4xx or 5xx
    curl $CURL_OPTIONS -f -m 5 -sI "$1" >/dev/null
}

iw_server_is_started() {
    if [ $CAPTURE_STREAM = av ]; then
        : # help me optimize this code
          temp=$(url_reachable "$AUDIO_URL"); au=$?; #echo au=$au
          temp=$(url_reachable "$VIDEO_URL"); vu=$?; #echo vu=$vu
          if [ $au = 0 -a $vu = 0 ]; then return 0; else return 1; fi
    elif [ $CAPTURE_STREAM = a ]; then
          if url_reachable "$AUDIO_URL"; then return 0; else return 1; fi
    elif [ $CAPTURE_STREAM = v ]; then
          if url_reachable "$VIDEO_URL"; then return 0; else return 1; fi
    else
          error "Incorrect CAPTURE_STREAM value ($CAPTURE_STREAM). Should be a, v or av."
    fi
}

module_id_by_sinkname() {
    pactl list sinks | grep -e "Name:" -e "Module:" |grep -A1 "Name: $1$" | grep Module: | cut -f2 -d: | tr -d ' '
}

ensure_div() {
    local -i val="$1"
    local -i div="$2"
    local -i mod
    mod=$(( val % div ))
    if (( mod == 0 )); then
        printf '%d' "$val"
    else
        if (( mod >= div/2 )); then
            printf '%d' "$(( val + div - mod ))"
        else
            printf '%d' "$(( val - mod ))"
        fi
        return 1
    fi
}

validate_div_16() {
    local param="$1"
    local val="$2"
    local val2
    if ! val2="$(ensure_div "$val" 16)"; then
        echo "warning: The parameter $param=$val might need to be divisible by 16. Consider using the closest value: $val2." >&2
    fi
    # use $val2 to enforce
    printf '%d' "$val"
}

# kills a <pid> with <name> with <sig> (TERM), waits <timeout> seconds before KILLing it
killtask() {
    local pid="$1"
    local sig="${2:-TERM}"
    local timeout="${3:-10}"
    local name="${4:-"pid $pid"}"
    if [ "$pid" ]; then
        printf "Terminating %s.\n" "$name" >&2
        kill -s "$sig" -- "$pid"

        local i
        for ((i=0; i < timeout; i++)); do
            sleep 1
            if ! ps -p "$pid" >/dev/null 2>&1; then
                return 0
            fi
        done

        printf "%s is not responding to %s, KILLing it.\n" "${name^}" "$sig" >&2
        kill -s KILL -- "$pid"
        return 1
    fi
}

# a kind of a macro to be run within monitor_job
# sets variable killing=1 and runs the killtask
kill_job() {
    killing=1
    trap - INT TERM
    killtask "$pid" "$killsig" 10 "$name" &
}

set_kill_job_trap() {
    trap 'kill_job' INT TERM
}

# runs a background job (specified with "$@") and monitors it for termination
# also watches stdin for enter, SIGINT (^C) and SIGTERM, on which it gracefully terminates the job
# accepts couple JOB_ variables, that slightly alter the behavior:
#   JOB_SIGNAL      - (TERM) initial signal to terminate the monitored job
#   JOB_LOG         - file to redirect job's stdin & stderr
#   JOB_NAME        - ("the job") name of the job for log messages
#   JOB_INTRO_CMD   - command or function name (w/o args) to be called after job start
#   JOB_FAILURE_CMD - command or function name (w/o args) to be called on job unexpected end
monitor_job() {
    local killsig="${JOB_SIGNAL:-TERM}"
    local log="${JOB_LOG:-}"
    local name="${JOB_NAME:-the job}"
    local intro="${JOB_INTRO_CMD:-}"
    local failure="${JOB_FAILURE_CMD:-}"
    local run_intro=1
    local pid=
    local killing=

    # schedule a signal trap that kills the job
    set_kill_job_trap
    # start the job (redirect output to a log file)
    if [ "$log" ]; then
        "$@" >"$log" 2>&1 &
    else
        "$@" &
    fi
    pid=$!

    # reading input to trigger termination, while also checking the process
    local rc
    while { rc=0; read -r -t 1 || rc=$?; } || ((rc > 128)); do
        # enter has been pressed
        if ((rc == 0)) && ! ((killing)); then
            kill_job
            break
        fi
        # break if the job is not running or we are killing it
        if ! ps -p "$pid" >/dev/null 2>&1 || ((killing)); then
            break
        fi
        # job is running (call intro 1st time)
        if ((run_intro)); then
            run_intro=0
           ($intro)
        fi
    done
    wait "$pid" >/dev/null 2>&1 || :
    # did job terminate without us?
    if ! ((killing)); then
        if [ "$failure" ]; then
            ($failure)
        else
            printf "warning: %s ended unexpectedly!\n" "${name^}" >&2
        fi
    fi
}

### CONFIGURATION

# Exit on first error
set -e

# Choose which stream to capture.
# a - audio only, v - video only, av - audio and video.
# Make sure that IP webcam is streaming corresponding streams, otherwise error will occur.
# Defaults to audio and video, ovverrided by command line options.
CAPTURE_STREAM=av

# Choose audio codec from wav, aac or opus
# do not choose opus until editing pipeline. If choose opus, pipeline will not work
# and some errors will appear in feed.log.
# I do not know how to edit pipelines for now.
AUDIO_CODEC=wav

# Port on which IP Webcam is listening
# Defaults to 8080, overrided by command line options.
PORT=8080

# If your "adb" is not in your $PATH, specify it on command line.
if can_run adb; then ADB=$(which adb); fi

# Flags for ADB.
# when you need to pick from several devices, specify deviceid on command line (list deviceids with 'adb devices').
ADB_FLAGS=

# set on command line
FLIP_METHOD=

# video framerate
# use a usual default, without fps the caps negotiation might fail
FPS=30/1

# Dimensions of video are infered from the source, can be overridden on command line.
# Make sure both dimensions are multiples of 16 (see issue #97).
WIDTH=
HEIGHT=

# Video crop values
CROP_LEFT=
CROP_RIGHT=
CROP_TOP=
CROP_BOTTOM=

# Force syncing to timestamps. Useful to keep audio and video in sync,
# but may impact performance in slow connections. If you see errors about
# timestamping or you do not need audio, you can try changing this to false from command line.
SYNC=true

# To disable proxy while acessing IP (set value 1 to disable, 0 for not)
# For cases when host m/c is connected to a Proxy-Server and IP belongs to local network
DISABLE_PROXY=0

# To disable echo cancellation
DISABLE_ECHO_CANCEL=0

# Use exclusive caps by default (required by Chrome, Cheese and others)
V4L2_OPTS="exclusive_caps=1"

USERNAME=""
PASSWORD=""

OPTS="$(getopt -o ab:Cd:f:F:h:l:i:p:P:stu:vw:x --long audio,adb-path:,no-echo-cancel,device:,flip:,fps:,height:,help,adb-flags:,use-wifi:,port:,password:,no-sync,with-tee,username:,video,width:,no-proxy,crop-left:,crop-right:,crop-top:,crop-bottom: -n "$0" -- "$@")"
eval set -- "$OPTS"

while true; do
    case "$1" in
        -a | --audio ) CAPTURE_STREAM="a"; shift;;
        -b | --adb-path ) ADB="$2"; shift 2;;
        -C | --no-echo-cancel ) DISABLE_ECHO_CANCEL=1; shift;;
        -d | --device ) DEVICE="$2"; shift 2;;
        -f | --flip ) FLIP_METHOD="$2"; shift 2;;
        -F | --fps ) FPS="$2"; shift 2;;
        -h | --height ) HEIGHT="$(validate_div_16 "$1" "$2")"; shift 2;;
        -l | --adb-flags ) ADB_FLAGS="-s $2"; shift 2;;
        -i | --use-wifi ) IP="$2"; shift 2;;
        -p | --port ) PORT="$2"; shift 2;;
        -P | --password) PASSWORD="$2"; shift 2;;
        -u | --username) USERNAME="$2"; shift 2;;
        -s | --no-sync ) SYNC=false; shift;;
        -t | --with-tee ) USE_TEE=true; shift;;
        -v | --video ) CAPTURE_STREAM="v"; shift;;
        -w | --width ) WIDTH="$(validate_div_16 "$1" "$2")"; shift 2;;
        -x | --no-proxy) DISABLE_PROXY=1; shift;;
             --crop-left) CROP_LEFT="$(validate_div_16 "$1" "$2")"; shift 2;;
             --crop-right) CROP_RIGHT="$(validate_div_16 "$1" "$2")"; shift 2;;
             --crop-top) CROP_TOP="$(validate_div_16 "$1" "$2")"; shift 2;;
             --crop-bottom) CROP_BOTTOM="$(validate_div_16 "$1" "$2")"; shift 2;;
        --help) show_help; exit; shift;;
        -- ) shift; break;;
        * ) echo "Internal error!" ; exit 1 ;;
    esac
done

# Ensure FPS is fractional (and above 1/1).
if ! grep '^[[:digit:]]\+/[[:digit:]]\+$' <<<"$FPS" >/dev/null 2>&1; then
    if grep '^[[:digit:]]\+$' <<<"$FPS" >/dev/null 2>&1; then
        FPS="$FPS/1"
    else
        error "Bad FPS format: $FPS. It should look like '30' or '30/1'."
    fi
fi
if ((FPS == 0)); then  # Note: the fractional value gets evaluated as an (integer arithmetic) expression.
    warning "FPS $FPS &lt; 1/1, which might prevent the underlying gstreamer pipeline from starting."
fi

declare -A DISTS
DISTS=(["Debian"]=1 ["Ubuntu"]=2 ["Arch"]=3 ["LinuxMint"]=4)

if can_run lsb_release; then
    DIST=`lsb_release -i | cut -f2 -d ":"`
    RELEASE=`lsb_release -r | cut -f2 -d ":"`
fi
if [ -z "$DIST" ] || [ -z "${DISTS[$DIST]}" ] ; then 
    if [ -f "/etc/arch-release" ]; then
        DIST="Arch"
        RELEASE=""
    elif [ -f "/etc/debian_version" ] ; then
        DIST="Debian"
        RELEASE=`perl -ne 'chomp; if(m:(jessie|testing|sid):){print "8.0"}elsif(m:[\d\.]+:){print}else{print "0.0"}' < /etc/debian_version`
    fi
fi

GST_VER="0.10"
GST_VIDEO_CONVERTER="ffmpegcolorspace"
GST_VIDEO_MIMETYPE="video/x-raw-yuv"
GST_VIDEO_FORMAT="format=(fourcc)YUY2"

GST_AUDIO_MIMETYPE="audio/x-raw-int"
GST_AUDIO_FORMAT="width=16,depth=16,endianness=1234,signed=true"
GST_AUDIO_RATE="rate=44100"
GST_AUDIO_CHANNELS="channels=1"
GST_AUDIO_LAYOUT=""

set +e
check_os_version $DIST $RELEASE
set -e
if [ $? -eq 0 ]
then
    GST_VER="1.0"
    GST_VIDEO_CONVERTER="videoconvert"
    GST_VIDEO_MIMETYPE="video/x-raw"
    GST_VIDEO_FORMAT="format=YUY2"

    GST_AUDIO_MIMETYPE="audio/x-raw"
    GST_AUDIO_FORMAT="format=S16LE"
    GST_AUDIO_LAYOUT=",layout=interleaved"
fi
DIMENSIONS="${WIDTH:+,width=$WIDTH}${HEIGHT:+,height=$HEIGHT}"

GST_VIDEO_CAPS="$GST_VIDEO_MIMETYPE,$GST_VIDEO_FORMAT$DIMENSIONS"
GST_AUDIO_CAPS="$GST_AUDIO_MIMETYPE,$GST_AUDIO_FORMAT$GST_AUDIO_LAYOUT,$GST_AUDIO_RATE,$GST_AUDIO_CHANNELS"
PA_AUDIO_CAPS="$GST_AUDIO_FORMAT $GST_AUDIO_RATE $GST_AUDIO_CHANNELS"

# GStreamer debug string (see gst-launch manpage)
GST_DEBUG=souphttpsrc:0,videoflip:0,$GST_VIDEO_CONVERTER:0,v4l2sink:0,pulse:0

### MAIN BODY


# Probe module if not probed yet
if lsmod | grep -w v4l2loopback >/dev/null 2>/dev/null; then
    # module is already loaded, do nothing
    :
elif [ $CAPTURE_STREAM = v -o $CAPTURE_STREAM = av ]; then
    if can_run sudo; then
        echo Loading module
        sudo modprobe v4l2loopback $V4L2_OPTS #-q > /dev/null 2>&1
        sleep .05
    else
        echo Load module with \"modprobe v4l2loopback $V4L2_OPTS\"
    fi
fi

# If the user hasn't manually specified which /dev/video* to use
# through DEVICE, use the first "v4l2 loopback" device as the webcam:
# this should help when loading v4l2loopback on a system that already
# has a regular webcam. If that doesn't work, fall back to first /dev/video*.
if [ -z "$DEVICE" ]; then
    if v4l2lb_video_device_names="$(ls /sys/devices/virtual/video4linux/ 2>/dev/null)"; then
        # use the first v4l2loopback device
        DEVICE="/dev/$(head -n 1 <<<"$v4l2lb_video_device_names")"
        if (($(wc -l <<<"$v4l2lb_video_device_names") > 1)); then
            echo "Using the first v4l2loopback device $DEVICE, but there are more. Make sure it's the right one." >&2
        fi
    elif video_device_names="$(ls /dev/video* 2>/dev/null)"; then
        DEVICE="/dev/$(head -n 1 <<<"$video_device_names")"
        warning "Could not find any v4l2loopback device: falling back to $DEVICE"
    else
        error "Could not find any video device."
    fi
fi

# Test that we can read from and write to the device
if ! test -r "$DEVICE"; then
    error "$DEVICE is not readable: please fix your permissions"
fi
if ! test -w "$DEVICE"; then
    error "$DEVICE is not writable: please fix your permissions"
fi

# Decide whether to connect through USB or through wi-fi
if [ -z $IP ]; then
    # start adb daemon to avoid relaunching it in while
    if ! can_run "$ADB"; then
        error "adb is not available: you'll have to use Wi-Fi, which will be slower.\nNext time, please install the Android SDK from developer.android.com/sdk or install adb package."
    fi
    start_adb
    if ! phone_plugged; then
        error "adb is available, but the phone is not plugged in.\nConnect your phone to USB and allow usb debugging under developer settings or use Wi-Fi (slower)."
    fi
    if ss -ln src ":$PORT" | grep -q ":$PORT"; then
        PIDOF_ADB="$(pidof adb)"
        if test -n "$PIDOF_ADB" && ss -lptn src ":$PORT" | grep -q "pid=${PIDOF_ADB}"; then
            if confirm "Your port $PORT seems to be in use by ADB: would you like to clear the previous port before continuing?"; then
                "$ADB" $ADB_FLAGS forward --remove tcp:$PORT
            else
                exit 1
            fi
        else
            error "Your port $PORT seems to be in use: try using Wi-Fi.\nIf you would like to use USB forwarding, please free it up and try again."
        fi
    fi
    "$ADB" $ADB_FLAGS forward tcp:$PORT tcp:$PORT
    IP=127.0.0.1
    MODE=adb
else
    MODE=wifi
fi

BASE_URL=http://$IP:$PORT
VIDEO_URL=$BASE_URL/videofeed
AUDIO_URL=$BASE_URL/audio.$AUDIO_CODEC

if ! iw_server_is_started; then
    if [ $CAPTURE_STREAM = av ]; then
        MESSAGE="The IP Webcam audio feed is not reachable at <a href=\"$AUDIO_URL\">$AUDIO_URL</a>.\nThe IP Webcam video feed is not reachable at <a href=\"$VIDEO_URL\">$VIDEO_URL</a>."
    elif [ $CAPTURE_STREAM = a ]; then
        MESSAGE="The IP Webcam audio feed is not reachable at <a href=\"$AUDIO_URL\">$AUDIO_URL</a>."
    elif [ $CAPTURE_STREAM = v ]; then
        MESSAGE="The IP Webcam video feed is not reachable at <a href=\"$VIDEO_URL\">$VIDEO_URL</a>."
    else
        error "Incorrect CAPTURE_STREAM value ($CAPTURE_STREAM). Should be a, v or av."
    fi
    error "$MESSAGE\nPlease install and open IP Webcam in your phone and start the server.\nMake sure that values of variables IP, PORT, CAPTURE_STREAM in this script are equal with settings in IP Webcam."
fi

# Test if audio server is running on pipewire
if pactl info | grep -q PipeWire; then
    if [ "$CAPTURE_STREAM" = v ]; then
        :
    else
    # currently setting audio sinks errors out, so give user a workaround
        error "Only video streams on Pipewire are currently supported. Audio is a WIP. Please set CAPTURE_STREAM value to v."
    fi
fi

if [ $CAPTURE_STREAM = a -o $CAPTURE_STREAM = av ]; then
    # idea: check if default-source is correct. If two copy of script are running,
    # then after ending first before second you will be set up with $SINK_NAME.monitor,
    # but not with your original defauld source.
    # The same issue if script was not end correctly, and you restart it.
    DEFAULT_SINK=$(pactl info | grep "Sink" | cut -f3 -d " ")
    DEFAULT_SOURCE=$(pactl info | grep "Source" | cut -f3 -d " ")

    SINK_NAME="ipwebcam"
    SINK_ID=$(module_id_by_sinkname $SINK_NAME)
    ECANCEL_ID=$(module_id_by_sinkname "${SINK_NAME}_echo_cancel")

    # Registering audio device if not yet registered
    if [ -z $SINK_ID ] ; then
        SINK_ID=$(pactl load-module module-null-sink \
                sink_name="$SINK_NAME" \
                $PA_AUDIO_CAPS \
                sink_properties="device.description='IP\ Webcam'")
    fi

    if [ $DISABLE_ECHO_CANCEL = 1 ]; then
        :
    elif [ -z $ECANCEL_ID ] ; then
        ECANCEL_ID=$(pactl load-module module-echo-cancel \
                   sink_name="${SINK_NAME}_echo_cancel" \
                   source_master="$SINK_NAME.monitor" \
                   sink_master="$DEFAULT_SINK" \
                   $PA_AUDIO_CAPS \
                   aec_method="webrtc" save_aec=true use_volume_sharing=true) || true
    fi

    pactl set-default-source $SINK_NAME.monitor
fi

# Check for gst-launch
GSTLAUNCH=gst-launch-${GST_VER}
if ! can_run "$GSTLAUNCH"; then
    error "Could not find gst-launch. Exiting."
fi

# Start the GStreamer graph needed to grab the video and audio
set +e

#sudo v4l2loopback-ctl set-caps $GST_0_10_VIDEO_CAPS $DEVICE

pipeline_video() {
    GST_FLIP="${FLIP_METHOD:+! videoflip method=$FLIP_METHOD}"
    GST_CROP="${CROP_LEFT:+ left=$CROP_LEFT}${CROP_RIGHT:+ right=$CROP_RIGHT}${CROP_TOP:+ top=$CROP_TOP}${CROP_BOTTOM:+ bottom=$CROP_BOTTOM}"
    GST_CROP="${GST_CROP:+! videocrop$GST_CROP}"
    # Due to what seems an issue between v4l2loopback and gst-1.0 (https://github.com/umlaeute/v4l2loopback/issues/83),
    # the pipeline might need the "tee" multiplexer to enforce an additional buffer copy.
    # Here we enable it if the user explicitly asked to.
    # TODO: consider automatically enabling this if using gst-1.0 and specific version ranges of v4l2loopback.
    GST_TEE=""
    if [ "$USE_TEE" = "true" ]; then
        GST_TEE="! tee "
    fi

    echo souphttpsrc location="$VIDEO_URL" do-timestamp=true is-live=true user-id="$USERNAME" user-pw="$PASSWORD" \
      ! queue \
      ! multipartdemux ! "image/jpeg,framerate=$FPS" \
      ! decodebin \
      ! $GST_VIDEO_CONVERTER \
      ! videoscale \
      ! $GST_VIDEO_CAPS \
      $GST_FLIP \
      $GST_CROP \
      $GST_TEE \
      ! v4l2sink device="$DEVICE" sync=$SYNC
}

pipeline_audio() {
  echo souphttpsrc location="$AUDIO_URL" do-timestamp=true is-live=true user-id="$USERNAME" user-pw="$PASSWORD" \
    ! $GST_AUDIO_CAPS ! queue \
    ! pulsesink device="$SINK_NAME" sync=$SYNC
}

if [ $CAPTURE_STREAM = av ]; then
    PIPELINE="$( pipeline_audio )  $( pipeline_video )"
elif [ $CAPTURE_STREAM = a ]; then
    PIPELINE=$( pipeline_audio )
elif [ $CAPTURE_STREAM = v ]; then
    PIPELINE=$( pipeline_video )
else
    error "Incorrect CAPTURE_STREAM value ($CAPTURE_STREAM). Should be a, v or av."
fi

# echo "$PIPELINE"

if [ $DISABLE_PROXY = 1 ]; then
    # Disabling proxy to access WIFI_IP viz. on local network
    unset http_proxy
fi

stream_intro() {
    if [ $CAPTURE_STREAM = av ]; then
        MESSAGE="IP Webcam audio is streaming through pulseaudio sink '$SINK_NAME'.\nIP Webcam video is streaming through v4l2loopback device $DEVICE.\n"
    elif [ $CAPTURE_STREAM = a ]; then
        MESSAGE="IP Webcam audio is streaming through pulseaudio sink '$SINK_NAME'.\n"
    elif [ $CAPTURE_STREAM = v ]; then
        MESSAGE="IP Webcam video is streaming through v4l2loopback device $DEVICE.\n"
    else
        error "Incorrect CAPTURE_STREAM value ($CAPTURE_STREAM). Should be a, v or av."
    fi
    info "${MESSAGE}You can now open your videochat app."

    echo "Press enter to end stream."
}
stream_failure() {
    warning "Stream ended unexpectedly!"
}

JOB_NAME='stream' JOB_LOG=feed.log JOB_INTRO_CMD=stream_intro JOB_FAILURE_CMD=stream_failure \
    monitor_job "$GSTLAUNCH" -e -vt --gst-debug="$GST_DEBUG" $PIPELINE
    # Maybe we need edit this pipeline to transfer it to "Monitor of IP Webcam" to be able to use it as a microphone?

# cleanup
if [ $CAPTURE_STREAM = a ] || [ $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

echo "Disconnected from IP Webcam. Have a nice day!"
