Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MM-45894] Allow signaling through data channel #865

Merged
merged 6 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/mattermost/mattermost-plugin-calls/server/public v0.0.3
github.com/mattermost/mattermost/server/public v0.1.5-0.20240613070149-4b0ae20ef7b4
github.com/mattermost/morph v1.1.0
github.com/mattermost/rtcd v0.17.1
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be
github.com/mattermost/squirrel v0.2.0
github.com/pkg/errors v0.9.1
github.com/rudderlabs/analytics-go v3.3.3+incompatible
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ github.com/mattermost/mattermost/server/public v0.1.5-0.20240613070149-4b0ae20ef
github.com/mattermost/mattermost/server/public v0.1.5-0.20240613070149-4b0ae20ef7b4/go.mod h1:PDPb/iqzJJ5ZvK/m70oDF55AXN/cOvVFj96Yu4e6j+Q=
github.com/mattermost/morph v1.1.0 h1:Q9vrJbeM3s2jfweGheq12EFIzdNp9a/6IovcbvOQ6Cw=
github.com/mattermost/morph v1.1.0/go.mod h1:gD+EaqX2UMyyuzmF4PFh4r33XneQ8Nzi+0E8nXjMa3A=
github.com/mattermost/rtcd v0.17.1 h1:LsThJFMRuWKf6F7k7IilYUm/9oWb3uQ0N0wBnq3pa+k=
github.com/mattermost/rtcd v0.17.1/go.mod h1:bpGyHeb+JDkDzbrQheenpbrqfPhphW0jr09Jh+rpmpY=
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be h1:dLuT3HxqzTHw7NQsom4QiaHGy4Z9QZ3udQ1Hs7Fz7uE=
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be/go.mod h1:bpGyHeb+JDkDzbrQheenpbrqfPhphW0jr09Jh+rpmpY=
github.com/mattermost/squirrel v0.2.0 h1:8ZWeyf+MWQ2cL7hu9REZgLtz2IJi51qqZEovI3T3TT8=
github.com/mattermost/squirrel v0.2.0/go.mod h1:NPPtk+CdpWre4GxMGoOpzEVFVc0ZoEFyJBZGCtn9nSU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
Expand Down
10 changes: 6 additions & 4 deletions lt/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,12 +597,14 @@ func (u *User) Connect(stopCh chan struct{}) error {
u.callsConfig = callsConfig

enableAV1, _ := u.callsConfig["EnableAV1"].(bool)
enableDCSignaling, _ := u.callsConfig["EnableDCSignaling"].(bool)

callsClient, err := client.New(client.Config{
SiteURL: u.cfg.SiteURL,
AuthToken: apiClient.AuthToken,
ChannelID: u.cfg.ChannelID,
EnableAV1: enableAV1,
SiteURL: u.cfg.SiteURL,
AuthToken: apiClient.AuthToken,
ChannelID: u.cfg.ChannelID,
EnableAV1: enableAV1,
EnableDCSignaling: enableDCSignaling,
}, client.WithLogger(u.log))
if err != nil {
return fmt.Errorf("failed to create calls client: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion lt/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/aws/aws-sdk-go v1.50.3
github.com/hajimehoshi/go-mp3 v0.3.4
github.com/mattermost/mattermost/server/public v0.0.12
github.com/mattermost/rtcd v0.17.1
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be
github.com/pion/rtp v1.8.6
github.com/pion/webrtc/v3 v3.2.41
gopkg.in/hraban/opus.v2 v2.0.0-20230925203106-0188a62cb302
Expand Down
4 changes: 2 additions & 2 deletions lt/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ github.com/mattermost/logr/v2 v2.0.21 h1:CMHsP+nrbRlEC4g7BwOk1GAnMtHkniFhlSQPXy5
github.com/mattermost/logr/v2 v2.0.21/go.mod h1:kZkB/zqKL9e+RY5gB3vGpsyenC+TpuiOenjMkvJJbzc=
github.com/mattermost/mattermost/server/public v0.0.12 h1:iunc9q4/XkArOrndEUn73uFw6v9TOEXEtp6Nm6Iv218=
github.com/mattermost/mattermost/server/public v0.0.12/go.mod h1:Bk+atJcELCIk9Yeq5FoqTr+gra9704+X4amrlwlTgSc=
github.com/mattermost/rtcd v0.17.1 h1:LsThJFMRuWKf6F7k7IilYUm/9oWb3uQ0N0wBnq3pa+k=
github.com/mattermost/rtcd v0.17.1/go.mod h1:bpGyHeb+JDkDzbrQheenpbrqfPhphW0jr09Jh+rpmpY=
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be h1:dLuT3HxqzTHw7NQsom4QiaHGy4Z9QZ3udQ1Hs7Fz7uE=
github.com/mattermost/rtcd v0.17.2-0.20240923221741-4301ac1ad2be/go.mod h1:bpGyHeb+JDkDzbrQheenpbrqfPhphW0jr09Jh+rpmpY=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
14 changes: 14 additions & 0 deletions plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@
"type": "bool",
"default": false,
"help_text": "When set to true it enables using the AV1 codec to encode screen sharing tracks. This can result in improved screen sharing quality for clients that support it.\nNote: this setting won't apply when EnableSimulcast is true."
},
{
"key": "EnableDCSignaling",
"display_name": "Use data channels for signaling (Experimental)",
"type": "bool",
"default": false,
"help_text": "When set to true, clients will use WebRTC data channels for signaling of new media tracks. This can result in a more efficient and less race-prone process, especially in case of frequent WebSocket disconnections."
}
]
},
Expand Down Expand Up @@ -676,6 +683,13 @@
"type": "bool",
"default": false,
"help_text": "When set to true it enables using the AV1 codec to encode screen sharing tracks. This can result in improved screen sharing quality for clients that support it.\nNote: this setting won't apply when EnableSimulcast is true."
},
{
"key": "EnableDCSignaling",
"display_name": "Use data channels for signaling (Experimental)",
"type": "bool",
"default": false,
"help_text": "When set to true, clients will use WebRTC data channels for signaling of new media tracks. This can result in a more efficient and less race-prone process, especially in case of frequent WebSocket disconnections."
}
]
},
Expand Down
10 changes: 10 additions & 0 deletions server/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ type clientConfig struct {
EnableAV1 *bool
// Let the server determine whether or not group calls are allowed (through license checks or otherwise)
GroupCallsAllowed bool
// When set to true it enables experimental support for using the data channel for signaling.
EnableDCSignaling *bool
}

