Live Streaming Complete - nself-org/nchat GitHub Wiki
Version: v0.4.0 Status: ✅ Complete Date: January 30, 2026
nself-chat (nchat) now includes a complete live streaming system with HLS playback, WebRTC ingest, adaptive bitrate streaming, live chat, emoji reactions, and comprehensive analytics. This implementation provides a production-ready streaming solution comparable to Twitch, YouTube Live, or Facebook Live.
- ✅ WebRTC Broadcast - Low-latency video/audio ingest from browser
- ✅ HLS Playback - Adaptive bitrate streaming with wide device compatibility
- ✅ Quality Selection - Auto, 1080p, 720p, 480p, 360p with manual and automatic switching
- ✅ Low-Latency Mode - <5 second latency for real-time interactions
- ✅ Stream Scheduling - Schedule streams for future broadcast
- ✅ Stream Recording - Automatic recording with replay functionality
- ✅ Live Chat - Real-time messaging during streams with rate limiting
- ✅ Emoji Reactions - Animated floating reactions with position control
- ✅ Q&A Mode - Optional question and answer sessions
- ✅ Chat Moderation - Pin, delete, and moderate chat messages
- ✅ Chat Modes - Open, followers-only, subscribers-only, or disabled
- ✅ Viewer Metrics - Real-time viewer count, peak viewers, total views
- ✅ Quality Metrics - Bitrate, FPS, resolution, dropped frames tracking
- ✅ Network Metrics - Latency, bandwidth, packet loss monitoring
- ✅ Engagement Metrics - Chat rate, reaction rate, average watch time
- ✅ Health Scoring - Real-time stream health assessment (0-100)
- ✅ EWMA Estimation - Exponentially weighted moving average bandwidth estimation
- ✅ Buffer-Based ABR - Quality selection based on buffer health
- ✅ Quality Switching - Intelligent upgrade/downgrade with cooldown periods
- ✅ Bitrate Limits - Configurable min/max bitrate constraints
| Component | Technology | Purpose |
|---|---|---|
| Video Ingest | WebRTC | Browser-based broadcasting |
| Media Processing | Ant Media Server / NGINX-RTMP | Transcoding & packaging |
| Playback | HLS.js | Adaptive streaming player |
| Database | PostgreSQL | Stream metadata & analytics |
| Real-time | Socket.io | Chat, reactions, viewer counts |
| Frontend | React 19 + Next.js 15 | UI components |
┌─────────────┐ WebRTC ┌──────────────┐ HLS ┌────────────┐
│ Broadcaster ├─────────────────→│ Media Server ├──────────→│ Viewers │
└─────────────┘ └──────────────┘ └────────────┘
│ │ │
│ │ │
↓ ↓ ↓
┌─────────────────────────────────────────────────────────────────────┐
│ PostgreSQL + Socket.io │
│ (Metadata, Chat, Reactions, Analytics, Presence) │
└─────────────────────────────────────────────────────────────────────┘
Primary stream metadata table.
CREATE TABLE nchat_streams (
id UUID PRIMARY KEY,
channel_id UUID NOT NULL,
broadcaster_id UUID NOT NULL,
-- Details
title VARCHAR(200) NOT NULL,
description TEXT,
thumbnail_url TEXT,
-- Scheduling
scheduled_at TIMESTAMPTZ,
started_at TIMESTAMPTZ,
ended_at TIMESTAMPTZ,
-- Status
status VARCHAR(20) CHECK (status IN ('scheduled', 'preparing', 'live', 'ended', 'cancelled')),
-- Configuration
stream_key VARCHAR(255) UNIQUE NOT NULL,
ingest_url TEXT NOT NULL,
hls_manifest_url TEXT,
max_resolution VARCHAR(10) DEFAULT '1080p',
-- Statistics
peak_viewer_count INTEGER DEFAULT 0,
total_view_count INTEGER DEFAULT 0,
total_chat_messages INTEGER DEFAULT 0,
total_reactions INTEGER DEFAULT 0,
-- Features
enable_chat BOOLEAN DEFAULT TRUE,
enable_reactions BOOLEAN DEFAULT TRUE,
chat_mode VARCHAR(20) DEFAULT 'open'
);Tracks individual viewer sessions.
Time-series quality and performance metrics.
Live chat messages with moderation support.
Emoji reactions with animation positions.
-
nchat_live_streams- Currently live streams with viewer counts -
nchat_top_streams- Top 100 streams by peak viewers
POST /api/streams/create
Body: {
channelId: string
title: string
description?: string
thumbnailUrl?: string
scheduledAt?: string (ISO 8601)
maxResolution?: '1080p' | '720p' | '480p' | '360p'
enableChat?: boolean
enableReactions?: boolean
enableQa?: boolean
chatMode?: 'open' | 'followers' | 'subscribers' | 'disabled'
tags?: string[]
}
Response: StreamGET / api / streams / [id]
Response: StreamPATCH / api / streams / [id]
Body: Partial<Stream>
Response: StreamDELETE / api / streams / [id]
Response: {
success: true
}POST /api/streams/[id]/start
Response: Stream (status: 'live', hls_manifest_url populated)POST /api/streams/[id]/end
Response: Stream (status: 'ended', with final statistics)GET /api/streams/[id]/chat?limit=100&offset=0
Response: StreamChatMessage[]POST /api/streams/[id]/chat
Body: {
content: string (max 500 chars)
}
Response: StreamChatMessagePOST /api/streams/[id]/reactions
Body: {
emoji: string
positionX?: number (0-100)
positionY?: number (0-100)
}
Response: StreamReactionimport { useLiveStream } from '@/hooks/use-live-stream'
const {
// State
stream,
isCreating,
isStarting,
isBroadcasting,
isEnding,
localStream,
connectionState,
qualityMetrics,
viewerCount,
duration,
error,
// Actions
createStream,
startBroadcast,
stopBroadcast,
endStream,
switchCamera,
switchMicrophone,
changeQuality,
toggleVideo,
toggleAudio,
// Devices
availableCameras,
availableMicrophones,
} = useLiveStream({
onStreamCreated: (stream) => console.log('Stream created:', stream),
onStreamStarted: (stream) => console.log('Now live:', stream),
onStreamEnded: (stream) => console.log('Stream ended:', stream),
onError: (error) => console.error('Stream error:', error),
})
// Create and start streaming
await createStream({
channelId: 'channel-uuid',
title: 'My First Stream',
description: 'Going live!',
maxResolution: '720p',
})
await startBroadcast('720p')
// End streaming
await endStream()import { useStreamViewer } from '@/hooks/use-stream-viewer'
const {
// State
stream,
isLoading,
isPlaying,
isPaused,
isBuffering,
currentQuality,
availableLevels,
stats,
viewerCount,
latency,
volume,
isMuted,
error,
// Actions
play,
pause,
setQuality,
setVolume,
setMuted,
goToLive,
// Refs
videoRef,
} = useStreamViewer({
streamId: 'stream-uuid',
autoStart: true,
lowLatencyMode: true,
onStreamEnded: () => console.log('Stream ended'),
onError: (error) => console.error('Viewer error:', error),
})
return (
<div>
<video ref={videoRef} className="w-full" />
<button onClick={isPlaying ? pause : play}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<select value={currentQuality} onChange={(e) => setQuality(e.target.value)}>
<option value="auto">Auto</option>
<option value="1080p">1080p</option>
<option value="720p">720p</option>
<option value="480p">480p</option>
<option value="360p">360p</option>
</select>
</div>
)import { useStreamChat } from '@/hooks/use-stream-chat'
const {
messages,
isLoading,
isSending,
error,
sendMessage,
deleteMessage,
pinMessage,
unpinMessage,
clear,
} = useStreamChat({
streamId: 'stream-uuid',
maxMessages: 100,
onNewMessage: (message) => console.log('New message:', message),
})
// Send message
await sendMessage('Hello world!')
// Moderate
await deleteMessage(messageId)
await pinMessage(messageId)import { useStreamReactions } from '@/hooks/use-stream-reactions'
const {
reactions,
recentReactions, // Last 20 for animation
isSending,
error,
sendReaction,
clearReactions,
} = useStreamReactions({
streamId: 'stream-uuid',
onNewReaction: (reaction) => console.log('New reaction:', reaction),
})
// Send reaction with position
await sendReaction('❤️', { x: 50, y: 0 })Full broadcaster UI with video preview, device selection, quality controls, and stream management.
import { StreamBroadcaster } from '@/components/streaming'
<StreamBroadcaster
channelId="channel-uuid"
onStreamEnded={() => console.log('Stream ended')}
/>Features:
- Video preview with local stream
- Camera/microphone device selection
- Quality preset selection (1080p, 720p, 480p, 360p)
- Live indicator with viewer count
- Duration timer
- Connection status
- Audio/video toggle controls
- Advanced settings panel
Full viewer UI with HLS player, quality selection, live chat, and reactions.
import { StreamViewer } from '@/components/streaming'
<StreamViewer
streamId="stream-uuid"
onStreamEnded={() => console.log('Stream ended')}
/>Features:
- HLS video player with adaptive bitrate
- Quality selection dropdown
- Volume controls
- Live indicator
- Viewer count display
- Latency indicator with "Go to Live" button
- Live chat panel
- Quick emoji reactions
- Animated floating reactions
# Stream Ingest URL (RTMP/WebRTC)
NEXT_PUBLIC_STREAM_INGEST_URL=rtmp://localhost:1935/live
# HLS Manifest Base URL
NEXT_PUBLIC_HLS_BASE_URL=http://localhost:8080/hls
# Recording
STREAM_RECORDING_ENABLED=true
STREAM_RECORDING_PATH=/var/recordingsfeatures: {
liveStreaming: true,
streamRecording: true,
streamChat: true,
streamReactions: true,
streamScheduling: true,
maxStreamDuration: 0, // 0 = unlimited, or set max minutes
}const config: HLSPlayerConfig = {
manifestUrl: string, // HLS manifest URL (.m3u8)
videoElement: HTMLVideoElement,
autoStart: true, // Auto-play on load
startLevel: -1, // -1 = auto, or specific level
lowLatencyMode: true, // Enable LL-HLS
maxBufferLength: 30, // Max buffer in seconds
maxBufferSize: 60 * 1000 * 1000, // Max buffer in bytes (60MB)
}const abrConfig: ABRConfig = {
minAutoBitrate: 500_000, // 500 kbps
maxAutoBitrate: 10_000_000, // 10 Mbps
bufferBasedABR: true, // Use buffer-based ABR
bandwidthEstimator: 'ewma', // 'ewma' or 'sliding-window'
switchUpThreshold: 0.8, // 80% of bandwidth
switchDownThreshold: 1.2, // 120% of bitrate
minBufferForQualitySwitch: 5, // 5 seconds
}Ant Media Server is recommended for production use with built-in WebRTC ingest, adaptive transcoding, and HLS packaging.
# Download and install Ant Media Server
wget https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.7.0/ant-media-server-2.7.0.zip
unzip ant-media-server-2.7.0.zip
cd ant-media-server
./start.sh
# Access dashboard
open http://localhost:5080
# Configure application
# - Create new application (e.g., "nchat")
# - Enable adaptive streaming
# - Enable HLS
# - Configure quality levels
# - Set up recording (optional)
# Update environment variables
NEXT_PUBLIC_STREAM_INGEST_URL=wss://localhost:5080/nchat/websocket
NEXT_PUBLIC_HLS_BASE_URL=https://localhost:5080/nchat/streamsFeatures:
- WebRTC ingest (sub-second latency)
- Adaptive bitrate transcoding
- HLS packaging with multiple quality levels
- Stream recording
- Live DVR
- Web admin dashboard
- REST API
- Cluster support
NGINX with RTMP module is suitable for simpler deployments or development.
# nginx.conf
rtmp {
server {
listen 1935;
application live {
live on;
# HLS
hls on;
hls_path /tmp/hls;
hls_fragment 2s;
hls_playlist_length 10s;
# Recording (optional)
record all;
record_path /var/recordings;
record_unique on;
# Adaptive streaming
exec ffmpeg -i rtmp://localhost:1935/live/$name
-c:v libx264 -preset veryfast
-b:v 3000k -maxrate 3000k -bufsize 6000k -s 1920x1080 -f flv rtmp://localhost:1935/hls/$name_1080p
-c:v libx264 -preset veryfast
-b:v 1500k -maxrate 1500k -bufsize 3000k -s 1280x720 -f flv rtmp://localhost:1935/hls/$name_720p
-c:v libx264 -preset veryfast
-b:v 800k -maxrate 800k -bufsize 1600k -s 854x480 -f flv rtmp://localhost:1935/hls/$name_480p
-c:v libx264 -preset veryfast
-b:v 400k -maxrate 400k -bufsize 800k -s 640x360 -f flv rtmp://localhost:1935/hls/$name_360p;
}
application hls {
live on;
hls on;
hls_path /tmp/hls;
hls_fragment 2s;
hls_playlist_length 10s;
}
}
}
http {
server {
listen 8080;
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /tmp;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control no-cache;
}
}
}For testing or professional broadcasting, you can use OBS Studio:
1. Open OBS Studio
2. Settings > Stream
- Service: Custom
- Server: rtmp://localhost:1935/live
- Stream Key: [your-stream-key]
3. Add sources (Display Capture, Window Capture, etc.)
4. Click "Start Streaming"
| Quality | Resolution | Bitrate | FPS | CPU | Use Case |
|---|---|---|---|---|---|
| 1080p | 1920x1080 | 3000 kbps | 30 | High | High quality, good bandwidth |
| 720p | 1280x720 | 1500 kbps | 30 | Medium | HD, recommended default |
| 480p | 854x480 | 800 kbps | 24 | Low | SD, moderate bandwidth |
| 360p | 640x360 | 400 kbps | 24 | Very Low | Low bandwidth |
| Auto | Adaptive | Dynamic | Dynamic | N/A | Automatic based on conditions |
- Use hardware encoding if available (H.264 QSV, NVENC, VideoToolbox)
- Close unnecessary applications to free CPU/memory
- Use wired internet connection for stable upload
- Test upload bandwidth before going live (>5 Mbps recommended for 720p)
- Start at lower quality if experiencing issues
- Monitor quality metrics during broadcast
- Enable low-latency mode for interactive streams
- Use Auto quality for best experience
- Close other streaming tabs to free bandwidth
- Disable chat/reactions if experiencing lag
- Refresh if buffering persists
- Use CDN for HLS distribution (CloudFront, CloudFlare, Fastly)
- Enable HTTP/2 for better delivery
- Configure proper caching for HLS segments
- Scale transcoding across multiple servers
- Monitor server resources (CPU, memory, bandwidth)
- Use SSD storage for recording
- Enable logging for debugging
Symptoms: 10+ seconds delay between broadcaster and viewers
Solutions:
- ✓ Enable low-latency mode in HLS player config
- ✓ Reduce HLS fragment size (2s recommended)
- ✓ Reduce playlist length
- ✓ Use LL-HLS if media server supports it
- ✓ Check network bandwidth (both upload and download)
Symptoms: "Failed to start stream" or WebRTC connection errors
Solutions:
- ✓ Check camera/microphone permissions in browser
- ✓ Verify STUN/TURN servers are accessible
- ✓ Check firewall settings (allow UDP ports)
- ✓ Try different browser (Chrome/Firefox recommended)
- ✓ Review WebRTC logs in browser console
Symptoms: Constant buffering, playback pauses
Solutions:
- ✓ Lower quality level manually
- ✓ Check viewer's download bandwidth
- ✓ Verify CDN performance
- ✓ Reduce broadcaster bitrate
- ✓ Check media server CPU usage
- ✓ Verify network stability
Symptoms: Messages not sending/receiving
Solutions:
- ✓ Check Socket.io connection status
- ✓ Verify authentication token is valid
- ✓ Review RLS policies in database
- ✓ Check message rate limits
- ✓ Verify stream status is 'live'
Symptoms: Blurry video, artifacts, pixelation
Solutions:
- ✓ Increase bitrate setting
- ✓ Use higher quality preset
- ✓ Check upload bandwidth (broadcaster)
- ✓ Verify transcoding settings
- ✓ Reduce motion/complexity in scene
- ✓ Use hardware encoder if available
# Test streaming library
pnpm test src/lib/streaming
# Test hooks
pnpm test src/hooks/use-live-stream
pnpm test src/hooks/use-stream-viewer
# Test components
pnpm test src/components/streaming# E2E streaming tests
pnpm test:e2e streaming- Create stream successfully
- Start broadcast with camera/microphone
- Switch between camera/microphone devices
- Change quality settings during broadcast
- Toggle video/audio on and off
- View stream in another browser/tab
- Verify HLS playback works
- Test quality switching (manual and auto)
- Send chat messages
- Send emoji reactions
- Verify viewer count updates
- Test with slow network (DevTools throttling)
- End stream successfully
- Verify recording is saved (if enabled)
- Test scheduled streams
- Test chat moderation features
- Monitor analytics/metrics
# Apply streaming migration
cd .backend
nself db migrate up
# Verify tables created
psql -d $DATABASE_URL -c "\\dt nchat_stream*"# Production .env
NEXT_PUBLIC_STREAM_INGEST_URL=wss://stream.yourapp.com/live/websocket
NEXT_PUBLIC_HLS_BASE_URL=https://stream.yourapp.com/hls
STREAM_RECORDING_ENABLED=true
STREAM_RECORDING_PATH=/mnt/recordingsKey Metrics to Monitor:
- Active streams count
- Concurrent viewers
- Average viewer count
- Chat messages per minute
- Reactions per minute
- Stream health scores
- Bitrate stability
- Latency measurements
- Error rates
Recommended Tools:
- Grafana for dashboards
- Prometheus for metrics collection
- Sentry for error tracking
- DataDog for APM
- ✓ Generate cryptographically secure stream keys
- ✓ Never expose stream keys in client code
- ✓ Allow broadcasters to regenerate keys
- ✓ Rotate keys periodically
- ✓ Verify user permissions before allowing broadcast
- ✓ Implement RLS policies for all stream tables
- ✓ Rate limit chat messages (default: 3 msgs/sec)
- ✓ Rate limit reactions (default: 5 reactions/sec)
- ✓ Validate all user input
- ✓ Implement profanity filter for chat
- ✓ Allow broadcasters to ban users
- ✓ Provide moderation dashboard
- ✓ Log all moderation actions
- ✓ Support DMCA takedown requests
- ✓ Allow users to hide viewer list
- ✓ Support private streams
- ✓ Respect GDPR/CCPA requirements
- ✓ Implement data retention policies
- ✓ Allow users to delete their data
Potential improvements for future releases:
- Multi-bitrate recording - Record multiple quality levels
- Clip creation - Allow viewers to create clips
- Instant replay - DVR functionality for viewers
- Simulcast - Stream to multiple platforms simultaneously
- Monetization - Subscriptions, donations, ads
- Advanced analytics - Heatmaps, drop-off analysis
- Mobile apps - Native iOS/Android broadcasting
- Screen sharing - Broadcast screen instead of camera
- Guest streaming - Multiple broadcasters in one stream
- Interactive polls - Real-time polls during streams
- Stream overlays - Custom graphics and animations
- Auto-moderation - AI-powered content moderation
The live streaming system in nself-chat v0.4.0 is production-ready with comprehensive features for both broadcasters and viewers. With HLS adaptive streaming, low-latency mode, real-time chat, animated reactions, and detailed analytics, it provides a complete streaming solution suitable for a wide range of use cases.
For questions, issues, or feature requests, please open an issue on GitHub or contact the maintainers.
Related Documentation: