webrtc

package
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2025 License: MIT Imports: 17 Imported by: 0

README

WebRTC Extension for Forge v2

Production-ready WebRTC extension that leverages the streaming extension for signaling, authentication, and room management.

Features

Multiple Topologies

  • Mesh (P2P) - Best for 2-4 participants
  • SFU (Selective Forwarding Unit) - Best for 5-50 participants
  • MCU (Multipoint Control Unit) - Best for 50+ participants (planned)

Signaling via Streaming

  • Uses streaming extension's WebSocket/SSE for signaling
  • Automatic room management
  • Distributed signaling across nodes

Media Management

  • Audio/Video tracks
  • Screen sharing
  • Data channels
  • Simulcast support (SFU)

Quality Monitoring

  • Real-time connection quality metrics
  • Packet loss, jitter, latency tracking
  • Adaptive quality based on network conditions

Recording

  • Record audio/video streams
  • Multiple formats (WebM, MP4)
  • Per-room or per-participant recording

Security

  • Integrated with streaming auth
  • Room-level permissions
  • STUN/TURN server support

Installation

go get github.com/xraph/forge/extensions/webrtc

Quick Start

Basic Video Call
package main

import (
    "github.com/xraph/forge"
    "github.com/xraph/forge/extensions/streaming"
    "github.com/xraph/forge/extensions/webrtc"
)

func main() {
    app := forge.NewApp(forge.AppConfig{
        Name: "Video Call App",
    })
    
    // Register streaming extension
    streamingExt := streaming.New(streaming.Config{
        RequireAuth: true,
        AuthProviders: []string{"jwt"},
    })
    app.Use(streamingExt)
    
    // Register WebRTC extension
    webrtcExt, _ := webrtc.New(streamingExt, webrtc.DefaultConfig())
    app.Use(webrtcExt)
    
    // Register routes
    router := app.Router()
    webrtcExt.RegisterRoutes(router)
    
    // Custom endpoint
    router.POST("/call/create", func(ctx forge.Context) error {
        roomID := ctx.PostValue("room_id")
        userID := ctx.Get("user_id").(string)
        
        // Create call room
        room, err := webrtcExt.CreateCallRoom(ctx, roomID, streaming.RoomOptions{
            Name:       "My Video Call",
            MaxMembers: 10,
        })
        if err != nil {
            return err
        }
        
        // Join call
        peer, err := room.Join(ctx, userID, &webrtc.JoinOptions{
            AudioEnabled: true,
            VideoEnabled: true,
        })
        if err != nil {
            return err
        }
        
        return ctx.JSON(map[string]any{
            "room_id": room.ID(),
            "peer_id": peer.ID(),
        })
    })
    
    app.Run(":8080")
}

Configuration

Mesh Topology (Default)
config := webrtc.Config{
    Topology: webrtc.TopologyMesh,
    
    STUNServers: []string{
        "stun:stun.l.google.com:19302",
    },
    
    MediaConfig: webrtc.MediaConfig{
        AudioEnabled:    true,
        AudioCodecs:     []string{"opus"},
        VideoEnabled:    true,
        VideoCodecs:     []string{"VP8", "H264"},
        MaxVideoBitrate: 2500, // kbps
    },
}
SFU Topology
config := webrtc.Config{
    Topology: webrtc.TopologySFU,
    
    SFUConfig: &webrtc.SFUConfig{
        WorkerCount:      4,
        MaxBandwidthMbps: 100,
        SimulcastEnabled: true,
        QualityLayers: []webrtc.QualityLayer{
            {RID: "f", MaxWidth: 1920, MaxHeight: 1080, MaxFPS: 30, Bitrate: 2500},
            {RID: "h", MaxWidth: 1280, MaxHeight: 720,  MaxFPS: 30, Bitrate: 1200},
            {RID: "q", MaxWidth: 640,  MaxHeight: 360,  MaxFPS: 30, Bitrate: 500},
        },
    },
}
With TURN Servers
config := webrtc.Config{
    STUNServers: []string{
        "stun:stun.example.com:3478",
    },
    
    TURNServers: []webrtc.TURNConfig{{
        URLs:       []string{"turn:turn.example.com:3478"},
        Username:   "user",
        Credential: "pass",
    }},
}
With Recording
config := webrtc.Config{
    RecordingEnabled: true,
    RecordingPath:    "/var/recordings",
}

// Start recording
err := webrtcExt.GetRecorder().Start(ctx, roomID, &webrtc.RecordingOptions{
    Format:     "webm",
    VideoCodec: "VP8",
    AudioCodec: "opus",
    OutputPath: "/var/recordings/call-123.webm",
})

Usage Examples

1. One-on-One Call
// User A creates offer
router.POST("/call/offer", func(ctx forge.Context) error {
    roomID := ctx.PostValue("room_id")
    userID := ctx.Get("user_id").(string)
    
    room, _ := webrtcExt.GetCallRoom(roomID)
    peer, _ := room.Join(ctx, userID, &webrtc.JoinOptions{
        AudioEnabled: true,
        VideoEnabled: true,
    })
    
    offer, _ := peer.CreateOffer(ctx)
    peer.SetLocalDescription(ctx, offer)
    
    return ctx.JSON(offer)
})

