mirror of
https://github.com/strukturag/nextcloud-spreed-signaling
synced 2026-03-14 14:35:44 +01:00
Merge pull request #1208 from strukturag/readlimit-janus-events
Don't limit size of received Janus events.
This commit is contained in:
commit
d069a924fc
4 changed files with 3988 additions and 489 deletions
|
|
@ -156,6 +156,13 @@ websocket url of the signaling server (`ws://127.0.0.1:port/spreed`) or -proxy
|
|||
(`ws://127.0.0.1:port/proxy`) and `subprotocol` must be set to `janus-events`.
|
||||
At least events of type `handles`, `media` and `webrtc` must be subscribed.
|
||||
|
||||
Warning: If the configuration between Janus and the signaling endpoint is
|
||||
interrupted or can't be established, unsent events will be queued by Janus
|
||||
and will use potentially lots of memory there. This can be limited by setting
|
||||
`events_cap_on_reconnect` in `janus.eventhandler.wsevh.jcfg`. By default, all
|
||||
events will be queued as the connection between Janus and the signaling endpoint
|
||||
is assumed to be stable (most likely will be on the same machine).
|
||||
|
||||
Edit the `server.conf` and enter the URL to the websocket endpoint of Janus in
|
||||
the section `[mcu]` and key `url`. During startup, the signaling server will
|
||||
connect to Janus and log information of the gateway.
|
||||
|
|
|
|||
514
sfu/janus/api.go
Normal file
514
sfu/janus/api.go
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
/**
|
||||
* Standalone signaling server for the Nextcloud Spreed app.
|
||||
* Copyright (C) 2026 struktur AG
|
||||
*
|
||||
* @author Joachim Bauch <bauch@struktur.de>
|
||||
*
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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)
|
||||
}
|
||||
3467
sfu/janus/api_easyjson.go
Normal file
3467
sfu/janus/api_easyjson.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
|
|
@ -82,471 +53,12 @@ const (
|
|||
|
||||
// Send pings to peer with this period. Must be less than pongWait.
|
||||
pingPeriod = (pongWait * 9) / 10
|
||||
|
||||
// Maximum message size allowed from peer.
|
||||
maxMessageSize = 64 * 1024
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
|
@ -727,7 +239,6 @@ func (h *EventsHandler) readPump() {
|
|||
return
|
||||
}
|
||||
|
||||
conn.SetReadLimit(maxMessageSize)
|
||||
conn.SetPongHandler(func(msg string) error {
|
||||
now := time.Now()
|
||||
conn.SetReadDeadline(now.Add(pongWait)) // nolint
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue