Stream Events
Monitor and respond to real-time stream events to create interactive and responsive video experiences. Handle stream lifecycle, viewer activities, broadcast status changes, and technical events.Overview
social.plus Video SDK provides comprehensive event handling for live streaming applications. Subscribe to events to update UI, trigger notifications, handle errors, and create interactive features.Event Categories
- Stream Lifecycle - Start, stop, pause, resume events
- Viewer Activity - Join, leave, engagement events
- Broadcast Status - Connection, quality, technical events
- Interactive Features - Chat, reactions, polls, screen sharing
- Recording Events - Start, stop, processing, completion
- Error Handling - Connection failures, stream errors, recovery
Event Types
Stream Lifecycle Events
| Event | Description | Payload |
|---|---|---|
stream.created | Stream session created | { streamId, title, scheduledTime } |
stream.started | Stream went live | { streamId, startTime, quality } |
stream.paused | Stream temporarily paused | { streamId, pauseTime, reason } |
stream.resumed | Stream resumed after pause | { streamId, resumeTime } |
stream.ended | Stream stopped | { streamId, endTime, duration, viewerCount } |
stream.deleted | Stream session deleted | { streamId, deletedAt } |
Viewer Activity Events
| Event | Description | Payload |
|---|---|---|
viewer.joined | Viewer joined stream | { streamId, viewerId, joinTime, viewerCount } |
viewer.left | Viewer left stream | { streamId, viewerId, leaveTime, duration, viewerCount } |
viewer.milestone | Viewer count milestone | { streamId, count, milestone, timestamp } |
viewer.engagement | Viewer interaction | { streamId, viewerId, action, timestamp } |
Broadcast Status Events
| Event | Description | Payload |
|---|---|---|
broadcast.connected | Broadcaster connected | { streamId, quality, bitrate, fps } |
broadcast.disconnected | Broadcaster disconnected | { streamId, reason, timestamp } |
broadcast.reconnecting | Attempting to reconnect | { streamId, attempt, maxAttempts } |
broadcast.quality_changed | Stream quality changed | { streamId, oldQuality, newQuality, reason } |
broadcast.error | Broadcasting error occurred | { streamId, error, severity, timestamp } |
Interactive Events
| Event | Description | Payload |
|---|---|---|
chat.message | Chat message sent | { streamId, message, sender, timestamp } |
reaction.added | Viewer reaction added | { streamId, reaction, viewerId, timestamp } |
poll.created | Poll created in stream | { streamId, poll, createdBy, timestamp } |
poll.voted | Vote cast in poll | { streamId, pollId, option, voterId, timestamp } |
screen.shared | Screen sharing started | { streamId, sharerDetails, timestamp } |
Recording Events
| Event | Description | Payload |
|---|---|---|
recording.started | Recording began | { streamId, recordingId, startTime, format } |
recording.stopped | Recording ended | { streamId, recordingId, endTime, duration } |
recording.processing | Recording being processed | { streamId, recordingId, progress, estimatedTime } |
recording.completed | Recording ready | { streamId, recordingId, url, duration, size } |
recording.failed | Recording failed | { streamId, recordingId, error, timestamp } |
Platform Implementation
- iOS
- Android
- React Native
- Flutter
- Web
Swift Event Handling
import SocialVideo
class StreamEventHandler: VideoStreamDelegate {
func setupEventListeners() {
// Stream lifecycle events
VideoStreamManager.shared.onStreamStarted = { streamData in
self.handleStreamStarted(streamData)
}
VideoStreamManager.shared.onStreamEnded = { streamData in
self.handleStreamEnded(streamData)
}
// Viewer activity events
VideoStreamManager.shared.onViewerJoined = { viewerData in
self.updateViewerCount(viewerData.viewerCount)
self.showViewerJoinedAnimation(viewerData.viewer)
}
// Broadcast status events
VideoStreamManager.shared.onBroadcastError = { error in
self.handleBroadcastError(error)
}
// Recording events
VideoStreamManager.shared.onRecordingStatusChanged = { status in
self.updateRecordingUI(status)
}
}
private func handleStreamStarted(_ streamData: StreamData) {
DispatchQueue.main.async {
self.liveIndicator.isHidden = false
self.liveIndicator.startAnimating()
self.viewerCountLabel.text = "0 viewers"
// Send analytics event
Analytics.track("stream_started", properties: [
"stream_id": streamData.id,
"quality": streamData.quality
])
}
}
private func handleStreamEnded(_ streamData: StreamData) {
DispatchQueue.main.async {
self.liveIndicator.isHidden = true
self.showStreamEndedScreen(streamData)
// Show stream statistics
self.presentStreamStats(
duration: streamData.duration,
viewerCount: streamData.maxViewers,
engagement: streamData.engagementRate
)
}
}
private func handleBroadcastError(_ error: BroadcastError) {
DispatchQueue.main.async {
switch error.severity {
case .critical:
self.showCriticalErrorAlert(error)
case .warning:
self.showWarningBanner(error)
case .info:
self.logInfo(error.message)
}
}
}
}
Kotlin Event Handling
import com.socialplus.video.VideoStreamManager
import com.socialplus.video.events.*
class StreamEventHandler : VideoStreamEventListener {
private val streamManager = VideoStreamManager.getInstance()
fun setupEventListeners() {
streamManager.addEventListener(this)
// Stream lifecycle
streamManager.setOnStreamStartedListener { streamData ->
handleStreamStarted(streamData)
}
streamManager.setOnStreamEndedListener { streamData ->
handleStreamEnded(streamData)
}
// Viewer activity
streamManager.setOnViewerActivityListener { viewerEvent ->
when (viewerEvent.type) {
ViewerEventType.JOINED -> handleViewerJoined(viewerEvent)
ViewerEventType.LEFT -> handleViewerLeft(viewerEvent)
ViewerEventType.MILESTONE -> handleViewerMilestone(viewerEvent)
}
}
// Broadcast status
streamManager.setOnBroadcastStatusListener { status ->
handleBroadcastStatusChange(status)
}
}
private fun handleStreamStarted(streamData: StreamData) {
runOnUiThread {
liveIndicator.visibility = View.VISIBLE
liveIndicator.startAnimation()
// Update UI
updateStreamInfo(streamData)
// Track analytics
Analytics.track("stream_started", mapOf(
"stream_id" to streamData.id,
"quality" to streamData.quality,
"platform" to "android"
))
}
}
private fun handleViewerJoined(viewerEvent: ViewerEvent) {
runOnUiThread {
// Update viewer count
viewerCountText.text = "${viewerEvent.viewerCount} viewers"
// Show join animation
showViewerJoinAnimation(viewerEvent.viewer)
// Update viewer list if showing
if (viewerListVisible) {
viewerAdapter.addViewer(viewerEvent.viewer)
}
}
}
private fun handleBroadcastStatusChange(status: BroadcastStatus) {
runOnUiThread {
when (status.state) {
BroadcastState.CONNECTED -> {
connectionIndicator.setImageResource(R.drawable.ic_connected)
qualityText.text = status.quality
}
BroadcastState.RECONNECTING -> {
connectionIndicator.setImageResource(R.drawable.ic_reconnecting)
showReconnectingMessage()
}
BroadcastState.FAILED -> {
connectionIndicator.setImageResource(R.drawable.ic_error)
handleConnectionFailure(status.error)
}
}
}
}
override fun onEvent(event: VideoStreamEvent) {
when (event.type) {
EventType.CHAT_MESSAGE -> handleChatMessage(event as ChatMessageEvent)
EventType.REACTION_ADDED -> handleReaction(event as ReactionEvent)
EventType.POLL_CREATED -> handlePollCreated(event as PollEvent)
EventType.RECORDING_STATUS -> handleRecordingStatus(event as RecordingEvent)
}
}
}
React Native Event Handling
import { VideoStreamManager, VideoStreamEvents } from '@social-plus/video-react-native';
import { useEffect, useState } from 'react';
export const StreamEventHandler = () => {
const [streamStatus, setStreamStatus] = useState('idle');
const [viewerCount, setViewerCount] = useState(0);
const [broadcastQuality, setBroadcastQuality] = useState('');
const [recordingStatus, setRecordingStatus] = useState('stopped');
useEffect(() => {
const streamManager = VideoStreamManager.getInstance();
// Stream lifecycle events
const streamStartedListener = streamManager.addListener(
VideoStreamEvents.STREAM_STARTED,
(streamData) => {
setStreamStatus('live');
console.log('Stream started:', streamData);
// Update UI
setStreamInfo(streamData);
// Track analytics
Analytics.track('stream_started', {
stream_id: streamData.id,
quality: streamData.quality,
platform: 'react-native'
});
}
);
const streamEndedListener = streamManager.addListener(
VideoStreamEvents.STREAM_ENDED,
(streamData) => {
setStreamStatus('ended');
// Show stream summary
showStreamSummary(streamData);
}
);
// Viewer activity events
const viewerJoinedListener = streamManager.addListener(
VideoStreamEvents.VIEWER_JOINED,
(viewerData) => {
setViewerCount(viewerData.viewerCount);
// Show join animation
showViewerJoinAnimation(viewerData.viewer);
}
);
const viewerMilestoneListener = streamManager.addListener(
VideoStreamEvents.VIEWER_MILESTONE,
(milestoneData) => {
// Celebrate milestone
showMilestoneCelebration(milestoneData.count);
// Send push notification
sendMilestoneNotification(milestoneData);
}
);
// Broadcast status events
const broadcastStatusListener = streamManager.addListener(
VideoStreamEvents.BROADCAST_STATUS_CHANGED,
(statusData) => {
setBroadcastQuality(statusData.quality);
switch (statusData.state) {
case 'connected':
setConnectionStatus('stable');
break;
case 'reconnecting':
setConnectionStatus('reconnecting');
showReconnectingIndicator();
break;
case 'failed':
setConnectionStatus('failed');
handleConnectionFailure(statusData.error);
break;
}
}
);
// Interactive events
const chatMessageListener = streamManager.addListener(
VideoStreamEvents.CHAT_MESSAGE,
(messageData) => {
addChatMessage(messageData);
}
);
const reactionListener = streamManager.addListener(
VideoStreamEvents.REACTION_ADDED,
(reactionData) => {
showReactionAnimation(reactionData);
}
);
// Recording events
const recordingStatusListener = streamManager.addListener(
VideoStreamEvents.RECORDING_STATUS_CHANGED,
(recordingData) => {
setRecordingStatus(recordingData.status);
if (recordingData.status === 'completed') {
showRecordingReadyNotification(recordingData.url);
}
}
);
// Cleanup listeners
return () => {
streamStartedListener.remove();
streamEndedListener.remove();
viewerJoinedListener.remove();
viewerMilestoneListener.remove();
broadcastStatusListener.remove();
chatMessageListener.remove();
reactionListener.remove();
recordingStatusListener.remove();
};
}, []);
const handleConnectionFailure = (error) => {
Alert.alert(
'Connection Issue',
`Stream connection failed: ${error.message}`,
[
{ text: 'Retry', onPress: () => retryConnection() },
{ text: 'End Stream', onPress: () => endStream() }
]
);
};
const showMilestoneCelebration = (count) => {
// Trigger confetti animation
confettiRef.current?.start();
// Show milestone message
setMilestoneMessage(`🎉 ${count} viewers!`);
setTimeout(() => {
setMilestoneMessage('');
}, 3000);
};
return (
<StreamEventProvider>
{/* Your stream UI components */}
</StreamEventProvider>
);
};
Flutter Event Handling
import 'package:social_plus_video/video_stream_manager.dart';
import 'package:social_plus_video/events.dart';
class StreamEventHandler {
VideoStreamManager _streamManager = VideoStreamManager.instance;
StreamController<StreamEvent> _eventController = StreamController<StreamEvent>();
void setupEventListeners() {
// Stream lifecycle events
_streamManager.onStreamStarted.listen((StreamData streamData) {
_handleStreamStarted(streamData);
});
_streamManager.onStreamEnded.listen((StreamData streamData) {
_handleStreamEnded(streamData);
});
// Viewer activity events
_streamManager.onViewerJoined.listen((ViewerEvent viewerEvent) {
_handleViewerJoined(viewerEvent);
});
_streamManager.onViewerMilestone.listen((MilestoneEvent milestoneEvent) {
_handleViewerMilestone(milestoneEvent);
});
// Broadcast status events
_streamManager.onBroadcastStatusChanged.listen((BroadcastStatus status) {
_handleBroadcastStatusChange(status);
});
// Interactive events
_streamManager.onChatMessage.listen((ChatMessage message) {
_handleChatMessage(message);
});
_streamManager.onReactionAdded.listen((ReactionEvent reaction) {
_handleReaction(reaction);
});
// Recording events
_streamManager.onRecordingStatusChanged.listen((RecordingStatus status) {
_handleRecordingStatusChange(status);
});
// Error handling
_streamManager.onError.listen((VideoStreamError error) {
_handleStreamError(error);
});
}
void _handleStreamStarted(StreamData streamData) {
// Update UI state
setState(() {
isLive = true;
streamId = streamData.id;
streamQuality = streamData.quality;
});
// Show live indicator
_showLiveIndicator();
// Track analytics
Analytics.track('stream_started', {
'stream_id': streamData.id,
'quality': streamData.quality,
'platform': 'flutter'
});
}
void _handleViewerJoined(ViewerEvent viewerEvent) {
setState(() {
viewerCount = viewerEvent.viewerCount;
});
// Show join animation
_showViewerJoinAnimation(viewerEvent.viewer);
// Update viewer list
_updateViewerList(viewerEvent.viewer);
}
void _handleViewerMilestone(MilestoneEvent milestoneEvent) {
// Show milestone celebration
_showMilestoneCelebration(milestoneEvent.count);
// Send push notification to broadcaster
_sendMilestoneNotification(milestoneEvent);
// Track milestone achievement
Analytics.track('viewer_milestone', {
'stream_id': milestoneEvent.streamId,
'milestone': milestoneEvent.count,
'timestamp': milestoneEvent.timestamp
});
}
void _handleBroadcastStatusChange(BroadcastStatus status) {
setState(() {
broadcastStatus = status.state;
connectionQuality = status.quality;
});
switch (status.state) {
case BroadcastState.connected:
_showConnectionStableIndicator();
break;
case BroadcastState.reconnecting:
_showReconnectingIndicator();
break;
case BroadcastState.failed:
_handleConnectionFailure(status.error);
break;
}
}
void _handleStreamError(VideoStreamError error) {
switch (error.severity) {
case ErrorSeverity.critical:
_showCriticalErrorDialog(error);
break;
case ErrorSeverity.warning:
_showWarningSnackbar(error);
break;
case ErrorSeverity.info:
print('Stream info: ${error.message}');
break;
}
}
void _showMilestoneCelebration(int count) {
showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.celebration, size: 50, color: Colors.amber),
SizedBox(height: 16),
Text('🎉 $count viewers!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
Text('Amazing milestone achieved!'),
],
),
),
);
// Auto-dismiss after 3 seconds
Timer(Duration(seconds: 3), () {
Navigator.of(context).pop();
});
}
}
JavaScript/TypeScript Event Handling
import { VideoStreamManager, StreamEvent, StreamEventType } from '@social-plus/video-web';
class StreamEventHandler {
private streamManager: VideoStreamManager;
private eventListeners: Map<string, Function[]> = new Map();
constructor() {
this.streamManager = VideoStreamManager.getInstance();
this.setupEventListeners();
}
private setupEventListeners(): void {
// Stream lifecycle events
this.streamManager.on(StreamEventType.STREAM_STARTED, (streamData) => {
this.handleStreamStarted(streamData);
});
this.streamManager.on(StreamEventType.STREAM_ENDED, (streamData) => {
this.handleStreamEnded(streamData);
});
// Viewer activity events
this.streamManager.on(StreamEventType.VIEWER_JOINED, (viewerData) => {
this.handleViewerJoined(viewerData);
});
this.streamManager.on(StreamEventType.VIEWER_MILESTONE, (milestoneData) => {
this.handleViewerMilestone(milestoneData);
});
// Broadcast status events
this.streamManager.on(StreamEventType.BROADCAST_STATUS_CHANGED, (statusData) => {
this.handleBroadcastStatusChange(statusData);
});
// Interactive events
this.streamManager.on(StreamEventType.CHAT_MESSAGE, (messageData) => {
this.handleChatMessage(messageData);
});
this.streamManager.on(StreamEventType.REACTION_ADDED, (reactionData) => {
this.handleReaction(reactionData);
});
// Recording events
this.streamManager.on(StreamEventType.RECORDING_STATUS_CHANGED, (recordingData) => {
this.handleRecordingStatusChange(recordingData);
});
// Error handling
this.streamManager.on(StreamEventType.ERROR, (error) => {
this.handleStreamError(error);
});
}
private handleStreamStarted(streamData: StreamData): void {
// Update UI
this.updateLiveIndicator(true);
this.updateStreamInfo(streamData);
// Start viewer count updates
this.startViewerCountUpdates();
// Track analytics
this.trackEvent('stream_started', {
stream_id: streamData.id,
quality: streamData.quality,
platform: 'web'
});
// Show notification
this.showNotification('Stream is now live!', 'success');
}
private handleViewerJoined(viewerData: ViewerData): void {
// Update viewer count display
this.updateViewerCount(viewerData.viewerCount);
// Show join animation
this.showViewerJoinAnimation(viewerData.viewer);
// Update viewer list
this.updateViewerList(viewerData.viewer);
// Emit custom event for other components
this.emit('viewer_activity', viewerData);
}
private handleViewerMilestone(milestoneData: MilestoneData): void {
// Show milestone celebration
this.showMilestoneCelebration(milestoneData.count);
// Trigger confetti effect
this.triggerConfetti();
// Send milestone notification
this.sendMilestoneNotification(milestoneData);
// Track milestone
this.trackEvent('viewer_milestone', milestoneData);
}
private handleBroadcastStatusChange(statusData: BroadcastStatusData): void {
const statusIndicator = document.getElementById('connection-status');
switch (statusData.state) {
case 'connected':
statusIndicator?.classList.add('connected');
statusIndicator?.classList.remove('reconnecting', 'failed');
this.updateQualityIndicator(statusData.quality);
break;
case 'reconnecting':
statusIndicator?.classList.add('reconnecting');
statusIndicator?.classList.remove('connected', 'failed');
this.showReconnectingMessage();
break;
case 'failed':
statusIndicator?.classList.add('failed');
statusIndicator?.classList.remove('connected', 'reconnecting');
this.handleConnectionFailure(statusData.error);
break;
}
}
private handleChatMessage(messageData: ChatMessageData): void {
// Add message to chat UI
this.addChatMessage(messageData);
// Check for mentions or special commands
if (messageData.mentions?.includes(this.currentUserId)) {
this.handleMention(messageData);
}
// Emit for other components
this.emit('chat_message', messageData);
}
private handleReaction(reactionData: ReactionData): void {
// Show reaction animation
this.showReactionAnimation(reactionData);
// Update reaction counts
this.updateReactionCounts(reactionData);
// Track engagement
this.trackEvent('viewer_reaction', reactionData);
}
private handleStreamError(error: StreamError): void {
console.error('Stream error:', error);
switch (error.severity) {
case 'critical':
this.showCriticalErrorModal(error);
break;
case 'warning':
this.showWarningToast(error);
break;
case 'info':
console.info('Stream info:', error.message);
break;
}
// Track error
this.trackEvent('stream_error', error);
}
private showMilestoneCelebration(count: number): void {
const celebration = document.createElement('div');
celebration.className = 'milestone-celebration';
celebration.innerHTML = `
<div class="milestone-content">
<div class="milestone-icon">🎉</div>
<div class="milestone-text">${count} viewers!</div>
<div class="milestone-subtext">Amazing milestone achieved!</div>
</div>
`;
document.body.appendChild(celebration);
// Animate in
setTimeout(() => celebration.classList.add('show'), 100);
// Remove after 3 seconds
setTimeout(() => {
celebration.classList.remove('show');
setTimeout(() => celebration.remove(), 500);
}, 3000);
}
private triggerConfetti(): void {
// Create confetti animation
const confetti = document.createElement('div');
confetti.className = 'confetti-container';
document.body.appendChild(confetti);
// Generate confetti particles
for (let i = 0; i < 50; i++) {
const particle = document.createElement('div');
particle.className = 'confetti-particle';
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = Math.random() * 2 + 's';
particle.style.backgroundColor = this.getRandomColor();
confetti.appendChild(particle);
}
// Clean up after animation
setTimeout(() => confetti.remove(), 4000);
}
// Event emitter methods
public on(event: string, callback: Function): void {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, []);
}
this.eventListeners.get(event)!.push(callback);
}
private emit(event: string, data: any): void {
const listeners = this.eventListeners.get(event);
if (listeners) {
listeners.forEach(callback => callback(data));
}
}
}
Advanced Event Patterns
Event Aggregation
// Aggregate multiple events for batch processing
class EventAggregator {
private events: StreamEvent[] = [];
private timer: NodeJS.Timeout | null = null;
addEvent(event: StreamEvent): void {
this.events.push(event);
// Batch process events every 5 seconds
if (!this.timer) {
this.timer = setTimeout(() => {
this.processEvents();
this.timer = null;
}, 5000);
}
}
private processEvents(): void {
// Group events by type
const eventGroups = this.events.reduce((groups, event) => {
const type = event.type;
if (!groups[type]) groups[type] = [];
groups[type].push(event);
return groups;
}, {} as Record<string, StreamEvent[]>);
// Process each group
Object.entries(eventGroups).forEach(([type, events]) => {
this.processBatchedEvents(type, events);
});
// Clear processed events
this.events = [];
}
}
Event Filtering
// Filter events based on conditions
class EventFilter {
private filters: Map<string, (event: StreamEvent) => boolean> = new Map();
addFilter(name: string, filter: (event: StreamEvent) => boolean): void {
this.filters.set(name, filter);
}
shouldProcessEvent(event: StreamEvent): boolean {
// Check all filters
for (const [name, filter] of this.filters) {
if (!filter(event)) {
console.log(`Event filtered out by ${name}`);
return false;
}
}
return true;
}
}
// Usage
const eventFilter = new EventFilter();
// Only process events for active streams
eventFilter.addFilter('active_streams', (event) => {
return activeStreamIds.includes(event.streamId);
});
// Skip viewer join events during high traffic
eventFilter.addFilter('high_traffic', (event) => {
if (event.type === 'viewer.joined' && currentViewerCount > 1000) {
return false;
}
return true;
});
Event Persistence
// Store events for replay or analysis
class EventStore {
private events: StoredEvent[] = [];
async storeEvent(event: StreamEvent): Promise<void> {
const storedEvent: StoredEvent = {
...event,
id: generateId(),
timestamp: Date.now(),
processed: false
};
// Store in database
await this.database.events.create(storedEvent);
this.events.push(storedEvent);
}
async getEventsForStream(streamId: string): Promise<StoredEvent[]> {
return this.database.events.find({ streamId });
}
async replayEvents(streamId: string, fromTimestamp: number): Promise<void> {
const events = await this.getEventsForStream(streamId);
const replayEvents = events.filter(e => e.timestamp >= fromTimestamp);
for (const event of replayEvents) {
await this.processEvent(event);
}
}
}
Error Handling
Comprehensive Error Management
class StreamErrorHandler {
private errorHandlers: Map<string, (error: StreamError) => void> = new Map();
constructor() {
this.setupDefaultHandlers();
}
private setupDefaultHandlers(): void {
// Connection errors
this.errorHandlers.set('connection.failed', (error) => {
this.handleConnectionError(error);
});
// Stream errors
this.errorHandlers.set('stream.error', (error) => {
this.handleStreamError(error);
});
// Viewer errors
this.errorHandlers.set('viewer.error', (error) => {
this.handleViewerError(error);
});
}
private handleConnectionError(error: StreamError): void {
// Attempt automatic recovery
if (error.recoverable) {
this.attemptRecovery(error);
} else {
// Show error to user
this.showErrorMessage('Connection lost. Please check your internet connection.');
}
}
private async attemptRecovery(error: StreamError): Promise<void> {
const maxRetries = 3;
let retryCount = 0;
while (retryCount < maxRetries) {
try {
await this.reconnect();
this.showSuccessMessage('Connection restored');
return;
} catch (retryError) {
retryCount++;
await this.delay(2000 * retryCount); // Exponential backoff
}
}
// Recovery failed
this.showErrorMessage('Unable to restore connection. Please restart the stream.');
}
}
Testing Events
Event Testing Utilities
// Mock event generator for testing
class MockEventGenerator {
private streamId: string;
private intervalId: NodeJS.Timeout | null = null;
constructor(streamId: string) {
this.streamId = streamId;
}
startSimulation(): void {
this.intervalId = setInterval(() => {
this.generateRandomEvent();
}, 2000);
}
stopSimulation(): void {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
private generateRandomEvent(): void {
const eventTypes = [
'viewer.joined',
'viewer.left',
'chat.message',
'reaction.added',
'quality.changed'
];
const randomType = eventTypes[Math.floor(Math.random() * eventTypes.length)];
const mockEvent = this.createMockEvent(randomType);
// Emit the mock event
VideoStreamManager.getInstance().emit(randomType, mockEvent);
}
private createMockEvent(type: string): StreamEvent {
switch (type) {
case 'viewer.joined':
return {
type,
streamId: this.streamId,
viewerId: `viewer-${Date.now()}`,
viewerCount: Math.floor(Math.random() * 1000),
timestamp: Date.now()
};
case 'chat.message':
return {
type,
streamId: this.streamId,
message: this.generateRandomMessage(),
sender: `user-${Math.floor(Math.random() * 100)}`,
timestamp: Date.now()
};
default:
return {
type,
streamId: this.streamId,
timestamp: Date.now()
};
}
}
}
Performance Considerations
Event Throttling: Use throttling for high-frequency events like viewer activity to prevent UI performance issues.
Event Throttling
// Throttle high-frequency events
class EventThrottler {
private lastEventTime: Map<string, number> = new Map();
private throttleIntervals: Map<string, number> = new Map();
constructor() {
// Set throttle intervals for different event types
this.throttleIntervals.set('viewer.joined', 1000); // 1 second
this.throttleIntervals.set('viewer.left', 1000);
this.throttleIntervals.set('quality.changed', 5000); // 5 seconds
}
shouldProcessEvent(event: StreamEvent): boolean {
const eventKey = `${event.type}-${event.streamId}`;
const now = Date.now();
const lastTime = this.lastEventTime.get(eventKey) || 0;
const throttleInterval = this.throttleIntervals.get(event.type) || 0;
if (now - lastTime >= throttleInterval) {
this.lastEventTime.set(eventKey, now);
return true;
}
return false;
}
}
Best Practices
Event Handling Strategy
- Prioritize Critical Events - Stream start/end, connection failures
- Batch Non-Critical Events - Viewer activity, chat messages
- Implement Retry Logic - For failed event processing
- Use Event Aggregation - Reduce processing overhead
- Store Important Events - For analytics and replay
Performance Optimization
- Throttle High-Frequency Events - Prevent UI blocking
- Debounce Rapid Events - Batch similar events
- Use Background Processing - For non-UI critical events
- Implement Event Queuing - Handle event bursts
- Monitor Event Volume - Track processing performance
Error Recovery
- Graceful Degradation - Continue operation when non-critical events fail
- Automatic Retry - For transient failures
- User Feedback - Clear error messages and recovery options
- Fallback Mechanisms - Alternative event sources when primary fails
Next Steps
- Push Notifications - Implement notification delivery
- Broadcasting Setup - Configure event-driven broadcasting
- Platform Guides: Implementation details:
- Troubleshooting - Debug event handling issues
Event Volume: High-traffic streams can generate thousands of events per minute. Implement appropriate throttling, batching, and filtering to maintain performance.