diff --git a/sfu/janus/api.go b/sfu/janus/api.go new file mode 100644 index 0000000..b28c7b6 --- /dev/null +++ b/sfu/janus/api.go @@ -0,0 +1,514 @@ +/** + * Standalone signaling server for the Nextcloud Spreed app. + * Copyright (C) 2026 struktur AG + * + * @author Joachim Bauch + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package janus + +import ( + "encoding/json" + "fmt" +) + +const ( + janusEventTypeSession = 1 + + janusEventTypeHandle = 2 + + janusEventTypeExternal = 4 + + janusEventTypeJSEP = 8 + + janusEventTypeWebRTC = 16 + janusEventSubTypeWebRTCICE = 1 + janusEventSubTypeWebRTCLocalCandidate = 2 + janusEventSubTypeWebRTCRemoteCandidate = 3 + janusEventSubTypeWebRTCSelectedPair = 4 + janusEventSubTypeWebRTCDTLS = 5 + janusEventSubTypeWebRTCPeerConnection = 6 + + janusEventTypeMedia = 32 + janusEventSubTypeMediaState = 1 + janusEventSubTypeMediaSlowLink = 2 + janusEventSubTypeMediaStats = 3 + + janusEventTypePlugin = 64 + + janusEventTypeTransport = 128 + + janusEventTypeCore = 256 + janusEventSubTypeCoreStatusStartup = 1 + janusEventSubTypeCoreStatusShutdown = 2 +) + +func unmarshalEvent[T any](data json.RawMessage) (*T, error) { + var e T + if err := json.Unmarshal(data, &e); err != nil { + return nil, err + } + + return &e, nil +} + +func marshalEvent[T any](e T) string { + data, err := json.Marshal(e) + if err != nil { + return fmt.Sprintf("Could not serialize %#v: %s", e, err) + } + + return string(data) +} + +type janusEvent struct { + Emitter string `json:"emitter"` + Type int `json:"type"` + SubType int `json:"subtype,omitempty"` + Timestamp uint64 `json:"timestamp"` + SessionId uint64 `json:"session_id,omitempty"` + HandleId uint64 `json:"handle_id,omitempty"` + OpaqueId uint64 `json:"opaque_id,omitempty"` + Event json.RawMessage `json:"event"` +} + +func (e janusEvent) String() string { + return marshalEvent(e) +} + +func (e janusEvent) Decode() (any, error) { + switch e.Type { + case janusEventTypeSession: + return unmarshalEvent[janusEventSession](e.Event) + case janusEventTypeHandle: + return unmarshalEvent[janusEventHandle](e.Event) + case janusEventTypeExternal: + return unmarshalEvent[janusEventExternal](e.Event) + case janusEventTypeJSEP: + return unmarshalEvent[janusEventJSEP](e.Event) + case janusEventTypeWebRTC: + switch e.SubType { + case janusEventSubTypeWebRTCICE: + return unmarshalEvent[janusEventWebRTCICE](e.Event) + case janusEventSubTypeWebRTCLocalCandidate: + return unmarshalEvent[janusEventWebRTCLocalCandidate](e.Event) + case janusEventSubTypeWebRTCRemoteCandidate: + return unmarshalEvent[janusEventWebRTCRemoteCandidate](e.Event) + case janusEventSubTypeWebRTCSelectedPair: + return unmarshalEvent[janusEventWebRTCSelectedPair](e.Event) + case janusEventSubTypeWebRTCDTLS: + return unmarshalEvent[janusEventWebRTCDTLS](e.Event) + case janusEventSubTypeWebRTCPeerConnection: + return unmarshalEvent[janusEventWebRTCPeerConnection](e.Event) + } + case janusEventTypeMedia: + switch e.SubType { + case janusEventSubTypeMediaState: + return unmarshalEvent[janusEventMediaState](e.Event) + case janusEventSubTypeMediaSlowLink: + return unmarshalEvent[janusEventMediaSlowLink](e.Event) + case janusEventSubTypeMediaStats: + return unmarshalEvent[janusEventMediaStats](e.Event) + } + case janusEventTypePlugin: + return unmarshalEvent[janusEventPlugin](e.Event) + case janusEventTypeTransport: + return unmarshalEvent[janusEventTransport](e.Event) + case janusEventTypeCore: + switch e.SubType { + case janusEventSubTypeCoreStatusStartup: + event, err := unmarshalEvent[janusEventCoreStartup](e.Event) + if err != nil { + return nil, err + } + + switch event.Status { + case "started": + return unmarshalEvent[janusEventStatusStartupInfo](event.Info) + case "update": + return unmarshalEvent[janusEventStatusUpdateInfo](event.Info) + } + + return event, nil + case janusEventSubTypeCoreStatusShutdown: + return unmarshalEvent[janusEventCoreShutdown](e.Event) + } + } + + return nil, fmt.Errorf("unsupported event type %d", e.Type) +} + +type janusEventSessionTransport struct { + Transport string `json:"transport"` + ID string `json:"id"` +} + +// type=1 +type janusEventSession struct { + Name string `json:"name"` // "created", "destroyed", "timeout" + + Transport *janusEventSessionTransport `json:"transport,omitempty"` +} + +func (e janusEventSession) String() string { + return marshalEvent(e) +} + +// type=2 +type janusEventHandle struct { + Name string `json:"name"` // "attached", "detached" + Plugin string `json:"plugin"` + Token string `json:"token,omitempty"` + // Deprecated + OpaqueId string `json:"opaque_id,omitempty"` +} + +func (e janusEventHandle) String() string { + return marshalEvent(e) +} + +// type=4 +type janusEventExternal struct { + Schema string `json:"schema"` + Data json.RawMessage `json:"data"` +} + +func (e janusEventExternal) String() string { + return marshalEvent(e) +} + +// type=8 +type janusEventJSEP struct { + Owner string `json:"owner"` + Jsep struct { + Type string `json:"type"` + SDP string `json:"sdp"` + } `json:"jsep"` +} + +func (e janusEventJSEP) String() string { + return marshalEvent(e) +} + +// type=16, subtype=1 +type janusEventWebRTCICE struct { + ICE string `json:"ice"` // "gathering", "connecting", "connected", "ready" + StreamID int `json:"stream_id"` + ComponentID int `json:"component_id"` +} + +func (e janusEventWebRTCICE) String() string { + return marshalEvent(e) +} + +// type=16, subtype=2 +type janusEventWebRTCLocalCandidate struct { + LocalCandidate string `json:"local-candidate"` + StreamID int `json:"stream_id"` + ComponentID int `json:"component_id"` +} + +func (e janusEventWebRTCLocalCandidate) String() string { + return marshalEvent(e) +} + +// type=16, subtype=3 +type janusEventWebRTCRemoteCandidate struct { + RemoteCandidate string `json:"remote-candidate"` + StreamID int `json:"stream_id"` + ComponentID int `json:"component_id"` +} + +func (e janusEventWebRTCRemoteCandidate) String() string { + return marshalEvent(e) +} + +type janusEventCandidate struct { + Address string `json:"address"` + Port int `json:"port"` + Type string `json:"type"` + Transport string `json:"transport"` + Family int `json:"family"` +} + +func (e janusEventCandidate) String() string { + return marshalEvent(e) +} + +type janusEventCandidates struct { + Local janusEventCandidate `json:"local"` + Remote janusEventCandidate `json:"remote"` +} + +func (e janusEventCandidates) String() string { + return marshalEvent(e) +} + +// type=16, subtype=4 +type janusEventWebRTCSelectedPair struct { + StreamID int `json:"stream_id"` + ComponentID int `json:"component_id"` + + SelectedPair string `json:"selected-pair"` + Candidates janusEventCandidates `json:"candidates"` +} + +func (e janusEventWebRTCSelectedPair) String() string { + return marshalEvent(e) +} + +// type=16, subtype=5 +type janusEventWebRTCDTLS struct { + DTLS string `json:"dtls"` // "trying", "connected" + + StreamID int `json:"stream_id"` + ComponentID int `json:"component_id"` + + Retransmissions int `json:"retransmissions"` +} + +func (e janusEventWebRTCDTLS) String() string { + return marshalEvent(e) +} + +// type=16, subtype=6 +type janusEventWebRTCPeerConnection struct { + Connection string `json:"connection"` // "webrtcup", "hangup" + Reason string `json:"reason,omitempty"` // Only if "connection" == "hangup" +} + +func (e janusEventWebRTCPeerConnection) String() string { + return marshalEvent(e) +} + +// type=32, subtype=1 +type janusEventMediaState struct { + Media string `json:"media"` // "audio", "video" + MID string `json:"mid"` + SubStream *int `json:"substream,omitempty"` + Receiving bool `json:"receiving"` + Seconds int `json:"seconds"` +} + +func (e janusEventMediaState) String() string { + return marshalEvent(e) +} + +// type=32, subtype=2 +type janusEventMediaSlowLink struct { + Media string `json:"media"` // "audio", "video" + MID string `json:"mid"` + SlowLink string `json:"slow_link"` // "uplink", "downlink" + LostLastSec int `json:"lost_lastsec"` +} + +func (e janusEventMediaSlowLink) String() string { + return marshalEvent(e) +} + +type janusMediaStatsRTTValues struct { + NTP uint32 `json:"ntp"` + LSR uint32 `json:"lsr"` + DLSR uint32 `json:"dlsr"` +} + +func (e janusMediaStatsRTTValues) String() string { + return marshalEvent(e) +} + +// type=32, subtype=3 +type janusEventMediaStats struct { + MID string `json:"mid"` + MIndex int `json:"mindex"` + Media string `json:"media"` // "audio", "video", "video-sim1", "video-sim2" + + // Audio / video only + Codec string `json:"codec,omitempty"` + Base uint32 `json:"base"` + Lost int32 `json:"lost"` + LostByRemote int32 `json:"lost-by-remote"` + JitterLocal uint32 `json:"jitter-local"` + JitterRemote uint32 `json:"jitter-remote"` + InLinkQuality uint32 `json:"in-link-quality"` + InMediaLinkQuality uint32 `json:"in-media-link-quality"` + OutLinkQuality uint32 `json:"out-link-quality"` + OutMediaLinkQuality uint32 `json:"out-media-link-quality"` + BytesReceivedLastSec uint32 `json:"bytes-received-lastsec"` + BytesSentLastSec uint32 `json:"bytes-sent-lastsec"` + NacksReceived uint32 `json:"nacks-received"` + NacksSent uint32 `json:"nacks-sent"` + RetransmissionsReceived uint32 `json:"retransmissions-received"` + + // Only for audio / video on layer 0 + RTT uint32 `json:"rtt,omitempty"` + // Only for audio / video on layer 0 if RTCP is active + RTTValues *janusMediaStatsRTTValues `json:"rtt-values,omitempty"` + + // For all media on all layers + PacketsReceived uint32 `json:"packets-received"` + PacketsSent uint32 `json:"packets-sent"` + BytesReceived uint64 `json:"bytes-received"` + BytesSent uint64 `json:"bytes-sent"` + + // For layer 0 if REMB is enabled + REMBBitrate uint32 `json:"remb-bitrate"` +} + +func (e janusEventMediaStats) String() string { + return marshalEvent(e) +} + +// type=64 +type janusEventPlugin struct { + Plugin string `json:"plugin"` + Data json.RawMessage `json:"data"` +} + +func (e janusEventPlugin) String() string { + return marshalEvent(e) +} + +type janusEventTransportWebsocket struct { + Event string `json:"event"` + AdminApi bool `json:"admin_api,omitempty"` + IP string `json:"ip,omitempty"` +} + +// type=128 +type janusEventTransport struct { + Transport string `json:"transport"` + Id string `json:"id"` + Data janusEventTransportWebsocket `json:"data"` +} + +func (e janusEventTransport) String() string { + return marshalEvent(e) +} + +type janusEventDependenciesInfo struct { + Glib2 string `json:"glib2"` + Jansson string `json:"jansson"` + Libnice string `json:"libnice"` + Libsrtp string `json:"libsrtp"` + Libcurl string `json:"libcurl,omitempty"` + Crypto string `json:"crypto"` +} + +func (e janusEventDependenciesInfo) String() string { + return marshalEvent(e) +} + +type janusEventPluginInfo struct { + Name string `json:"name"` + Author string `json:"author"` + Description string `json:"description"` + VersionString string `json:"version_string"` + Version int `json:"version"` +} + +func (e janusEventPluginInfo) String() string { + return marshalEvent(e) +} + +// type=256, subtype=1, status="startup" +type janusEventStatusStartupInfo struct { + Janus string `json:"janus"` + Version int `json:"version"` + VersionString string `json:"version_string"` + Author string `json:"author"` + CommitHash string `json:"commit-hash"` + CompileTime string `json:"compile-time"` + LogToStdout bool `json:"log-to-stdout"` + LogToFile bool `json:"log-to-file"` + LogPath string `json:"log-path,omitempty"` + DataChannels bool `json:"data_channels"` + AcceptingNewSessions bool `json:"accepting-new-sessions"` + SessionTimeout int `json:"session-timeout"` + ReclaimSessionTimeout int `json:"reclaim-session-timeout"` + CandidatesTimeout int `json:"candidates-timeout"` + ServerName string `json:"server-name"` + LocalIP string `json:"local-ip"` + PublicIP string `json:"public-ip,omitempty"` + PublicIPs []string `json:"public-ips,omitempty"` + IPv6 bool `json:"ipv6"` + IPv6LinkLocal bool `json:"ipv6-link-local,omitempty"` + ICELite bool `json:"ice-lite"` + ICETCP bool `json:"ice-tcp"` + ICENomination string `json:"ice-nomination,omitempty"` + ICEConsentFreshness bool `json:"ice-consent-freshness"` + ICEKeepaliveConncheck bool `json:"ice-keepalive-conncheck"` + HangupOnFailed bool `json:"hangup-on-failed"` + FullTrickle bool `json:"full-trickle"` + MDNSEnabled bool `json:"mdns-enabled"` + MinNACKQueue int `json:"min-nack-queue"` + NACKOptimizations bool `json:"nack-optimizations"` + TWCCPeriod int `json:"twcc-period"` + DSCP int `json:"dscp,omitempty"` + DTLSMCU int `json:"dtls-mcu"` + STUNServer string `json:"stun-server,omitempty"` + TURNServer string `json:"turn-server,omitempty"` + AllowForceRelay bool `json:"allow-force-relay,omitempty"` + StaticEventLoops int `json:"static-event-loops"` + LoopIndication bool `json:"loop-indication,omitempty"` + APISecret bool `json:"api_secret"` + AuthToken bool `json:"auth_token"` + EventHandlers bool `json:"event_handlers"` + OpaqueIdInAPI bool `json:"opaqueid_in_api"` + WebRTCEncryption bool `json:"webrtc_encryption"` + + Dependencies *janusEventDependenciesInfo `json:"dependencies,omitempty"` + Transports map[string]janusEventPluginInfo `json:"transports,omitempty"` + Events map[string]janusEventPluginInfo `json:"events,omitempty"` + Loggers map[string]janusEventPluginInfo `json:"loggers,omitempty"` + Plugins map[string]janusEventPluginInfo `json:"plugins,omitempty"` +} + +func (e janusEventStatusStartupInfo) String() string { + return marshalEvent(e) +} + +// type=256, subtype=1, status="update" +type janusEventStatusUpdateInfo struct { + Sessions int `json:"sessions"` + Handles int `json:"handles"` + PeerConnections int `json:"peerconnections"` + StatsPeriod int `json:"stats-period"` +} + +func (e janusEventStatusUpdateInfo) String() string { + return marshalEvent(e) +} + +// type=256, subtype=1 +type janusEventCoreStartup struct { + Status string `json:"status"` + Info json.RawMessage `json:"info"` +} + +func (e janusEventCoreStartup) String() string { + return marshalEvent(e) +} + +// type=256, subtype=2 +type janusEventCoreShutdown struct { + Status string `json:"status"` + Signum int `json:"signum"` +} + +func (e janusEventCoreShutdown) String() string { + return marshalEvent(e) +} diff --git a/sfu/janus/events_handler.go b/sfu/janus/events_handler.go index 475fb8c..37cd4f3 100644 --- a/sfu/janus/events_handler.go +++ b/sfu/janus/events_handler.go @@ -45,35 +45,6 @@ import ( const ( EventsSubprotocol = "janus-events" - janusEventTypeSession = 1 - - janusEventTypeHandle = 2 - - janusEventTypeExternal = 4 - - janusEventTypeJSEP = 8 - - janusEventTypeWebRTC = 16 - janusEventSubTypeWebRTCICE = 1 - janusEventSubTypeWebRTCLocalCandidate = 2 - janusEventSubTypeWebRTCRemoteCandidate = 3 - janusEventSubTypeWebRTCSelectedPair = 4 - janusEventSubTypeWebRTCDTLS = 5 - janusEventSubTypeWebRTCPeerConnection = 6 - - janusEventTypeMedia = 32 - janusEventSubTypeMediaState = 1 - janusEventSubTypeMediaSlowLink = 2 - janusEventSubTypeMediaStats = 3 - - janusEventTypePlugin = 64 - - janusEventTypeTransport = 128 - - janusEventTypeCore = 256 - janusEventSubTypeCoreStatusStartup = 1 - janusEventSubTypeCoreStatusShutdown = 2 - // Time allowed to write a message to the peer. writeWait = 10 * time.Second @@ -88,462 +59,6 @@ var ( bufferPool pool.BufferPool ) -func unmarshalEvent[T any](data json.RawMessage) (*T, error) { - var e T - if err := json.Unmarshal(data, &e); err != nil { - return nil, err - } - - return &e, nil -} - -func marshalEvent[T any](e T) string { - data, err := json.Marshal(e) - if err != nil { - return fmt.Sprintf("Could not serialize %#v: %s", e, err) - } - - return string(data) -} - -type janusEvent struct { - Emitter string `json:"emitter"` - Type int `json:"type"` - SubType int `json:"subtype,omitempty"` - Timestamp uint64 `json:"timestamp"` - SessionId uint64 `json:"session_id,omitempty"` - HandleId uint64 `json:"handle_id,omitempty"` - OpaqueId uint64 `json:"opaque_id,omitempty"` - Event json.RawMessage `json:"event"` -} - -func (e janusEvent) String() string { - return marshalEvent(e) -} - -func (e janusEvent) Decode() (any, error) { - switch e.Type { - case janusEventTypeSession: - return unmarshalEvent[janusEventSession](e.Event) - case janusEventTypeHandle: - return unmarshalEvent[janusEventHandle](e.Event) - case janusEventTypeExternal: - return unmarshalEvent[janusEventExternal](e.Event) - case janusEventTypeJSEP: - return unmarshalEvent[janusEventJSEP](e.Event) - case janusEventTypeWebRTC: - switch e.SubType { - case janusEventSubTypeWebRTCICE: - return unmarshalEvent[janusEventWebRTCICE](e.Event) - case janusEventSubTypeWebRTCLocalCandidate: - return unmarshalEvent[janusEventWebRTCLocalCandidate](e.Event) - case janusEventSubTypeWebRTCRemoteCandidate: - return unmarshalEvent[janusEventWebRTCRemoteCandidate](e.Event) - case janusEventSubTypeWebRTCSelectedPair: - return unmarshalEvent[janusEventWebRTCSelectedPair](e.Event) - case janusEventSubTypeWebRTCDTLS: - return unmarshalEvent[janusEventWebRTCDTLS](e.Event) - case janusEventSubTypeWebRTCPeerConnection: - return unmarshalEvent[janusEventWebRTCPeerConnection](e.Event) - } - case janusEventTypeMedia: - switch e.SubType { - case janusEventSubTypeMediaState: - return unmarshalEvent[janusEventMediaState](e.Event) - case janusEventSubTypeMediaSlowLink: - return unmarshalEvent[janusEventMediaSlowLink](e.Event) - case janusEventSubTypeMediaStats: - return unmarshalEvent[janusEventMediaStats](e.Event) - } - case janusEventTypePlugin: - return unmarshalEvent[janusEventPlugin](e.Event) - case janusEventTypeTransport: - return unmarshalEvent[janusEventTransport](e.Event) - case janusEventTypeCore: - switch e.SubType { - case janusEventSubTypeCoreStatusStartup: - event, err := unmarshalEvent[janusEventCoreStartup](e.Event) - if err != nil { - return nil, err - } - - switch event.Status { - case "started": - return unmarshalEvent[janusEventStatusStartupInfo](event.Info) - case "update": - return unmarshalEvent[janusEventStatusUpdateInfo](event.Info) - } - - return event, nil - case janusEventSubTypeCoreStatusShutdown: - return unmarshalEvent[janusEventCoreShutdown](e.Event) - } - } - - return nil, fmt.Errorf("unsupported event type %d", e.Type) -} - -type janusEventSessionTransport struct { - Transport string `json:"transport"` - ID string `json:"id"` -} - -// type=1 -type janusEventSession struct { - Name string `json:"name"` // "created", "destroyed", "timeout" - - Transport *janusEventSessionTransport `json:"transport,omitempty"` -} - -func (e janusEventSession) String() string { - return marshalEvent(e) -} - -// type=2 -type janusEventHandle struct { - Name string `json:"name"` // "attached", "detached" - Plugin string `json:"plugin"` - Token string `json:"token,omitempty"` - // Deprecated - OpaqueId string `json:"opaque_id,omitempty"` -} - -func (e janusEventHandle) String() string { - return marshalEvent(e) -} - -// type=4 -type janusEventExternal struct { - Schema string `json:"schema"` - Data json.RawMessage `json:"data"` -} - -func (e janusEventExternal) String() string { - return marshalEvent(e) -} - -// type=8 -type janusEventJSEP struct { - Owner string `json:"owner"` - Jsep struct { - Type string `json:"type"` - SDP string `json:"sdp"` - } `json:"jsep"` -} - -func (e janusEventJSEP) String() string { - return marshalEvent(e) -} - -// type=16, subtype=1 -type janusEventWebRTCICE struct { - ICE string `json:"ice"` // "gathering", "connecting", "connected", "ready" - StreamID int `json:"stream_id"` - ComponentID int `json:"component_id"` -} - -func (e janusEventWebRTCICE) String() string { - return marshalEvent(e) -} - -// type=16, subtype=2 -type janusEventWebRTCLocalCandidate struct { - LocalCandidate string `json:"local-candidate"` - StreamID int `json:"stream_id"` - ComponentID int `json:"component_id"` -} - -func (e janusEventWebRTCLocalCandidate) String() string { - return marshalEvent(e) -} - -// type=16, subtype=3 -type janusEventWebRTCRemoteCandidate struct { - RemoteCandidate string `json:"remote-candidate"` - StreamID int `json:"stream_id"` - ComponentID int `json:"component_id"` -} - -func (e janusEventWebRTCRemoteCandidate) String() string { - return marshalEvent(e) -} - -type janusEventCandidate struct { - Address string `json:"address"` - Port int `json:"port"` - Type string `json:"type"` - Transport string `json:"transport"` - Family int `json:"family"` -} - -func (e janusEventCandidate) String() string { - return marshalEvent(e) -} - -type janusEventCandidates struct { - Local janusEventCandidate `json:"local"` - Remote janusEventCandidate `json:"remote"` -} - -func (e janusEventCandidates) String() string { - return marshalEvent(e) -} - -// type=16, subtype=4 -type janusEventWebRTCSelectedPair struct { - StreamID int `json:"stream_id"` - ComponentID int `json:"component_id"` - - SelectedPair string `json:"selected-pair"` - Candidates janusEventCandidates `json:"candidates"` -} - -func (e janusEventWebRTCSelectedPair) String() string { - return marshalEvent(e) -} - -// type=16, subtype=5 -type janusEventWebRTCDTLS struct { - DTLS string `json:"dtls"` // "trying", "connected" - - StreamID int `json:"stream_id"` - ComponentID int `json:"component_id"` - - Retransmissions int `json:"retransmissions"` -} - -func (e janusEventWebRTCDTLS) String() string { - return marshalEvent(e) -} - -// type=16, subtype=6 -type janusEventWebRTCPeerConnection struct { - Connection string `json:"connection"` // "webrtcup", "hangup" - Reason string `json:"reason,omitempty"` // Only if "connection" == "hangup" -} - -func (e janusEventWebRTCPeerConnection) String() string { - return marshalEvent(e) -} - -// type=32, subtype=1 -type janusEventMediaState struct { - Media string `json:"media"` // "audio", "video" - MID string `json:"mid"` - SubStream *int `json:"substream,omitempty"` - Receiving bool `json:"receiving"` - Seconds int `json:"seconds"` -} - -func (e janusEventMediaState) String() string { - return marshalEvent(e) -} - -// type=32, subtype=2 -type janusEventMediaSlowLink struct { - Media string `json:"media"` // "audio", "video" - MID string `json:"mid"` - SlowLink string `json:"slow_link"` // "uplink", "downlink" - LostLastSec int `json:"lost_lastsec"` -} - -func (e janusEventMediaSlowLink) String() string { - return marshalEvent(e) -} - -type janusMediaStatsRTTValues struct { - NTP uint32 `json:"ntp"` - LSR uint32 `json:"lsr"` - DLSR uint32 `json:"dlsr"` -} - -func (e janusMediaStatsRTTValues) String() string { - return marshalEvent(e) -} - -// type=32, subtype=3 -type janusEventMediaStats struct { - MID string `json:"mid"` - MIndex int `json:"mindex"` - Media string `json:"media"` // "audio", "video", "video-sim1", "video-sim2" - - // Audio / video only - Codec string `json:"codec,omitempty"` - Base uint32 `json:"base"` - Lost int32 `json:"lost"` - LostByRemote int32 `json:"lost-by-remote"` - JitterLocal uint32 `json:"jitter-local"` - JitterRemote uint32 `json:"jitter-remote"` - InLinkQuality uint32 `json:"in-link-quality"` - InMediaLinkQuality uint32 `json:"in-media-link-quality"` - OutLinkQuality uint32 `json:"out-link-quality"` - OutMediaLinkQuality uint32 `json:"out-media-link-quality"` - BytesReceivedLastSec uint32 `json:"bytes-received-lastsec"` - BytesSentLastSec uint32 `json:"bytes-sent-lastsec"` - NacksReceived uint32 `json:"nacks-received"` - NacksSent uint32 `json:"nacks-sent"` - RetransmissionsReceived uint32 `json:"retransmissions-received"` - - // Only for audio / video on layer 0 - RTT uint32 `json:"rtt,omitempty"` - // Only for audio / video on layer 0 if RTCP is active - RTTValues *janusMediaStatsRTTValues `json:"rtt-values,omitempty"` - - // For all media on all layers - PacketsReceived uint32 `json:"packets-received"` - PacketsSent uint32 `json:"packets-sent"` - BytesReceived uint64 `json:"bytes-received"` - BytesSent uint64 `json:"bytes-sent"` - - // For layer 0 if REMB is enabled - REMBBitrate uint32 `json:"remb-bitrate"` -} - -func (e janusEventMediaStats) String() string { - return marshalEvent(e) -} - -// type=64 -type janusEventPlugin struct { - Plugin string `json:"plugin"` - Data json.RawMessage `json:"data"` -} - -func (e janusEventPlugin) String() string { - return marshalEvent(e) -} - -type janusEventTransportWebsocket struct { - Event string `json:"event"` - AdminApi bool `json:"admin_api,omitempty"` - IP string `json:"ip,omitempty"` -} - -// type=128 -type janusEventTransport struct { - Transport string `json:"transport"` - Id string `json:"id"` - Data janusEventTransportWebsocket `json:"data"` -} - -func (e janusEventTransport) String() string { - return marshalEvent(e) -} - -type janusEventDependenciesInfo struct { - Glib2 string `json:"glib2"` - Jansson string `json:"jansson"` - Libnice string `json:"libnice"` - Libsrtp string `json:"libsrtp"` - Libcurl string `json:"libcurl,omitempty"` - Crypto string `json:"crypto"` -} - -func (e janusEventDependenciesInfo) String() string { - return marshalEvent(e) -} - -type janusEventPluginInfo struct { - Name string `json:"name"` - Author string `json:"author"` - Description string `json:"description"` - VersionString string `json:"version_string"` - Version int `json:"version"` -} - -func (e janusEventPluginInfo) String() string { - return marshalEvent(e) -} - -// type=256, subtype=1, status="startup" -type janusEventStatusStartupInfo struct { - Janus string `json:"janus"` - Version int `json:"version"` - VersionString string `json:"version_string"` - Author string `json:"author"` - CommitHash string `json:"commit-hash"` - CompileTime string `json:"compile-time"` - LogToStdout bool `json:"log-to-stdout"` - LogToFile bool `json:"log-to-file"` - LogPath string `json:"log-path,omitempty"` - DataChannels bool `json:"data_channels"` - AcceptingNewSessions bool `json:"accepting-new-sessions"` - SessionTimeout int `json:"session-timeout"` - ReclaimSessionTimeout int `json:"reclaim-session-timeout"` - CandidatesTimeout int `json:"candidates-timeout"` - ServerName string `json:"server-name"` - LocalIP string `json:"local-ip"` - PublicIP string `json:"public-ip,omitempty"` - PublicIPs []string `json:"public-ips,omitempty"` - IPv6 bool `json:"ipv6"` - IPv6LinkLocal bool `json:"ipv6-link-local,omitempty"` - ICELite bool `json:"ice-lite"` - ICETCP bool `json:"ice-tcp"` - ICENomination string `json:"ice-nomination,omitempty"` - ICEConsentFreshness bool `json:"ice-consent-freshness"` - ICEKeepaliveConncheck bool `json:"ice-keepalive-conncheck"` - HangupOnFailed bool `json:"hangup-on-failed"` - FullTrickle bool `json:"full-trickle"` - MDNSEnabled bool `json:"mdns-enabled"` - MinNACKQueue int `json:"min-nack-queue"` - NACKOptimizations bool `json:"nack-optimizations"` - TWCCPeriod int `json:"twcc-period"` - DSCP int `json:"dscp,omitempty"` - DTLSMCU int `json:"dtls-mcu"` - STUNServer string `json:"stun-server,omitempty"` - TURNServer string `json:"turn-server,omitempty"` - AllowForceRelay bool `json:"allow-force-relay,omitempty"` - StaticEventLoops int `json:"static-event-loops"` - LoopIndication bool `json:"loop-indication,omitempty"` - APISecret bool `json:"api_secret"` - AuthToken bool `json:"auth_token"` - EventHandlers bool `json:"event_handlers"` - OpaqueIdInAPI bool `json:"opaqueid_in_api"` - WebRTCEncryption bool `json:"webrtc_encryption"` - - Dependencies *janusEventDependenciesInfo `json:"dependencies,omitempty"` - Transports map[string]janusEventPluginInfo `json:"transports,omitempty"` - Events map[string]janusEventPluginInfo `json:"events,omitempty"` - Loggers map[string]janusEventPluginInfo `json:"loggers,omitempty"` - Plugins map[string]janusEventPluginInfo `json:"plugins,omitempty"` -} - -func (e janusEventStatusStartupInfo) String() string { - return marshalEvent(e) -} - -// type=256, subtype=1, status="update" -type janusEventStatusUpdateInfo struct { - Sessions int `json:"sessions"` - Handles int `json:"handles"` - PeerConnections int `json:"peerconnections"` - StatsPeriod int `json:"stats-period"` -} - -func (e janusEventStatusUpdateInfo) String() string { - return marshalEvent(e) -} - -// type=256, subtype=1 -type janusEventCoreStartup struct { - Status string `json:"status"` - Info json.RawMessage `json:"info"` -} - -func (e janusEventCoreStartup) String() string { - return marshalEvent(e) -} - -// type=256, subtype=2 -type janusEventCoreShutdown struct { - Status string `json:"status"` - Signum int `json:"signum"` -} - -func (e janusEventCoreShutdown) String() string { - return marshalEvent(e) -} - type EventHandler interface { UpdateBandwidth(handle uint64, media string, sent api.Bandwidth, received api.Bandwidth) }