// User B creates answer
router.POST("/call/answer", func(ctx forge.Context) error {
    roomID := ctx.PostValue("room_id")
    userID := ctx.Get("user_id").(string)
    offer := ctx.PostValue("offer") // SDP offer
    
    room, _ := webrtcExt.GetCallRoom(roomID)
    peer, _ := room.Join(ctx, userID, nil)
    
    peer.SetRemoteDescription(ctx, offer)
    answer, _ := peer.CreateAnswer(ctx)
    peer.SetLocalDescription(ctx, answer)
    
    return ctx.JSON(answer)
})
2. Group Video Call
router.POST("/group/join", func(ctx forge.Context) error {
    roomID := ctx.PostValue("room_id")
    userID := ctx.Get("user_id").(string)
    
    room, err := webrtcExt.GetCallRoom(roomID)
    if err != nil {
        // Create room if doesn't exist
        room, _ = webrtcExt.CreateCallRoom(ctx, roomID, streaming.RoomOptions{
            Name:       "Group Call",
            MaxMembers: 50,
        })
    }
    
    peer, _ := room.Join(ctx, userID, &webrtc.JoinOptions{
        AudioEnabled: true,
        VideoEnabled: true,
        DisplayName:  ctx.PostValue("display_name"),
    })
    
    // Get all participants
    participants := room.GetParticipants()
    
    return ctx.JSON(map[string]any{
        "peer_id":      peer.ID(),
        "participants": participants,
    })
})
3. Screen Sharing
router.POST("/screen/start", func(ctx forge.Context) error {
    roomID := ctx.PostValue("room_id")
    userID := ctx.Get("user_id").(string)
    
    room, _ := webrtcExt.GetCallRoom(roomID)
    
    // Create screen share track (would use actual WebRTC library)
    screenTrack := createScreenShareTrack()
    
    err := room.StartScreenShare(ctx, userID, screenTrack)
    if err != nil {
        return err
    }
    
    return ctx.JSON(map[string]any{
        "status": "screen_sharing_started",
    })
})
4. Quality Monitoring
router.GET("/call/{roomID}/quality", func(ctx forge.Context) error {
    roomID := ctx.Param("roomID")
    
    room, _ := webrtcExt.GetCallRoom(roomID)
    quality, _ := room.GetQuality(ctx)
    
    return ctx.JSON(quality)
})

// Monitor quality changes
monitor := webrtcExt.GetQualityMonitor()
monitor.OnQualityChange(func(peerID string, quality *webrtc.ConnectionQuality) {
    if quality.Score < 50 {
        // Poor quality - notify user or reduce bitrate
        log.Printf("Poor quality for peer %s: score=%f", peerID, quality.Score)
    }
})

Architecture

Signaling Flow
┌─────────┐                    ┌─────────┐
│ Client  │                    │  Server │
│   A     │                    │ (Forge) │
└────┬────┘                    └────┬────┘
     │                              │
     │  WebSocket Connect           │
     │────────────────────────────>│
     │                              │
     │  Create Offer (SDP)          │
     │────────────────────────────>│
     │                              │
     │           Streaming Message  │
     │<────────────────────────────│
     │  (via streaming extension)   │
     │                              │
     │  ICE Candidates              │
     │<────────────────────────────│
     │                              │
     
┌─────────────────────────────────────────┐
│   After Signaling: P2P Connection       │
├─────────────────────────────────────────┤
│  Client A  <──────RTP────────>  Client B│
│  (direct peer-to-peer connection)       │
└─────────────────────────────────────────┘
Topology Comparison
Feature Mesh SFU MCU
Participants 2-4 5-50 50+
Client Upload High (N streams) Low (1 stream) Low (1 stream)
Client Download High (N streams) Medium (N streams) Low (1 stream)
Server CPU None Low High
Server Bandwidth Low High High
Latency Lowest Low Medium
Best For 1-on-1 calls Webinars, meetings Large conferences

Integration with Streaming Extension

The WebRTC extension leverages streaming for:

1. Signaling Transport
// Signaling messages use streaming rooms
signaling.SendOffer(ctx, roomID, peerID, offer)
// Internally uses: streaming.SendToRoom()
2. Authentication
// Inherit auth from streaming
streaming.Config{
    RequireAuth: true,
    AuthProviders: []string{"jwt"},
}
// WebRTC calls automatically authenticated
3. Room Management
// Call rooms extend streaming rooms
type CallRoom interface {
    streaming.Room  // Inherits all room features
    // + WebRTC-specific methods
}
4. Presence
// Participant presence tracked via streaming
participants := room.GetParticipants()
// Uses streaming.PresenceTracker under the hood
5. Distributed Coordination
// Multi-node signaling via streaming coordinator
streaming.Config{
    Coordination: streaming.CoordinationConfig{
        Enabled: true,
        Backend: "redis",
    },
}
// WebRTC signaling works across nodes

Client Integration

JavaScript Client Example
// Connect to signaling server
const ws = new WebSocket('wss://example.com/webrtc/signal/room-123');
const pc = new RTCPeerConnection({
    iceServers: [
        { urls: 'stun:stun.l.google.com:19302' }
    ]
});

// Add local media
const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true
});
stream.getTracks().forEach(track => pc.addTrack(track, stream));

// Create and send offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
ws.send(JSON.stringify({
    type: 'webrtc.offer',
    sdp: offer
}));

// Handle answer
ws.onmessage = async (event) => {
    const msg = JSON.parse(event.data);
    
    if (msg.type === 'webrtc.answer') {
        await pc.setRemoteDescription(msg.sdp);
    }
    
    if (msg.type === 'webrtc.ice_candidate') {
        await pc.addIceCandidate(msg.candidate);
    }
};

// Send ICE candidates
pc.onicecandidate = (event) => {
    if (event.candidate) {
        ws.send(JSON.stringify({
            type: 'webrtc.ice_candidate',
            candidate: event.candidate
        }));
    }
};

// Receive remote tracks
pc.ontrack = (event) => {
    const remoteVideo = document.getElementById('remote-video');
    remoteVideo.srcObject = event.streams[0];
};

Performance Considerations

Mesh Topology
  • Pros: Lowest latency, no server cost
  • Cons: Doesn't scale (N² connections), high client bandwidth
// Good for: 1-on-1, 2-person calls
config := webrtc.Config{
    Topology: webrtc.TopologyMesh,
}
SFU Topology
  • Pros: Scales to 50+, moderate server cost
  • Cons: Server bandwidth intensive
// Good for: Team meetings, webinars
config := webrtc.Config{
    Topology: webrtc.TopologySFU,
    SFUConfig: &webrtc.SFUConfig{
        SimulcastEnabled: true,  // Client sends 3 quality layers
        AdaptiveBitrate:  true,  // Adjust based on network
    },
}

Deployment

