Skip to content

Add testing of synchronization script with virtual screen buffer #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y \
flawfinder squashfs-tools uuid-dev libuuid1 libffi-dev libssl-dev libssl1.1 \
libarchive-dev libgpgme11-dev libseccomp-dev wget gcc make pkg-config
libarchive-dev libgpgme11-dev libseccomp-dev wget gcc make pkg-config \
xvfb xdotool ffmpeg

- name: Build and install Singularity
run: |
Expand Down Expand Up @@ -83,3 +84,39 @@ jobs:
./test_reprostim_container.sh --version
cd ../..
pwd

- name: Test timesync-stimuli run
run: |
export FRAME_WIDTH=1920
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally place this into a script which could even be used locally .

Do not rely on /tmp - use ${TMPDIR:-/tmp}

export FRAME_HEIGHT=1080
export FRAME_RATE=60
export FRAME_BPP=24
export DISPLAY_PATH="/tmp/reprostim_last_display.txt"
export XVFB_OPTS="-screen 0 ${FRAME_WIDTH}x${FRAME_HEIGHT}x${FRAME_BPP} -ac +extension GLX +render -noreset"
export DISPLAY_START=25
export REPROSTIM_CMD="./run_reprostim_container.sh timesync-stimuli -m event --mute -d \$(cat /tmp/reprostim_last_display.txt)"
cd tools/ci
echo "Run Xvfb in background with REPROSTIM_CMD"
xvfb-run -a -n $DISPLAY_START -s "$XVFB_OPTS" bash -c "echo \$DISPLAY > ${DISPLAY_PATH}; $REPROSTIM_CMD"&
XVFB_RUN_PID=$!
echo "Started xvfb-run with PID $XVFB_RUN_PID"
echo "Wait for Xvfb to start"
sleep 4
export DISPLAY=$(cat ${DISPLAY_PATH})
echo "Xvfb started on display: $DISPLAY"
echo "Send test pulse events"
./test_reprostim_events.sh 2 5 5 1.5 20 "${DISPLAY}" &
echo "Record video for 45 seconds"
ffmpeg -video_size "${FRAME_WIDTH}x${FRAME_HEIGHT}" -framerate "${FRAME_RATE}" -f x11grab -i "$DISPLAY" -t 45 -c:v libx264 -pix_fmt yuv420p "/tmp/reprostim_screenshot_$(date +%Y-%m-%d_%H-%M-%S).mp4"
sleep 45
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be move this entire block into REPROSTIM_CMD which would already have DISPLAY

ls -l /tmp/reprostim_*
echo "Kill Xvfb at the end"
sleep 1
kill $XVFB_RUN_PID 2>/dev/null || true
wait $XVFB_RUN_PID 2>/dev/null || true

- name: Upload screenshot video artifact
uses: actions/upload-artifact@v4
with:
name: reprostim-screenshot
path: /tmp/reprostim_screenshot*.mp4
103 changes: 103 additions & 0 deletions docs/misc/xvfb-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Virtual Screen Notes

## Installation & Usage

```shell
sudo apt update
sudo apt install xvfb
sudo apt install xdotool

which xvfb-run
```

Run in background mode as FullHD:
```shell
# use FullHD resolution, disables access control, enables GLX and
# render extensions, no reset at last client exit
export XVFB_OPTS="-screen 0 1920x1080x24 -ac +extension GLX +render -noreset"

# run on display :99
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99

# or use automatic screen selection
Xvfb --auto-servernum --server-num=20 --auto-servernum --server-num=20 -s "$XVFB_OPTS"

```
Run say `xterm` in background:
```shell
xvfb-run xterm &
```

Make PNG screenshot:
```shell
import -display :99 -window root "screenshot_$(date +%Y-%m-%d_%H:%M:%S).png"
```

Kill Xvfb at the end:
```shell
killall Xvfb
```

## Script Example

Now all together in a script:
```bash
# install Xvfb
sudo apt update
sudo apt install xvfb
sudo apt install xdotool
which xvfb-run

# setup params
export FRAME_WIDTH=1920
export FRAME_HEIGHT=1080
export FRAME_RATE=60
export FRAME_BPP=24
export DISPLAY_PATH="/tmp/reprostim_last_display.txt"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not hardcode paths under folders which are public, use mktemp , e.g. smth like $(mktemp -d ${TMPDIR:-/tmp}/dl-XXXXXXX) if you want an entire folder to place stuff in.

export XVFB_OPTS="-screen 0 ${FRAME_WIDTH}x${FRAME_HEIGHT}x${FRAME_BPP} -ac +extension GLX +render -noreset"
export DISPLAY_START=25
# export REPROSTIM_CMD="hatch run reprostim timesync-stimuli -m event --mute -d $(cat /tmp/reprostim_last_display.txt)"
export REPROSTIM_CMD="./run_reprostim_container.sh timesync-stimuli -m event --mute -d $(cat /tmp/reprostim_last_display.txt)"

cd tools/ci

# run Xvfb in background with REPROSTIM_CMD
xvfb-run -a -n $DISPLAY_START -s "$XVFB_OPTS" \
bash -c 'echo $DISPLAY > ${DISPLAY_PATH}; $REPROSTIM_CMD'&


XVFB_RUN_PID=$!
echo "Started xvfb-run with PID $XVFB_RUN_PID"

# wait for Xvfb to start
sleep 2

export DISPLAY=$(cat ${DISPLAY_PATH})
echo "Xvfb started on display: $DISPLAY"

# wait some time to start command
# sleep 5

# make screenshot
# import -display $DISPLAY -window root "/tmp/reprostim_screenshot${DISPLAY}_$(date +%Y-%m-%d_%H:%M:%S).png"

# send test pulse events
./test_reprostim_events.sh 2 5 5 1.5 20&

# record video for 45 seconds
ffmpeg -video_size ${FRAME_WIDTH}x${FRAME_HEIGHT} -framerate ${FRAME_RATE} -f x11grab -i $DISPLAY \
-t 45 -c:v libx264 -pix_fmt yuv420p /tmp/reprostim_screenshot${DISPLAY}_$(date +%Y-%m-%d_%H:%M:%S).mp4

sleep 45

# kill Xvfb at the end
sleep 1
kill $XVFB_RUN_PID
wait $XVFB_RUN_PID 2>/dev/null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when you move all those commands into a script, there would be no need for duplicating the commands here.

```





