Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 20 additions & 0 deletions call.go
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,26 @@ func awaitMigrationCompleteOn(client *signal.Client) *event.EventAwaiter[*sfu_ev
})
}

// UseSFU points the call straight at an SFU with credentials the caller already holds, so
// Join skips the coordinator's join-call request.
//
// It is for development and tests against a locally running SFU, where there is no
// coordinator to hand out an SFU and a token. Production calls get both from the
// coordinator and should not use it. Call it before Join. Reconnects keep using the same
// credentials, since there is no coordinator to ask for new ones.
func (c *Call) UseSFU(cred models.Credentials) {
c.GetCred = func(bool, string) (models.Credentials, error) { return cred, nil }
// The reconnect and migration paths read the SFU they were on from here.
c.coordinatorState.Store(&CallState{
Url: cred.Server.URL,
Token: cred.Token,
WebsocketUrl: cred.Server.WsEndpoint,
EdgeName: cred.Server.EdgeName,
})
c.getPeer().client.Store(signal.NewClient(cred, c, c.signalOptions()...))
c.SetCredentials(cred)
}

func (c *Call) SetCredentials(cred models.Credentials) {
c.logger.Debugf("setting credentials: %#+v", cred)
state := c.coordinatorState.Load()
Expand Down
40 changes: 40 additions & 0 deletions use_sfu_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package rtc

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/GetStream/getstream-go-webrtc/internal/testutil"
)

// TestUseSFUJoinsWithoutTheCoordinator joins a call through the public API with credentials
// for an SFU the caller already knows, the way a test against a local SFU does.
func TestUseSFUJoinsWithoutTheCoordinator(t *testing.T) {
t.Parallel()

sfu := testutil.NewFakeSFU()
defer sfu.Close()

const userID = "direct-user"
token, err := testutil.GenerateToken("test-api-key", "test-api-secret", userID, time.Hour)
require.NoError(t, err)
client, err := NewClient(token.APIKey, User{ID: userID}, StaticToken(token.Token),
WithoutCoordinatorWS())
require.NoError(t, err)

call := client.Call(testutil.DefaultCallType, "direct-call")
call.UseSFU(fakeSFUCredentials(sfu, "local-sfu", "sfu-token"))

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, err = call.Join(ctx)
require.NoError(t, err)
t.Cleanup(func() { _ = call.Leave("test over") })

join := nextJoinRequest(t, sfu)
require.Equal(t, "sfu-token", join.GetToken(), "the SFU gets the token the caller supplied")
require.Equal(t, "local-sfu", call.GetState().EdgeName, "reconnects know which SFU they were on")
}
Loading