Single Node
# docker-compose.yml
services:
  forge:
    image: forge-app
    ports:
      - "8080:8080"
      - "3478:3478/udp"  # TURN
    environment:
      WEBRTC_TOPOLOGY: "sfu"
      STUN_SERVER: "stun:stun.l.google.com:19302"
Multi-Node with Load Balancer
services:
  forge-1:
    image: forge-app
    environment:
      NODE_ID: "node-1"
      STREAMING_BACKEND: "redis"
      REDIS_URL: "redis://redis:6379"
  
  forge-2:
    image: forge-app
    environment:
      NODE_ID: "node-2"
      STREAMING_BACKEND: "redis"
      REDIS_URL: "redis://redis:6379"
  
  redis:
    image: redis:7-alpine
  
  nginx:
    image: nginx
    # Sticky session load balancing for WebRTC

Monitoring

Metrics

The extension exposes metrics compatible with Prometheus:

# Connection metrics
webrtc_connections_total
webrtc_connections_active
webrtc_connections_failed

# Media metrics
webrtc_tracks_total{kind="audio|video"}
webrtc_bytes_sent_total
webrtc_bytes_received_total
webrtc_packet_loss_ratio

# Quality metrics
webrtc_connection_quality_score
webrtc_jitter_milliseconds
webrtc_round_trip_time_milliseconds
Logging
// Enable debug logging
logger := forge.NewLogger(forge.LogConfig{
    Level: forge.LogLevelDebug,
})

// WebRTC extension will log:
// - Connection state changes
// - Signaling messages
// - ICE candidate exchanges
// - Media track additions/removals
// - Quality warnings

Security Best Practices

  1. Always use authentication
webrtc.Config{
    RequireAuth: true,
}
  1. Use TURN over TLS
TURNServers: []webrtc.TURNConfig{{
    URLs:       []string{"turns:turn.example.com:5349"},
    TLSEnabled: true,
}},
  1. Implement rate limiting
streaming.Config{
    RateLimitEnabled: true,
    RateLimit: streaming.RateLimitConfig{
        ConnectionsPerUser: 5,
        ConnectionsPerIP:   20,
    },
}
  1. Room-level permissions
// Use streaming room auth
room.CanJoin(ctx, userID) // Checks permissions

Roadmap

  • Full pion/webrtc integration
  • MCU topology support
  • End-to-end encryption (E2EE)
  • Noise suppression / background blur
  • Advanced recording features
  • React/Vue client SDK
  • Mobile SDK (iOS/Android)

Contributing

See CONTRIBUTING.md

License

MIT License - see LICENSE

Documentation

Index

Constants

View Source
const (
	MessageTypeOffer        = "webrtc.offer"
	MessageTypeAnswer       = "webrtc.answer"
	MessageTypeICECandidate = "webrtc.ice_candidate"
)

Message types for signaling

Variables

View Source
var (
	// Configuration errors
	ErrInvalidConfig       = errors.New("webrtc: invalid configuration")
	ErrNoICEServers        = errors.New("webrtc: no ICE servers configured")
	ErrInvalidBitrateRange = errors.New("webrtc: invalid bitrate range")

	// Connection errors
	ErrPeerNotFound           = errors.New("webrtc: peer not found")
	ErrPeerAlreadyExists      = errors.New("webrtc: peer already exists")
	ErrConnectionFailed       = errors.New("webrtc: connection failed")
	ErrConnectionClosed       = errors.New("webrtc: connection closed")
	ErrInvalidConnectionState = errors.New("webrtc: invalid connection state")

	// Signaling errors
	ErrSignalingFailed  = errors.New("webrtc: signaling failed")
	ErrInvalidSDP       = errors.New("webrtc: invalid SDP")
	ErrInvalidCandidate = errors.New("webrtc: invalid ICE candidate")
	ErrSignalingTimeout = errors.New("webrtc: signaling timeout")

	// Media errors
	ErrTrackNotFound     = errors.New("webrtc: track not found")
	ErrInvalidTrackKind  = errors.New("webrtc: invalid track kind")
	ErrMediaNotSupported = errors.New("webrtc: media type not supported")
	ErrCodecNotSupported = errors.New("webrtc: codec not supported")

	// Room errors
	ErrRoomNotFound  = errors.New("webrtc: room not found")
	ErrRoomFull      = errors.New("webrtc: room is full")
	ErrNotInRoom     = errors.New("webrtc: not in room")
	ErrAlreadyInRoom = errors.New("webrtc: already in room")

	// Data channel errors
	ErrDataChannelClosed = errors.New("webrtc: data channel closed")
	ErrDataChannelFailed = errors.New("webrtc: data channel failed")

	// Recording errors
	ErrRecordingFailed  = errors.New("webrtc: recording failed")
	ErrNotRecording     = errors.New("webrtc: not recording")
	ErrAlreadyRecording = errors.New("webrtc: already recording")

	// SFU errors
	ErrSFUNotEnabled    = errors.New("webrtc: SFU not enabled")
	ErrRoutingFailed    = errors.New("webrtc: media routing failed")
	ErrReceiverNotFound = errors.New("webrtc: receiver not found")

	// Auth errors
	ErrUnauthorized = errors.New("webrtc: unauthorized")
	ErrForbidden    = errors.New("webrtc: forbidden")

	// General errors
	ErrNotImplemented = errors.New("webrtc: not implemented - requires additional setup")
)

Common errors

Functions

This section is empty.

Types

type AnswerHandler

type AnswerHandler func(peerID string, answer *SessionDescription)

Callback handlers

type CallQuality

type CallQuality struct {
	RoomID           string
	ParticipantCount int
	AverageQuality   float64 // 0-100
	PacketLoss       float64
	Jitter           time.Duration
	Latency          time.Duration
	Participants     map[string]*ConnectionQuality
}

CallQuality holds overall call quality metrics

type CallRoom

