-
Notifications
You must be signed in to change notification settings - Fork 156
/
run-videochat.sh
executable file
·656 lines (572 loc) · 23.1 KB
/
run-videochat.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
#!/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 < 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!"