Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions bin/deploy_to_balena.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ print_help() {
echo "Usage: deploy_to_balena.sh [options]"
echo "Options:"
echo " -h, --help show this help message and exit"
echo " -b, --board BOARD specify the board to build for (pi1, pi2, pi3, pi4, pi5)"
echo " -b, --board BOARD specify the board to build for (pi1, pi2, pi3, pi4, pi5, x86)"
echo " -f, --fleet FLEET specify the fleet name to deploy to"
echo " -s, --short-hash HASH specify the short hash to use for the image tag"
echo " -d, --dev run in dev mode"
Expand All @@ -23,7 +23,7 @@ while [[ $# -gt 0 ]]; do
-b|--board)
export BOARD="$2"

if [[ $BOARD =~ ^(pi1|pi2|pi3|pi4|pi5)$ ]]; then
if [[ $BOARD =~ ^(pi1|pi2|pi3|pi4|pi5|x86)$ ]]; then
echo "Building for $BOARD"
else
echo "Invalid board $BOARD"
Expand Down Expand Up @@ -91,7 +91,7 @@ function prepare_balena_file() {
cat docker-compose.balena.yml.tmpl | \
envsubst > balena-deploy/docker-compose.yml

if [[ "$BOARD" == "pi5" ]]; then
if [[ $BOARD =~ ^(pi5|x86)$ ]]; then
sed -i '/devices:/ {N; /\n.*\/dev\/vchiq:\/dev\/vchiq/d}' \
balena-deploy/docker-compose.yml
fi
Expand All @@ -118,7 +118,7 @@ else
cat docker-compose.balena.dev.yml.tmpl | \
envsubst > docker-compose.yml

if [[ "$BOARD" == "pi5" ]]; then
if [[ $BOARD =~ ^(pi5|x86)$ ]]; then
sed -i '/devices:/ {N; /\n.*\/dev\/vchiq:\/dev\/vchiq/d}' \
docker-compose.yml
fi
Expand Down
73 changes: 64 additions & 9 deletions bin/start_viewer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,77 @@ trap '' 16
# Disable swapping
echo 0 > /sys/fs/cgroup/memory/memory.swappiness

if [ "$DEVICE_TYPE" = "x86" ]; then
# Clean up any stale X server processes and lock files
pkill Xorg
rm -f /tmp/.X0-lock /tmp/.X11-unix/X0

# Start X server with dummy video driver and cursor disabled
export DISPLAY=:0
Xorg "$DISPLAY" -s 0 dpms -nocursor &
XORG_PID=$!

# Wait for X server to be ready with timeout
TIMEOUT=30
TIMEOUT_COUNT=0
while [ $TIMEOUT_COUNT -lt $TIMEOUT ]; do
if xset -display :0 q > /dev/null 2>&1; then
echo "X server is ready"
break
fi

# Check if X server process is still running
if ! kill -0 $XORG_PID 2>/dev/null; then
echo "X server failed to start"
exit 1
fi

echo "Waiting for X server to be ready (${TIMEOUT_COUNT}/${TIMEOUT}s)"
sleep 1
TIMEOUT_COUNT=$((TIMEOUT_COUNT + 1))
done

if [ $TIMEOUT_COUNT -eq $TIMEOUT ]; then
echo "X server failed to start within $TIMEOUT seconds"
exit 1
fi

# Now that X is ready, configure display settings
xset -display "$DISPLAY" s off
xset -display "$DISPLAY" s noblank
xset -display "$DISPLAY" -dpms

# Hide cursor immediately after X server is ready
xset -display "$DISPLAY" -cursor_name left_ptr
# Alternative: completely hide cursor
xset -display "$DISPLAY" -cursor_name none
fi

# Start viewer
sudo -E -u viewer dbus-run-session python -m viewer &
VIEWER_PID=$!

# Wait for the viewer
while true; do
PID=$(pidof python)
if [ "$?" == '0' ]; then
break
fi
sleep 0.5
# Wait for the viewer with timeout
TIMEOUT=30
TIMEOUT_COUNT=0
while [ $TIMEOUT_COUNT -lt $TIMEOUT ]; do
if kill -0 $VIEWER_PID 2>/dev/null; then
break
fi
echo "Waiting for viewer to start (${TIMEOUT_COUNT}/${TIMEOUT}s)"
sleep 1
TIMEOUT_COUNT=$((TIMEOUT_COUNT + 1))
done

if [ $TIMEOUT_COUNT -eq $TIMEOUT ]; then
echo "Viewer failed to start within $TIMEOUT seconds"
exit 1
fi

# If the viewer runs OOM, force the OOM killer to kill this script so the container restarts
echo 1000 > /proc/$$/oom_score_adj

# Exit when the viewer stops
while kill -0 "$PID"; do
sleep 1
while kill -0 "$VIEWER_PID"; do
sleep 1
done
6 changes: 5 additions & 1 deletion docker/Dockerfile.viewer.j2
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ RUN curl "{{webview_base_url}}/webview-{{qt_version}}-{{debian_version}}-{{board
curl "{{webview_base_url}}/webview-{{qt_version}}-{{debian_version}}-{{board}}-{{webview_git_hash}}.tar.gz.sha256" \
-sL -o "/tmp/webview-{{qt_version}}-{{debian_version}}-{{board}}-{{webview_git_hash}}.tar.gz.sha256" && \
cd /tmp && \
sha256sum -c "webview-{{qt_version}}-{{debian_version}}-{{board}}-{{webview_git_hash}}.tar.gz.sha256" && \
tar -xzf "/tmp/webview-{{qt_version}}-{{debian_version}}-{{board}}-{{webview_git_hash}}.tar.gz" -C /usr/local && \
rm "webview-{{qt_version}}-{{debian_version}}-{{board}}-{{webview_git_hash}}.tar.gz"

ENV QT_QPA_EGLFS_FORCE888=1
{% if board == 'x86' %}
ENV QT_QPA_PLATFORM=xcb
ENV DISPLAY=:0
{% else %}
ENV QT_QPA_PLATFORM=linuxfb
{% endif %}

# Turn on debug logging for now
#ENV QT_LOGGING_RULES=qt.qpa.*=true
Expand Down
9 changes: 8 additions & 1 deletion static/src/components/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
selectActiveAssets,
selectInactiveAssets,
} from '@/store/assets'
import { AssetEditData, AppDispatch } from '@/types'
import { fetchDeviceModel } from '@/store/settings'
import { AssetEditData, AppDispatch, RootState } from '@/types'

import { EmptyAssetMessage } from '@/components/empty-asset-message'
import { InactiveAssetsTable } from '@/components/inactive-assets'
Expand All @@ -24,6 +25,8 @@
const [assetToEdit, setAssetToEdit] = useState<AssetEditData | null>(null)
const [playerName, setPlayerName] = useState('')

const { deviceModel } = useSelector((state: RootState) => state.settings)

Check failure on line 28 in static/src/components/home.tsx

View workflow job for this annotation

GitHub Actions / lint

'deviceModel' is assigned a value but never used

const fetchPlayerName = async () => {
try {
const response = await fetch('/api/v2/device_settings')
Expand All @@ -41,6 +44,10 @@
fetchPlayerName()
}, [dispatch, playerName])

useEffect(() => {
dispatch(fetchDeviceModel())
}, [dispatch])

// Initialize tooltips
useEffect(() => {
const tooltipElements: Tooltip[] = []
Expand Down
9 changes: 9 additions & 0 deletions tools/image_builder/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ def get_viewer_context(board: str) -> dict:
]

if board in ['pi5', 'x86']:
if board == 'x86':
apt_dependencies.extend([
'xserver-xorg-core',
'xserver-xorg-video-fbdev',
'x11-xserver-utils',
'xauth',
'xinit',
])

apt_dependencies.extend([
'qt6-base-dev',
'qt6-webengine-dev',
Expand Down
37 changes: 23 additions & 14 deletions viewer/media_player.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import unicode_literals

from os import getenv

import sh
import vlc

Expand All @@ -25,6 +27,23 @@ def stop(self):
def is_playing(self):
raise NotImplementedError

def get_alsa_audio_device(self):
if settings['audio_output'] == 'local':
if get_device_type() == 'pi5':
return 'default:CARD=vc4hdmi0'
elif get_device_type() == 'x86':
return 'default:CARD=HID'
return 'plughw:CARD=Headphones'
else:
if get_device_type() in ['pi4', 'pi5']:
return 'default:CARD=vc4hdmi0'
elif get_device_type() in ['pi1', 'pi2', 'pi3']:
return 'default:CARD=vc4hdmi'
elif get_device_type() == 'x86':
return 'hdmi:CARD=PCH'
else:
return 'default:CARD=HID'


class FFMPEGMediaPlayer(MediaPlayer):
def __init__(self):
Expand All @@ -38,6 +57,10 @@ def set_asset(self, uri, duration):
self.player_kwargs = {
'_bg': True,
'_ok_code': [0, 124],
'_env': {
'AUDIODEV': self.get_alsa_audio_device(),
'DISPLAY': getenv('DISPLAY', ':0')
}
}

def play(self):
Expand Down Expand Up @@ -66,20 +89,6 @@ def __init__(self):

self.player.audio_output_set('alsa')

def get_alsa_audio_device(self):
if settings['audio_output'] == 'local':
if get_device_type() == 'pi5':
return 'default:CARD=vc4hdmi0'

return 'plughw:CARD=Headphones'
else:
if get_device_type() in ['pi4', 'pi5']:
return 'default:CARD=vc4hdmi0'
elif get_device_type() in ['pi1', 'pi2', 'pi3']:
return 'default:CARD=vc4hdmi'
else:
return 'default:CARD=HID'

def __get_options(self):
return [
f'--alsa-audio-device={self.get_alsa_audio_device()}',
Expand Down
Loading