type CallRoom interface {
	// ID returns room ID
	ID() string

	// Name returns room name
	Name() string

	// Join joins the call
	JoinCall(ctx context.Context, userID string, options *JoinOptions) (PeerConnection, error)

	// Leave leaves the call
	Leave(ctx context.Context, userID string) error

	// GetPeer returns peer connection for user
	GetPeer(userID string) (PeerConnection, error)

	// GetPeers returns all peer connections
	GetPeers() []PeerConnection

	// GetParticipants returns participant information
	GetParticipants() []Participant

	// MuteUser mutes a user's audio
	MuteUser(ctx context.Context, userID string) error

	// UnmuteUser unmutes a user's audio
	UnmuteUser(ctx context.Context, userID string) error

	// EnableVideo enables user's video
	EnableVideo(ctx context.Context, userID string) error

	// DisableVideo disables user's video
	DisableVideo(ctx context.Context, userID string) error

	// StartScreenShare starts screen sharing
	StartScreenShare(ctx context.Context, userID string, track MediaTrack) error

	// StopScreenShare stops screen sharing
	StopScreenShare(ctx context.Context, userID string) error

	// GetQuality returns call quality metrics
	GetQuality(ctx context.Context) (*CallQuality, error)

	// Close closes the call room
	Close(ctx context.Context) error
}

CallRoom represents a WebRTC call room

func NewMeshCallRoom

func NewMeshCallRoom(
	streamingRoom streaming.Room,
	config Config,
	signaling SignalingManager,
	logger forge.Logger,
	metrics forge.Metrics,
) CallRoom

NewMeshCallRoom creates a call room with mesh topology

func NewMeshCallRoomFromOptions

func NewMeshCallRoomFromOptions(
	opts streaming.RoomOptions,
	config Config,
	signaling SignalingManager,
	logger forge.Logger,
	metrics forge.Metrics,
) (CallRoom, error)

NewMeshCallRoomFromOptions creates a mesh call room from streaming room options

func NewSFUCallRoomFromOptions

func NewSFUCallRoomFromOptions(
	opts streaming.RoomOptions,
	config Config,
	signaling SignalingManager,
	router SFURouter,
	logger forge.Logger,
	metrics forge.Metrics,
) (CallRoom, error)

NewSFUCallRoomFromOptions creates an SFU call room from streaming room options

type Config

type Config struct {
	// Signaling
	SignalingEnabled bool
	SignalingTimeout time.Duration

	// Topology
	Topology Topology

	// STUN servers for NAT traversal
	STUNServers []string

	// TURN servers for relaying when P2P fails
	TURNServers []TURNConfig

	// Media configuration
	MediaConfig MediaConfig

	// SFU configuration (if topology is SFU)
	SFUConfig *SFUConfig

	// Quality settings
	QualityConfig QualityConfig

	// Recording
	RecordingEnabled bool
	RecordingPath    string

	// Metrics
	MetricsEnabled bool

	// Security
	RequireAuth bool
	AllowGuests bool
}

Config holds WebRTC extension configuration

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns default WebRTC configuration

func (*Config) GetICEServers

func (c *Config) GetICEServers() []ICEServer

GetICEServers returns all configured ICE servers

func (*Config) Validate

func (c *Config) Validate() error

Validate validates the configuration

type ConfigOption

type ConfigOption func(*Config)

ConfigOption is a functional option for Config

func WithAudioCodecs

func WithAudioCodecs(codecs ...string) ConfigOption

WithAudioCodecs sets audio codecs

func WithQualityMonitoring

func WithQualityMonitoring(config QualityConfig) ConfigOption

WithQualityMonitoring enables quality monitoring

func WithRecording

func WithRecording(path string) ConfigOption

WithRecording enables recording

func WithSFU

func WithSFU(config SFUConfig) ConfigOption

WithSFU enables SFU mode with configuration

func WithSTUNServers

func WithSTUNServers(servers ...string) ConfigOption

WithSTUNServers sets STUN servers

func WithTURNServer

func WithTURNServer(turn TURNConfig) ConfigOption

WithTURNServer adds a TURN server

func WithTopology

func WithTopology(topology Topology) ConfigOption

WithTopology sets the connection topology

func WithVideoCodecs

func WithVideoCodecs(codecs ...string) ConfigOption

WithVideoCodecs sets video codecs

type ConnectionError

type ConnectionError struct {
	PeerID string
	State  ConnectionState
	Err    error
}

ConnectionError wraps connection errors with context

func (*ConnectionError) Error

func (e *ConnectionError) Error() string

func (*ConnectionError) Unwrap

func (e *ConnectionError) Unwrap() error

type ConnectionQuality

type ConnectionQuality struct {
	Score       float64 // 0-100
	PacketLoss  float64 // Percentage
	Jitter      time.Duration
	Latency     time.Duration
	BitrateKbps int
	Warnings    []string
	LastUpdated time.Time
}

ConnectionQuality holds connection quality metrics

type ConnectionState

type ConnectionState string

ConnectionState represents peer connection state

const (
	ConnectionStateNew          ConnectionState = "new"
	ConnectionStateConnecting   ConnectionState = "connecting"
	ConnectionStateConnected    ConnectionState = "connected"
	ConnectionStateDisconnected ConnectionState = "disconnected"
	ConnectionStateFailed       ConnectionState = "failed"
	ConnectionStateClosed       ConnectionState = "closed"
)

type ConnectionStateHandler

type ConnectionStateHandler func(state ConnectionState)

Callback handlers

type DataChannel

type DataChannel interface {
	// ID returns channel ID
	ID() string

	// Label returns channel label
	Label() string

	// State returns channel state
	State() DataChannelState

	// Send sends data
	Send(data []byte) error

	// SendText sends text
	SendText(text string) error

	// OnMessage sets message callback
	OnMessage(handler DataChannelMessageHandler)

	// OnOpen sets open callback
	OnOpen(handler DataChannelStateHandler)

	// OnClose sets close callback
	OnClose(handler DataChannelStateHandler)

	// Close closes the channel
	Close() error
}

DataChannel represents a WebRTC data channel

func NewDataChannel

func NewDataChannel(pc *webrtc.PeerConnection, label string, ordered bool, logger forge.Logger) (DataChannel, error)

NewDataChannel creates a new data channel on a peer connection

type DataChannelHandler