Comment on lines +99 to +103
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

1 change: 1 addition & 0 deletions docs/source/notes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Miscellaneous Notes
containers
audiocodes-notes
disp_mon-notes
xvfb-notes
2 changes: 2 additions & 0 deletions docs/source/notes/xvfb-notes.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.. include:: ../../misc/xvfb-notes.md
:parser: myst_parser.sphinx_
15 changes: 9 additions & 6 deletions src/reprostim/cli/cmd_timesync_stimuli.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@
@click.option(
"-d",
"--display",
default=1,
type=int,
help="Specify display number as an integer (default: 1).",
default="1",
type=str,
help="Specify display number as an integer or as X11 format like "
":display_num (default: 1).",
)
@click.option(
"-s",
Expand Down Expand Up @@ -111,7 +112,7 @@
"-t", "--trials", default=300, type=int, help="Specifies number of trials."
)
@click.option(
"-d",
"-x",
"--duration",
default=-1,
type=float,
Expand Down Expand Up @@ -140,7 +141,7 @@ def timesync_stimuli(
output_prefix: str,
windowed: bool,
win_size: tuple[int, int],
display: int,
display: str,
qr_scale: float,
qr_duration: float,
qr_async: bool,
Expand Down Expand Up @@ -177,6 +178,8 @@ def timesync_stimuli(
logger.debug(f" qr async : {qr_async}")
logger.debug(f" interval : {interval}")

display_num: int = int(display.lstrip(':'))

output: str = get_output_file_name(output_prefix, start_ts)
logger.debug(f" output : {output}")

Expand All @@ -192,7 +195,7 @@ def timesync_stimuli(
output,
is_fullscreen,
win_size,
display,
display_num,
qr_scale,
qr_duration,
qr_async,
Expand Down
3 changes: 2 additions & 1 deletion src/reprostim/qr/timesync_stimuli.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,9 +484,10 @@ def wait_or_keys(

if win.monitor:
logger.info(f"display [{display}] info:")
fr = win.getActualFrameRate()
logger.info(
f" {win.size[0]}x{win.size[1]} px, "
f"{round(win.getActualFrameRate(), 2)} Hz"
f" {round(fr, 2)} Hz" if fr else " N/A Hz"
)

# log script started event
Expand Down
56 changes: 56 additions & 0 deletions tools/ci/test_reprostim_events.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/bash

# Script to simulate pulse events using xdotool
# Usage: ./test_reprostim_events.sh NUM_SERIES SERIES_INTERVAL NUM_EVT EVT_INTERVAL [SLEEP_DELAY] [DISPLAY]
# Make sure to set DISPLAY if using Xvfb

NUM_SERIES="$1"
SERIES_INTERVAL="$2"
NUM_EVT="$3"
EVT_INTERVAL="$4"
SLEEP_DELAY="${5:-0}"
DISPLAY_PARAM="$6"

# Use passed-in DISPLAY if provided
if [[ -n "$DISPLAY_PARAM" ]]; then
export DISPLAY="$DISPLAY_PARAM"
fi

echo "DISPLAY is set to: $DISPLAY"

sleep "$SLEEP_DELAY"

# Validate inputs
if [ -z "$NUM_SERIES" ] || [ -z "$SERIES_INTERVAL" ] || [ -z "$NUM_EVT" ] || [ -z "$EVT_INTERVAL" ]; then
echo "Usage: $0 <number_of_series> <series_interval> <number_of_events> <events_interval> [<sleep_delay>] [<display>]"
exit 1
fi

start_time=$(date +%s)

for (( series=1; series<=NUM_SERIES; series++ )); do
echo "Starting series $series"
for (( event=1; event<=NUM_EVT; event++ )); do
echo "Sending pulse event $series.$event"
xdotool key 5
sleep "$EVT_INTERVAL"
done

if [ "$series" -lt "$NUM_SERIES" ]; then
echo "Waiting $SERIES_INTERVAL seconds before next series..."
sleep "$SERIES_INTERVAL"
fi
done

# Escape and quit the application
echo "Finishing up and send ESC q ESC..."
xdotool key Escape
sleep 0.2
xdotool key q
sleep 0.2
xdotool key Escape

end_time=$(date +%s)
dt=$(( end_time - start_time ))

echo "Done. Execution time: $dt seconds"
Loading