type adminClientConfig struct {
Expand Down Expand Up @@ -265,6 +267,9 @@ func (c *configuration) SetDefaults() {
if c.EnableAV1 == nil {
c.EnableAV1 = model.NewBool(false)
}
if c.EnableDCSignaling == nil {
c.EnableDCSignaling = model.NewBool(false)
}
}

func (c *configuration) IsValid() error {
Expand Down Expand Up @@ -453,6 +458,10 @@ func (c *configuration) Clone() *configuration {
cfg.EnableAV1 = model.NewBool(*c.EnableAV1)
}

if c.EnableDCSignaling != nil {
cfg.EnableDCSignaling = model.NewBool(*c.EnableDCSignaling)
}

return &cfg
}

Expand Down Expand Up @@ -517,6 +526,7 @@ func (p *Plugin) getClientConfig(c *configuration) clientConfig {
HostControlsAllowed: p.licenseChecker.HostControlsAllowed(),
EnableAV1: c.EnableAV1,
GroupCallsAllowed: p.licenseChecker.GroupCallsAllowed(),
EnableDCSignaling: c.EnableDCSignaling,
}
}

Expand Down
36 changes: 21 additions & 15 deletions server/websocket.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ type CallsClientJoinData struct {
Title string
ThreadID string

AV1Support bool
AV1Support bool
DCSignaling bool

// JobID is the id of the job tight to the bot connection to
// a call (e.g. recording, transcription). It's a parameter reserved to the
Expand Down Expand Up @@ -776,11 +777,12 @@ func (p *Plugin) handleJoin(userID, connID, authSessionID string, joinData calls
msg := rtcd.ClientMessage{
Type: rtcd.ClientMessageJoin,
Data: map[string]any{
"callID": us.callID,
"userID": userID,
"sessionID": connID,
"channelID": channelID,
"av1Support": joinData.AV1Support,
"callID": us.callID,
"userID": userID,
"sessionID": connID,
"channelID": channelID,
"av1Support": joinData.AV1Support,
"dcSignaling": joinData.DCSignaling,
},
}
if err := p.rtcdManager.Send(msg, state.Call.Props.RTCDHost); err != nil {
Expand Down Expand Up @@ -809,8 +811,9 @@ func (p *Plugin) handleJoin(userID, connID, authSessionID string, joinData calls
UserID: userID,
SessionID: connID,
Props: rtc.SessionProps{
"channelID": channelID,
"av1Support": joinData.AV1Support,
"channelID": channelID,
"av1Support": joinData.AV1Support,
"dcSignaling": joinData.DCSignaling,
},
}
p.LogDebug("initializing RTC session", "userID", userID, "connID", connID, "channelID", channelID, "callID", us.callID)
Expand All @@ -837,8 +840,9 @@ func (p *Plugin) handleJoin(userID, connID, authSessionID string, joinData calls
CallID: us.callID,
SenderID: p.nodeID,
SessionProps: rtc.SessionProps{
"channelID": channelID,
"av1Support": joinData.AV1Support,
"channelID": channelID,
"av1Support": joinData.AV1Support,
"dcSignaling": joinData.DCSignaling,
},
}, clusterMessageTypeConnect, handlerID); err != nil {
p.LogError("failed to send connect message", "err", err.Error())
Expand Down Expand Up @@ -1169,17 +1173,19 @@ func (p *Plugin) WebSocketMessageHasBeenPosted(connID, userID string, req *model
jobID, _ := req.Data["jobID"].(string)

av1Support, _ := req.Data["av1Support"].(bool)
dcSignaling, _ := req.Data["dcSignaling"].(bool)

remoteAddr, _ := req.Data[model.WebSocketRemoteAddr].(string)
xff, _ := req.Data[model.WebSocketXForwardedFor].(string)

joinData := callsJoinData{
CallsClientJoinData{
ChannelID: channelID,
Title: title,
ThreadID: threadID,
AV1Support: av1Support,
JobID: jobID,
ChannelID: channelID,
Title: title,
ThreadID: threadID,
AV1Support: av1Support,
DCSignaling: dcSignaling,
JobID: jobID,
},
remoteAddr,
xff,
Expand Down
6 changes: 3 additions & 3 deletions standalone/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"extract": "formatjs extract 'src/**/*.{ts,tsx}' --ignore 'src/**/*.d.ts' --out-file i18n/temp.json --id-interpolation-pattern '[sha512:contenthash:base64:6]' && formatjs compile 'i18n/temp.json' --out-file i18n/en.json && rm i18n/temp.json"
},
"dependencies": {
"@mattermost/calls-common": "github:mattermost/calls-common#1ce6defb1ee0c1e0f106ddff8f46c37d10d60b76",
"@mattermost/calls-common": "github:mattermost/calls-common#93c0c8b657f66d16434854e26391c79113aa9a71",
"@mattermost/compass-icons": "0.1.31",
"@msgpack/msgpack": "2.7.1",
"bootstrap": "3.4.1",
Expand Down
1 change: 1 addition & 0 deletions standalone/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export default async function init(cfg: InitConfig) {
authToken: getToken(),
simulcast: callsConfig(store.getState()).EnableSimulcast,
enableAV1: callsConfig(store.getState()).EnableAV1,
dcSignaling: callsConfig(store.getState()).EnableDCSignaling,
};

connectCall(joinData, clientConfig, (ev) => {
Expand Down
2 changes: 2 additions & 0 deletions webapp/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"0fj4bj": "Allow screen sharing",
"10k1Mv": "The URL pointing to a running calls-offloader job service instance.",
"1QvHUW": "Your recording will end in {count, plural, =1 {# minute} other {# minutes}}.",
"1s4g9H": "When set to true, clients will use WebRTC data channels for signaling of new media tracks. This can result in a more efficient and less race-prone process, especially in case of frequent WebSocket disconnections.",
"1vzfaf": "End call for everyone",
"22Lra1": "Here's the call recording",
"23eRB2": "Call connection failed",
Expand Down Expand Up @@ -247,6 +248,7 @@
"kr3shS": "Unable to join call",
"ks1Gvx": "Or hold space bar",
"l/BSzX": "When set to true, simulcast for screen sharing is enabled. This can help to improve screen sharing quality.",
"lE59Z5": "Use data channels for signaling (Experimental)",
"lKv8ex": "Default",
"lRSSL4": "You're already in a call in {channel}.",
"lWsBmL": "Chat unavailable: different team selected. Click here to switch back to {channelName} in {teamName}.",
Expand Down
6 changes: 3 additions & 3 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"dependencies": {
"@floating-ui/react": "0.26.12",
"@mattermost/calls-common": "github:mattermost/calls-common#1ce6defb1ee0c1e0f106ddff8f46c37d10d60b76",
"@mattermost/calls-common": "github:mattermost/calls-common#93c0c8b657f66d16434854e26391c79113aa9a71",
"@msgpack/msgpack": "2.7.1",
"@redux-devtools/extension": "3.2.3",
"core-js": "3.26.1",
Expand Down
7 changes: 7 additions & 0 deletions webapp/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default class CallsClient extends EventEmitter {
private av1Codec: RTCRtpCodecCapability | null = null;

constructor(config: CallsClientConfig) {
logDebug('creating new calls client', JSON.stringify(config));
super();
this.ws = null;
this.peer = null;
Expand Down Expand Up @@ -233,6 +234,11 @@ export default class CallsClient extends EventEmitter {
logWarn('both simulcast and av1 support are enabled');
}

if (this.config.dcSignaling) {
logDebug('enabling DC signaling on client');
joinData.dcSignaling = true;
}

if (!window.isSecureContext) {
throw insecureContextErr;
}
Expand Down Expand Up @@ -299,6 +305,7 @@ export default class CallsClient extends EventEmitter {
logInfo,
},
simulcast: this.config.simulcast,
dcSignaling: this.config.dcSignaling,
});

this.peer = peer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, {ChangeEvent} from 'react';
import {useIntl} from 'react-intl';
import {leftCol, RadioInput, RadioInputLabel, rightCol} from 'src/components/admin_console_settings/common';
import {CustomComponentProps} from 'src/types/mattermost-webapp';

export default function EnableDCSignaling(props: CustomComponentProps) {
const {formatMessage} = useIntl();

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
props.onChange(props.id, e.target.value === 'true');
};

// @ts-ignore val is a boolean, but the signature says 'string'. (being defensive here, just in case)
const checked = props.value === 'true' || props.value === true;

return (
<div
data-testid={props.id}
className='form-group'
>
<label className={'control-label ' + leftCol}>
{formatMessage({defaultMessage: 'Use data channels for signaling (Experimental)'})}
</label>
<div className={rightCol}>
<RadioInputLabel $disabled={props.disabled}>
<RadioInput
data-testid={props.id + 'true'}
type='radio'
value='true'
id={props.id + 'true'}
name={props.id + 'true'}
checked={checked}
onChange={handleChange}
disabled={props.disabled}
/>
{formatMessage({defaultMessage: 'True'})}
</RadioInputLabel>
<RadioInputLabel $disabled={props.disabled}>
<RadioInput
data-testid={props.id + 'false'}
type='radio'
value='false'
id={props.id + 'false'}
name={props.id + 'false'}
checked={!checked}
onChange={handleChange}
disabled={props.disabled}
/>
{formatMessage({defaultMessage: 'False'})}
</RadioInputLabel>
<div
data-testid={props.id + 'help-text'}
className='help-text'
>
{formatMessage({defaultMessage: 'When set to true, clients will use WebRTC data channels for signaling of new media tracks. This can result in a more efficient and less race-prone process, especially in case of frequent WebSocket disconnections.'})}
</div>
</div>
</div>
);
}
3 changes: 3 additions & 0 deletions webapp/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
import {navigateToURL} from 'src/browser_routing';
import AllowScreenSharing from 'src/components/admin_console_settings/allow_screen_sharing';
import EnableAV1 from 'src/components/admin_console_settings/enable_av1';
import EnableDCSignaling from 'src/components/admin_console_settings/enable_dc_signaling';
import EnableIPv6 from 'src/components/admin_console_settings/enable_ipv6';
import EnableRinging from 'src/components/admin_console_settings/enable_ringing';
import EnableSimulcast from 'src/components/admin_console_settings/enable_simulcast';
Expand Down Expand Up @@ -458,6 +459,7 @@ export default class Plugin {
registry.registerAdminConsoleCustomSetting('EnableSimulcast', EnableSimulcast);
registry.registerAdminConsoleCustomSetting('EnableAV1', EnableAV1);
registry.registerAdminConsoleCustomSetting('EnableRinging', EnableRinging);
registry.registerAdminConsoleCustomSetting('EnableDCSignaling', EnableDCSignaling);

// RTCD Service
if (registry.registerAdminConsoleCustomSection) {
Expand Down Expand Up @@ -631,6 +633,7 @@ export default class Plugin {
iceServers: iceConfigs,
simulcast: callsConfig(state).EnableSimulcast,
enableAV1: callsConfig(state).EnableAV1,
dcSignaling: callsConfig(state).EnableDCSignaling,
});
window.currentCallData = CurrentCallDataDefault;

Expand Down
Loading
Loading