type DataChannelHandler func(channel DataChannel)

Callback handlers

type DataChannelMessageHandler

type DataChannelMessageHandler func(data []byte)

Callback handlers

type DataChannelState

type DataChannelState string

DataChannelState represents data channel state

const (
	DataChannelStateConnecting DataChannelState = "connecting"
	DataChannelStateOpen       DataChannelState = "open"
	DataChannelStateClosing    DataChannelState = "closing"
	DataChannelStateClosed     DataChannelState = "closed"
)

type DataChannelStateHandler

type DataChannelStateHandler func()

Callback handlers

type Extension

type Extension struct {
	// contains filtered or unexported fields
}

Extension is the WebRTC extension

func New

func New(streamingExt *streaming.Extension, config Config, opts ...ConfigOption) (*Extension, error)

New creates a new WebRTC extension

func (*Extension) CreateCallRoom

func (e *Extension) CreateCallRoom(ctx context.Context, roomID string, opts streaming.RoomOptions) (CallRoom, error)

CreateCallRoom creates a new call room

func (*Extension) DeleteCallRoom

func (e *Extension) DeleteCallRoom(ctx context.Context, roomID string) error

DeleteCallRoom deletes a call room

func (*Extension) Dependencies

func (e *Extension) Dependencies() []string

Dependencies returns the extensions this extension depends on

func (*Extension) Description

func (e *Extension) Description() string

Description returns the extension description

func (*Extension) GetCallRoom

func (e *Extension) GetCallRoom(roomID string) (CallRoom, error)

GetCallRoom retrieves a call room

func (*Extension) GetCallRooms

func (e *Extension) GetCallRooms() []CallRoom

GetCallRooms returns all call rooms

func (*Extension) GetConfig

func (e *Extension) GetConfig() Config

GetConfig returns the extension configuration

func (*Extension) GetQualityMonitor

func (e *Extension) GetQualityMonitor() QualityMonitor

GetQualityMonitor returns the quality monitor

func (*Extension) GetRecorder

func (e *Extension) GetRecorder() Recorder

GetRecorder returns the recorder

func (*Extension) GetSFURouter

func (e *Extension) GetSFURouter() SFURouter

GetSFURouter returns the SFU router (if enabled)

func (*Extension) GetSignalingManager

func (e *Extension) GetSignalingManager() SignalingManager

GetSignalingManager returns the signaling manager

func (*Extension) Health

func (e *Extension) Health(ctx context.Context) error

Health checks extension health

func (*Extension) JoinCall

func (e *Extension) JoinCall(ctx context.Context, roomID, userID string, opts *JoinOptions) (PeerConnection, error)

JoinCall is a convenience method to join a call

func (*Extension) LeaveCall

func (e *Extension) LeaveCall(ctx context.Context, roomID, userID string) error

LeaveCall is a convenience method to leave a call

func (*Extension) Name

func (e *Extension) Name() string

Name returns the extension name

func (*Extension) Register

func (e *Extension) Register(app forge.App) error

Register registers the extension with the app

func (*Extension) RegisterRoutes

func (e *Extension) RegisterRoutes(router forge.Router) error

RegisterRoutes registers WebRTC HTTP routes

func (*Extension) Start

func (e *Extension) Start(ctx context.Context) error

Start starts the extension

func (*Extension) Stop

func (e *Extension) Stop(ctx context.Context) error

Stop stops the extension

func (*Extension) Version

func (e *Extension) Version() string

Version returns the extension version

type ICECandidate

type ICECandidate struct {
	Candidate        string
	SDPMid           string
	SDPMLineIndex    int
	UsernameFragment string
}

ICECandidate represents an ICE candidate

type ICECandidateHandler

type ICECandidateHandler func(candidate *ICECandidate)

Callback handlers

type ICECandidateReceivedHandler

type ICECandidateReceivedHandler func(peerID string, candidate *ICECandidate)

Callback handlers

type ICEServer

type ICEServer struct {
	URLs       []string
	Username   string
	Credential string
}

ICEServer represents a STUN/TURN server

type JoinOptions

type JoinOptions struct {
	AudioEnabled bool
	VideoEnabled bool
	DisplayName  string
	Metadata     map[string]any
}

JoinOptions holds options for joining a call

type MediaConfig

type MediaConfig struct {
	// Audio
	AudioEnabled bool
	AudioCodecs  []string // ["opus", "pcmu", "pcma"]

	// Video
	VideoEnabled bool
	VideoCodecs  []string // ["VP8", "VP9", "H264", "AV1"]

	// Screen sharing
	ScreenShareEnabled bool

	// Data channels
	DataChannelsEnabled bool

	// Bitrate limits (kbps)
	MaxAudioBitrate int
	MaxVideoBitrate int
	MinVideoBitrate int

	// Resolution constraints
	MaxWidth  int
	MaxHeight int
	MaxFPS    int
}

MediaConfig holds media stream configuration

type MediaError

type MediaError struct {
	TrackID string
	Kind    TrackKind
	Err     error
}

MediaError wraps media errors with context

func (*MediaError) Error

func (e *MediaError) Error() string

func (*MediaError) Unwrap

func (e *MediaError) Unwrap() error

type MediaTrack

type MediaTrack interface {
	// ID returns the track ID
	ID() string

	// Kind returns track kind ("audio" or "video")
	Kind() TrackKind

	// Label returns track label
	Label() string

	// Enabled returns if track is enabled
	Enabled() bool

	// SetEnabled enables/disables track
	SetEnabled(enabled bool)

	// GetSettings returns track settings
	GetSettings() TrackSettings

	// GetStats returns track statistics
	GetStats(ctx context.Context) (*TrackStats, error)

	// Close stops the track
	Close() error
}

MediaTrack represents a media track (audio/video)

func NewLocalTrack

func NewLocalTrack(kind TrackKind, id, label string, logger forge.Logger) (MediaTrack, error)

NewLocalTrack creates a new local media track

type MeshCallRoom

type MeshCallRoom struct {
	// contains filtered or unexported fields
}

MeshCallRoom implements CallRoom with mesh topology

