package core import ( "io" "net/http" "reflect" "sync/atomic" ) func NewID() uint32 { return id.Add(1) } // Deprecated: use NewID instead func ID(v any) uint32 { p := uintptr(reflect.ValueOf(v).UnsafePointer()) return 0x8000_0000 | uint32(p) } var id atomic.Uint32 type Info interface { SetProtocol(string) SetRemoteAddr(string) SetSource(string) SetURL(string) WithRequest(*http.Request) GetSource() string } // Connection just like webrtc.PeerConnection // - ID and RemoteAddr used for building Connection(s) graph // - FormatName, Protocol, RemoteAddr, Source, URL, SDP, UserAgent used for info about Connection // - FormatName and Protocol has FFmpeg compatible names // - Transport used for auto closing on Stop type Connection struct { ID uint32 `json:"id,omitempty"` FormatName string `json:"format_name,omitempty"` // rtsp, webrtc, mp4, mjpeg, mpjpeg... Protocol string `json:"protocol,omitempty"` // tcp, udp, http, ws, pipe... RemoteAddr string `json:"remote_addr,omitempty"` // host:port other info Source string `json:"source,omitempty"` URL string `json:"url,omitempty"` SDP string `json:"sdp,omitempty"` UserAgent string `json:"user_agent,omitempty"` Medias []*Media `json:"medias,omitempty"` Receivers []*Receiver `json:"receivers,omitempty"` Senders []*Sender `json:"senders,omitempty"` Recv int `json:"bytes_recv,omitempty"` Send int `json:"bytes_send,omitempty"` Transport any `json:"-"` } func (c *Connection) GetMedias() []*Media { return c.Medias } func (c *Connection) GetTrack(media *Media, codec *Codec) (*Receiver, error) { for _, receiver := range c.Receivers { if receiver.Codec == codec { return receiver, nil } } receiver := NewReceiver(media, codec) c.Receivers = append(c.Receivers, receiver) return receiver, nil } func (c *Connection) Stop() error { for _, receiver := range c.Receivers { receiver.Close() } for _, sender := range c.Senders { sender.Close() } if closer, ok := c.Transport.(io.Closer); ok { return closer.Close() } return nil } // Deprecated: func (c *Connection) Codecs() []*Codec { codecs := make([]*Codec, len(c.Senders)) for i, sender := range c.Senders { codecs[i] = sender.Codec } return codecs } func (c *Connection) SetProtocol(s string) { c.Protocol = s } func (c *Connection) SetRemoteAddr(s string) { if c.RemoteAddr == "" { c.RemoteAddr = s } else { c.RemoteAddr += " forwarded " + s } } func (c *Connection) SetSource(s string) { c.Source = s } func (c *Connection) SetURL(s string) { c.URL = s } func (c *Connection) WithRequest(r *http.Request) { if r.Header.Get("Upgrade") == "websocket" { c.Protocol = "ws" } else { c.Protocol = "http" } c.RemoteAddr = r.RemoteAddr if remote := r.Header.Get("X-Forwarded-For"); remote != "" { c.RemoteAddr += " forwarded " + remote } c.UserAgent = r.UserAgent() } func (c *Connection) GetSource() string { return c.Source } // Create like os.Create, init Consumer with existing Transport func Create(w io.Writer) (*Connection, error) { return &Connection{Transport: w}, nil } // Open like os.Open, init Producer from existing Transport func Open(r io.Reader) (*Connection, error) { return &Connection{Transport: r}, nil } // Dial like net.Dial, init Producer via Dialing func Dial(rawURL string) (*Connection, error) { return &Connection{}, nil }