Media Download Synchronization Feature#
Overview#
This feature ensures fair gameplay by tracking when players have downloaded media content for questions. The game displays visual indicators on player cards showing the download status of each player.
Event Flow Diagram#
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Player 1 │ │ Server │ │ Player 2 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ 1. Showman picks question │ │
│ ─────────────────────────────────>│ │
│ │ │
│ 2. QUESTION_DATA event │ 2. QUESTION_DATA event │
│ <─────────────────────────────────┤──────────────────────────────────>│
│ (mediaDownloaded: false) │ (mediaDownloaded: false) │
│ │ │
│ 3. Download/Load media │ │ 3. Download/Load media
│ ⏳ │ │ ⏳
│ │ │
│ 4. MEDIA_DOWNLOADED │ │
│ ─────────────────────────────────>│ │
│ │ │
│ 5. MEDIA_DOWNLOAD_STATUS │ 5. MEDIA_DOWNLOAD_STATUS │
│ <─────────────────────────────────┤──────────────────────────────────>│
│ (player1: true, allReady: false) (player1: true, allReady: false) │
│ │ │
│ UI: ✓ Player 1 │ │ UI: ✓ Player 1
│ ⏳ Player 2 │ │ ⏳ Player 2
│ │ │
│ │ 6. MEDIA_DOWNLOADED │
│ │ <─────────────────────────────────│
│ │ │
│ 7. MEDIA_DOWNLOAD_STATUS │ 7. MEDIA_DOWNLOAD_STATUS │
│ <─────────────────────────────────┤──────────────────────────────────>│
│ (player2: true, allReady: true) (player2: true, allReady: true) │
│ │ │
│ UI: ✓ Player 1 │ │ UI: ✓ Player 1
│ ✓ Player 2 │ │ ✓ Player 2
│ │ │
│ 8. Start media playback │ │ 8. Start media playback
│ ▶️ │ │ ▶️
│ │ │
Legend:
✓ = Green check (downloaded)
⏳ = Orange downloading icon
▶️ = Media playback starts after all players readyHow It Works#
Backend (Server)#
Player State Tracking
- Added
mediaDownloadedfield toPlayerDTOandPlayerentity - Tracks whether each player has downloaded the current question’s media
- Added
Socket.IO Events
MEDIA_DOWNLOADED: Sent by client when media download completesMEDIA_DOWNLOAD_STATUS: Broadcast to all clients with player’s download status
Event Flow
- When a question is picked, all players’
mediaDownloadedstatus is reset tofalse - Client downloads/loads media and sends
MEDIA_DOWNLOADEDevent - Server broadcasts
MEDIA_DOWNLOAD_STATUSto all clients withallPlayersReadyflag - All clients update their UI to show which players have downloaded media
- When
allPlayersReadyistrue, clients start media playback synchronously
- When a question is picked, all players’
Frontend (Client)#
Media Download Detection
- After media (video/audio/image) is loaded, client sends
MEDIA_DOWNLOADEDevent - For questions without media, event is sent immediately
- Media is prepared but NOT played until all players are ready
- After media (video/audio/image) is loaded, client sends
Synchronized Playback
- Client waits for
allPlayersReadysignal from server - Only when all active players have downloaded media does playback start
- Ensures fair gameplay where all players see content simultaneously
- Client waits for
Visual Indicators
- Orange downloading icon: Player is still downloading media
- Green check icon: Player has downloaded media
- Indicators only shown when active question has media
State Management
- Player download status is stored in game state
- Status is reset when new question is picked
- UI reactively updates based on status changes
Files Modified#
Backend#
server/src/domain/enums/SocketIOEvents.ts- Added new event enumsMEDIA_DOWNLOADED = "media-downloaded", // Client -> Server MEDIA_DOWNLOAD_STATUS = "media-download-status", // Server -> All Clientsserver/src/domain/types/dto/game/player/PlayerDTO.ts- Added mediaDownloaded fieldserver/src/domain/entities/game/Player.ts- Added media download trackingserver/src/domain/handlers/socket/game/MediaDownloadedEventHandler.ts- New handlerserver/src/application/services/socket/SocketIOQuestionService.ts- Added media download methodshandleMediaDownloaded(socketId)- Handles incoming media downloaded eventresetMediaDownloadStatus(game)- Resets all players’ status
server/src/domain/handlers/socket/SocketEventHandlerFactory.ts- Registered handlerserver/src/domain/types/socket/events/game/MediaDownloadStatusEventPayload.ts- Event payload typeinterface MediaDownloadStatusBroadcastData { playerId: number; mediaDownloaded: boolean; allPlayersReady: boolean; }openapi/schema.json- Updated OpenAPI schema
Frontend#
client/lib/src/features/game_question/controllers/game_question_controller.dart- Send media downloaded event- Calls
notifyMediaDownloaded()after media loads or immediately if no media
- Calls
client/lib/src/features/game_lobby/controllers/game_lobby_controller.dart- Handle status eventsnotifyMediaDownloaded()- Emits MEDIA_DOWNLOADED event to server_onMediaDownloadStatus()- Updates player state when receiving status broadcasts usingMediaDownloadStatusEventPayloadmodel
client/lib/src/features/game_lobby/view/game_lobby_player.dart- Visual indicators_MediaDownloadIndicatorwidget shows download status icons
openapi/dart_sdk/lib/src/models/media_download_status_event_payload.dart- Event payload model (temporary manual implementation)- This file should be replaced when running
./oqhelper gen_files(from client directory) to regenerate the full SDK from OpenAPI schema
- This file should be replaced when running
API Usage Examples#
Client-Side (Dart/Flutter)#
// Emit media downloaded event (done automatically by GameQuestionController)
socket?.emit(SocketIOGameSendEvents.mediaDownloaded.json!);
// Listen for status updates (handled in GameLobbyController)
socket?.on(SocketIOGameReceiveEvents.mediaDownloadStatus.json!, (data) {
final statusData = MediaDownloadStatusEventPayload.fromJson(
data as Map<String, dynamic>,
);
// Access typed fields
final playerId = statusData.playerId;
final mediaDownloaded = statusData.mediaDownloaded;
final allPlayersReady = statusData.allPlayersReady;
// Update UI
});Server-Side (TypeScript)#
// The handler automatically:
// 1. Marks player as downloaded
// 2. Checks if all players are ready
// 3. Broadcasts status to all clients
await socketIOQuestionService.handleMediaDownloaded(socketId);
// Reset status when new question is picked
socketIOQuestionService.resetMediaDownloadStatus(game);Future Enhancements#
The current implementation provides visual feedback but doesn’t enforce waiting. Potential enhancements:
- Timeout Implementation: Add a 10-second timeout after which the question proceeds regardless of download status
- Content Hiding: Don’t show question content until all players are ready (or timeout)
- Progress Indicators: Show download progress percentage instead of just status
- Skip Option: Allow showman to skip waiting for specific players