func (MeshCallRoom) Close

func (r MeshCallRoom) Close(ctx context.Context) error

Close closes the call room

func (MeshCallRoom) DisableVideo

func (r MeshCallRoom) DisableVideo(ctx context.Context, userID string) error

DisableVideo disables user's video

func (MeshCallRoom) EnableVideo

func (r MeshCallRoom) EnableVideo(ctx context.Context, userID string) error

EnableVideo enables user's video

func (MeshCallRoom) GetParticipants

func (r MeshCallRoom) GetParticipants() []Participant

GetParticipants returns participant information

func (MeshCallRoom) GetPeer

func (r MeshCallRoom) GetPeer(userID string) (PeerConnection, error)

GetPeer returns peer connection for user

func (MeshCallRoom) GetPeers

func (r MeshCallRoom) GetPeers() []PeerConnection

GetPeers returns all peer connections

func (MeshCallRoom) GetQuality

func (r MeshCallRoom) GetQuality(ctx context.Context) (*CallQuality, error)

GetQuality returns call quality metrics (stub implementation)

func (MeshCallRoom) ID

func (r MeshCallRoom) ID() string

ID returns room ID

func (*MeshCallRoom) JoinCall

func (r *MeshCallRoom) JoinCall(ctx context.Context, userID string, opts *JoinOptions) (PeerConnection, error)

JoinCall joins the mesh call

func (MeshCallRoom) Leave

func (r MeshCallRoom) Leave(ctx context.Context, userID string) error

Leave leaves the call

func (MeshCallRoom) MuteUser

func (r MeshCallRoom) MuteUser(ctx context.Context, userID string) error

MuteUser mutes a user's audio

func (MeshCallRoom) Name

func (r MeshCallRoom) Name() string

Name returns room name

func (MeshCallRoom) StartScreenShare

func (r MeshCallRoom) StartScreenShare(ctx context.Context, userID string, track MediaTrack) error

StartScreenShare starts screen sharing (stub implementation)

func (MeshCallRoom) StopScreenShare

func (r MeshCallRoom) StopScreenShare(ctx context.Context, userID string) error

StopScreenShare stops screen sharing (stub implementation)

func (MeshCallRoom) UnmuteUser

func (r MeshCallRoom) UnmuteUser(ctx context.Context, userID string) error

UnmuteUser unmutes a user's audio

type OfferHandler

type OfferHandler func(peerID string, offer *SessionDescription)

Callback handlers

type Participant

type Participant struct {
	UserID        string
	DisplayName   string
	AudioEnabled  bool
	VideoEnabled  bool
	ScreenSharing bool
	Quality       *ConnectionQuality
	JoinedAt      time.Time
}

Participant represents a call participant

type PeerConnection

type PeerConnection interface {
	// ID returns the peer connection ID
	ID() string

	// UserID returns the user ID associated with this peer
	UserID() string

	// State returns the current connection state
	State() ConnectionState

	// CreateOffer creates an SDP offer
	CreateOffer(ctx context.Context) (*SessionDescription, error)

	// CreateAnswer creates an SDP answer
	CreateAnswer(ctx context.Context) (*SessionDescription, error)

	// SetLocalDescription sets local SDP
	SetLocalDescription(ctx context.Context, sdp *SessionDescription) error

	// SetRemoteDescription sets remote SDP
	SetRemoteDescription(ctx context.Context, sdp *SessionDescription) error

	// AddICECandidate adds an ICE candidate
	AddICECandidate(ctx context.Context, candidate *ICECandidate) error

	// AddTrack adds a media track
	AddTrack(ctx context.Context, track MediaTrack) error

	// RemoveTrack removes a media track
	RemoveTrack(ctx context.Context, trackID string) error

	// GetTracks returns all media tracks
	GetTracks() []MediaTrack

	// GetStats returns connection statistics
	GetStats(ctx context.Context) (*PeerStats, error)

	// Close closes the peer connection
	Close(ctx context.Context) error

	// OnICECandidate sets ICE candidate callback
	OnICECandidate(handler ICECandidateHandler)

	// OnTrack sets track received callback
	OnTrack(handler TrackHandler)

	// OnConnectionStateChange sets state change callback
	OnConnectionStateChange(handler ConnectionStateHandler)

	// OnDataChannel sets data channel callback
	OnDataChannel(handler DataChannelHandler)
}

PeerConnection represents a WebRTC peer connection

func NewPeerConnection

func NewPeerConnection(id, userID string, config Config, logger forge.Logger) (PeerConnection, error)

NewPeerConnection creates a new peer connection

type PeerStats

type PeerStats struct {
	PeerID              string
	ConnectionState     ConnectionState
	LocalCandidateType  string
	RemoteCandidateType string
	BytesSent           uint64
	BytesReceived       uint64
	PacketsSent         uint64
	PacketsReceived     uint64
	PacketsLost         uint64
	Jitter              time.Duration
	RoundTripTime       time.Duration
	AvailableBitrate    int
}

PeerStats holds peer connection statistics

type QualityChangeHandler

type QualityChangeHandler func(peerID string, quality *ConnectionQuality)

Callback handlers

type QualityConfig

type QualityConfig struct {
	// Monitoring
	MonitorEnabled  bool
	MonitorInterval time.Duration

	// Thresholds for quality warnings
	MaxPacketLoss float64 // Percentage
	MaxJitter     time.Duration
	MinBitrate    int // kbps

	// Adaptive quality
	AdaptiveQuality      bool
	QualityCheckInterval time.Duration
}

QualityConfig holds quality monitoring configuration

func DefaultQualityConfig

func DefaultQualityConfig() QualityConfig

DefaultQualityConfig returns default quality monitoring configuration

type QualityLayer

type QualityLayer struct {
	RID       string // "f" (full), "h" (half), "q" (quarter)
	MaxWidth  int
	MaxHeight int
	MaxFPS    int
	Bitrate   int
}

QualityLayer represents a simulcast quality layer

type QualityMonitor

