Files
client/client.go
2025-07-13 22:30:33 +05:30

150 lines
3.9 KiB
Go

package client
import (
"context"
"errors"
"github.com/pion/interceptor"
"github.com/pion/interceptor/pkg/cc"
"github.com/pion/webrtc/v4"
"github.com/harshabose/tools/pkg/multierr"
)
type Client struct {
peerConnections map[string]*PeerConnection
mediaEngine *webrtc.MediaEngine
settingsEngine *webrtc.SettingEngine
interceptorRegistry *interceptor.Registry
estimatorChan chan cc.BandwidthEstimator
api *webrtc.API
ctx context.Context
cancel context.CancelFunc
}
func NewClient(
ctx context.Context, cancel context.CancelFunc,
mediaEngine *webrtc.MediaEngine, interceptorRegistry *interceptor.Registry,
settings *webrtc.SettingEngine, options ...ClientOption,
) (*Client, error) {
if mediaEngine == nil {
mediaEngine = &webrtc.MediaEngine{}
}
if interceptorRegistry == nil {
interceptorRegistry = &interceptor.Registry{}
}
if settings == nil {
settings = &webrtc.SettingEngine{}
}
settings.DetachDataChannels()
peerConnections := &Client{
mediaEngine: mediaEngine,
interceptorRegistry: interceptorRegistry,
settingsEngine: settings,
peerConnections: make(map[string]*PeerConnection),
estimatorChan: make(chan cc.BandwidthEstimator, 10),
ctx: ctx,
cancel: cancel,
}
for _, option := range options {
if err := option(peerConnections); err != nil {
return nil, err
}
}
peerConnections.api = webrtc.NewAPI(webrtc.WithMediaEngine(peerConnections.mediaEngine), webrtc.WithInterceptorRegistry(peerConnections.interceptorRegistry), webrtc.WithSettingEngine(*peerConnections.settingsEngine))
return peerConnections, nil
}
func NewClientFromConfig(
ctx context.Context, cancel context.CancelFunc,
mediaEngine *webrtc.MediaEngine, interceptorRegistry *interceptor.Registry,
settings *webrtc.SettingEngine, config *ClientConfig,
) (*Client, error) {
return NewClient(
ctx, cancel, mediaEngine, interceptorRegistry, settings,
config.ToOptions()..., // The magic spread operator!
)
}
func (client *Client) CreatePeerConnection(label string, config webrtc.Configuration, options ...PeerConnectionOption) (*PeerConnection, error) {
var err error
if _, exists := client.peerConnections[label]; exists {
return nil, errors.New("peer connection already exists")
}
// TODO: CHANGE THE SIGNATURE; SENDING A CANCEL FUNC IS IDIOTIC
if client.peerConnections[label], err = CreatePeerConnection(client.ctx, client.cancel, label, client.api, config, options...); err != nil {
return nil, err
}
return client.peerConnections[label], nil
}
func (client *Client) CreatePeerConnectionFromConfig(config PeerConnectionConfig) (*PeerConnection, error) {
pc, err := client.CreatePeerConnection(config.Name, config.RTCConfig, config.ToOptions()...)
if err != nil {
return nil, err
}
if err := config.CreateDataChannels(pc); err != nil {
return nil, err
}
if err := config.CreateMediaSources(pc); err != nil {
return nil, err
}
if err := config.CreateMediaSinks(pc); err != nil {
return nil, err
}
return pc, nil
}
func (client *Client) GetPeerConnection(label string) (*PeerConnection, error) {
if _, exists := client.peerConnections[label]; !exists {
return nil, errors.New("peer connection not found")
}
return client.peerConnections[label], nil
}
func (client *Client) WaitUntilClosed() {
<-client.ctx.Done()
}
func (client *Client) Connect(category string) error {
var merr error
for _, pc := range client.peerConnections {
if err := pc.Connect(category); err != nil {
merr = multierr.Append(merr, err)
}
}
return merr
}
func (client *Client) ClosePeerConnection(label string) error {
pc, err := client.GetPeerConnection(label)
if err != nil {
return err
}
return pc.Close()
}
func (client *Client) Close() error {
for _, peerConnection := range client.peerConnections {
if err := peerConnection.Close(); err != nil {
return err
}
}
return nil
}