type QualityMonitor interface {
	// Monitor starts monitoring peer connection
	Monitor(ctx context.Context, peer PeerConnection) error

	// Stop stops monitoring
	Stop(peerID string)

	// GetQuality returns current quality metrics
	GetQuality(peerID string) (*ConnectionQuality, error)

	// OnQualityChange sets quality change callback
	OnQualityChange(handler QualityChangeHandler)
}

QualityMonitor monitors connection quality

func NewQualityMonitor

func NewQualityMonitor(peerID string, peer PeerConnection, config QualityConfig, logger forge.Logger, metrics forge.Metrics) QualityMonitor

NewQualityMonitor creates a new quality monitor

type QualitySample

type QualitySample struct {
	Timestamp        time.Time
	PacketLoss       float64
	Jitter           time.Duration
	RTT              time.Duration
	Bitrate          uint64
	AvailableBitrate uint64
}

QualitySample represents a quality measurement at a point in time

type RecordOptions

type RecordOptions struct {
	Format      string
	Quality     string
	AudioOnly   bool
	VideoOnly   bool
	MaxDuration time.Duration
}

RecordOptions holds recording configuration options

type Recorder

type Recorder interface {
	// Start starts recording
	Start(ctx context.Context, roomID string, options *RecordingOptions) error

	// Stop stops recording
	Stop(ctx context.Context, roomID string) error

	// Pause pauses recording
	Pause(ctx context.Context, roomID string) error

	// Resume resumes recording
	Resume(ctx context.Context, roomID string) error

	// GetStatus returns recording status
	GetStatus(roomID string) (*RecordingStatus, error)
}

Recorder handles call recording

func NewRecorder

func NewRecorder(roomID string, config RecorderConfig, logger forge.Logger, metrics forge.Metrics) (Recorder, error)

NewRecorder creates a new media recorder

type RecorderConfig

type RecorderConfig struct {
	OutputDir      string
	AudioCodec     string // opus, pcm
	VideoCodec     string // vp8, h264
	EnableAudio    bool
	EnableVideo    bool
	MaxDuration    time.Duration
	FileNamePrefix string
}

RecorderConfig holds recording configuration

func DefaultRecorderConfig

func DefaultRecorderConfig() RecorderConfig

DefaultRecorderConfig returns default recorder configuration

type RecordingOptions

type RecordingOptions struct {
	Format      string // "webm", "mp4"
	VideoCodec  string
	AudioCodec  string
	OutputPath  string
	IncludeChat bool
}

RecordingOptions holds recording options

type RecordingStats

type RecordingStats struct {
	Duration    time.Duration
	FileSize    uint64
	Bitrate     int
	FrameRate   int
	AudioTracks int
	VideoTracks int
	StartTime   time.Time
	EndTime     time.Time
}

RecordingStats holds recording statistics

type RecordingStatus

type RecordingStatus struct {
	RoomID     string
	Recording  bool
	Paused     bool
	StartedAt  time.Time
	Duration   time.Duration
	FileSize   int64
	OutputPath string
}

RecordingStatus represents recording status

type RouterStats

type RouterStats struct {
	TotalTracks        int
	ActiveReceivers    int
	TotalBytesSent     uint64
	TotalBytesReceived uint64
	AverageBitrate     int
}

RouterStats holds SFU router statistics

type SFUCallRoom

type SFUCallRoom struct {
	// contains filtered or unexported fields
}

SFUCallRoom implements CallRoom with SFU topology

func (SFUCallRoom) Close

func (r SFUCallRoom) Close(ctx context.Context) error

Close closes the call room

func (SFUCallRoom) DisableVideo

func (r SFUCallRoom) DisableVideo(ctx context.Context, userID string) error

DisableVideo disables user's video

func (SFUCallRoom) EnableVideo

func (r SFUCallRoom) EnableVideo(ctx context.Context, userID string) error

EnableVideo enables user's video

func (SFUCallRoom) GetParticipants

func (r SFUCallRoom) GetParticipants() []Participant

GetParticipants returns participant information

func (SFUCallRoom) GetPeer

func (r SFUCallRoom) GetPeer(userID string) (PeerConnection, error)

GetPeer returns peer connection for user

func (SFUCallRoom) GetPeers

func (r SFUCallRoom) GetPeers() []PeerConnection

GetPeers returns all peer connections

func (SFUCallRoom) GetQuality

func (r SFUCallRoom) GetQuality(ctx context.Context) (*CallQuality, error)

GetQuality returns call quality metrics (stub implementation)

func (SFUCallRoom) ID

func (r SFUCallRoom) ID() string

ID returns room ID

func (*SFUCallRoom) JoinCall

func (r *SFUCallRoom) JoinCall(ctx context.Context, userID string, opts *JoinOptions) (PeerConnection, error)

JoinCall joins the SFU call

func (SFUCallRoom) Leave

func (r SFUCallRoom) Leave(ctx context.Context, userID string) error

Leave leaves the call

func (SFUCallRoom) MuteUser

func (r SFUCallRoom) MuteUser(ctx context.Context, userID string) error

MuteUser mutes a user's audio

func (SFUCallRoom) Name

func (r SFUCallRoom) Name() string

Name returns room name

func (SFUCallRoom) StartScreenShare

func (r SFUCallRoom) StartScreenShare(ctx context.Context, userID string, track MediaTrack) error

StartScreenShare starts screen sharing (stub implementation)

func (SFUCallRoom) StopScreenShare

func (r SFUCallRoom) StopScreenShare(ctx context.Context, userID string) error

StopScreenShare stops screen sharing (stub implementation)

func (SFUCallRoom) UnmuteUser

func (r SFUCallRoom) UnmuteUser(ctx context.Context, userID string) error

UnmuteUser unmutes a user's audio

type SFUConfig

type SFUConfig struct {
	// Worker configuration
	WorkerCount int

	// Bandwidth management
	MaxBandwidthMbps int
	AdaptiveBitrate  bool
	SimulcastEnabled bool

	// Quality layers for simulcast
	QualityLayers []QualityLayer

	// Recording
	RecordingEnabled bool
	RecordingFormat  string // "webm", "mp4"
}

SFUConfig holds SFU-specific configuration

type SFURouter

type SFURouter interface {
	// RouteTrack routes a track from sender to receivers
	RouteTrack(ctx context.Context, senderID string, track MediaTrack, receiverIDs []string) error

	// AddPublisher adds a publishing peer
	AddPublisher(ctx context.Context, userID string, peer PeerConnection) error

	// AddSubscriber adds a subscribing peer
	AddSubscriber(ctx context.Context, userID string, peer PeerConnection) error

	// RemovePublisher removes a publishing peer
	RemovePublisher(ctx context.Context, userID string) error

	// RemoveSubscriber removes a subscribing peer
	RemoveSubscriber(ctx context.Context, userID string) error

	// SubscribeToTrack subscribes a peer to a publisher's track
	SubscribeToTrack(ctx context.Context, subscriberID, publisherID, trackID string) error

	// UnsubscribeFromTrack unsubscribes a peer from a track
	UnsubscribeFromTrack(ctx context.Context, subscriberID, trackID string) error

	// AddReceiver adds a receiver for a track
	AddReceiver(ctx context.Context, trackID, receiverID string) error

	// RemoveReceiver removes a receiver
	RemoveReceiver(ctx context.Context, trackID, receiverID string) error

	// GetReceivers returns all receivers for a track
	GetReceivers(trackID string) []string

	// SetQuality sets quality layer for receiver
	SetQuality(ctx context.Context, trackID, receiverID, quality string) error

	// GetStats returns routing statistics
	GetStats(ctx context.Context) (*RouterStats, error)

	// GetAvailableTracks returns all available tracks
	GetAvailableTracks() []TrackInfo
}

SFURouter handles media routing in SFU mode

func NewSFURouter

func NewSFURouter(roomID string, logger forge.Logger, metrics forge.Metrics) SFURouter

NewSFURouter creates a new SFU router

type SFUStats

type SFUStats struct {
	TotalTracks        int
	ActiveReceivers    int
	TotalBytesSent     uint64
	TotalBytesReceived uint64
	AverageBitrate     int
	Timestamp          time.Time
}

SFUStats holds SFU router statistics

type SessionDescription

type SessionDescription struct {
	Type SessionDescriptionType
	SDP  string
}

SessionDescription represents SDP

type SessionDescriptionType

type SessionDescriptionType string

SessionDescriptionType is the type of SDP

const (
	SessionDescriptionTypeOffer  SessionDescriptionType = "offer"
	SessionDescriptionTypeAnswer SessionDescriptionType = "answer"
)

type SignalingError

type SignalingError struct {
	Op     string // Operation that failed
	PeerID string
	RoomID string
	Err    error
}

SignalingError wraps signaling errors with context

func (*SignalingError) Error

func (e *SignalingError) Error() string

func (*SignalingError) Unwrap

func (e *SignalingError) Unwrap() error

type SignalingManager

type SignalingManager interface {
	// SendOffer sends SDP offer to peer
	SendOffer(ctx context.Context, roomID, peerID string, offer *SessionDescription) error

	// SendAnswer sends SDP answer to peer
	SendAnswer(ctx context.Context, roomID, peerID string, answer *SessionDescription) error

	// SendICECandidate sends ICE candidate to peer
	SendICECandidate(ctx context.Context, roomID, peerID string, candidate *ICECandidate) error

	// OnOffer sets offer received callback
	OnOffer(handler OfferHandler)

	// OnAnswer sets answer received callback
	OnAnswer(handler AnswerHandler)

	// OnICECandidate sets ICE candidate received callback
	OnICECandidate(handler ICECandidateReceivedHandler)

	// Start begins listening for signaling messages
	Start(ctx context.Context) error

	// Stop stops listening
	Stop(ctx context.Context) error
}

SignalingManager handles WebRTC signaling via streaming

func NewSignalingManager

func NewSignalingManager(streamingExt *streaming.Extension, logger forge.Logger) SignalingManager

NewSignalingManager creates a new signaling manager

type SimulcastLayer

type SimulcastLayer struct {
	RID     string
	Active  bool
	Width   int
	Height  int
	Bitrate int
}

SimulcastLayer represents a simulcast layer

type TURNConfig

type TURNConfig struct {
	URLs       []string
	Username   string
	Credential string

	// TLS configuration
	TLSEnabled  bool
	TLSCertFile string
	TLSKeyFile  string
}

TURNConfig holds TURN server configuration

type Topology

type Topology string

Topology represents the WebRTC connection topology

const (
	// TopologyMesh - Peer-to-peer mesh (each peer connects to all others)
	TopologyMesh Topology = "mesh"

	// TopologySFU - Selective Forwarding Unit (server routes media)
	TopologySFU Topology = "sfu"

	// TopologyMCU - Multipoint Control Unit (server mixes media)
	TopologyMCU Topology = "mcu"
)

type TrackHandler

type TrackHandler func(track MediaTrack, receiver *TrackReceiver)

Callback handlers

type TrackInfo

type TrackInfo struct {
	TrackID     string
	PublisherID string
	Kind        TrackKind
}

Helper types for SFU stats

type TrackKind

type TrackKind string

TrackKind represents track type

const (
	TrackKindAudio TrackKind = "audio"
	TrackKindVideo TrackKind = "video"
)

type TrackReceiver

type TrackReceiver struct {
	TrackID  string
	PeerID   string
	Kind     TrackKind
	Settings TrackSettings
}

TrackReceiver receives a track

type TrackSettings

type TrackSettings struct {
	Width      int
	Height     int
	FrameRate  int
	Bitrate    int
	SampleRate int
	Channels   int
}

TrackSettings represents track settings

type TrackStats

type TrackStats struct {
	TrackID         string
	Kind            TrackKind
	BytesSent       uint64
	BytesReceived   uint64
	PacketsSent     uint64
	PacketsReceived uint64
	PacketsLost     uint64
	Bitrate         int
	FrameRate       int
	Jitter          time.Duration
}

TrackStats holds media track statistics

Directories

Path Synopsis
examples
basic command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL