Add support for WHIP ICE Trickle/Restart. (#3596)

* Add support for WHIP ICE Trickle/Restart.

Tested a bit using the WHIP client at https://github.com/Eyevinn/whip,
but needs a lot more testing. ICERestart is not tested yet.

* comment

* clean up
This commit is contained in:
Raja Subramanian
2025-04-09 00:20:58 +05:30
committed by GitHub
parent ec2dff96a3
commit 35ac5f561a
7 changed files with 440 additions and 19 deletions
+4 -4
View File
@@ -23,7 +23,7 @@ require (
github.com/jxskiss/base62 v1.1.0
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1
github.com/livekit/mediatransportutil v0.0.0-20250310153736-45596af895b6
github.com/livekit/protocol v1.36.2-0.20250408143132-c193b8d080da
github.com/livekit/protocol v1.36.2-0.20250408183714-0975d348643e
github.com/livekit/psrpc v0.6.1-0.20250205181828-a0beed2e4126
github.com/mackerelio/go-osstat v0.2.5
github.com/magefile/mage v1.15.0
@@ -55,7 +55,7 @@ require (
go.uber.org/atomic v1.11.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0
golang.org/x/mod v0.24.0
golang.org/x/sync v0.13.0
google.golang.org/protobuf v1.36.6
@@ -133,10 +133,10 @@ require (
github.com/zeebo/xxh3 v1.0.2 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/tools v0.31.0 // indirect
golang.org/x/tools v0.32.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250407143221-ac9807e6c755 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250407143221-ac9807e6c755 // indirect
google.golang.org/grpc v1.71.1 // indirect
+8 -8
View File
@@ -171,8 +171,8 @@ github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1 h1:jm09419p0lqTkD
github.com/livekit/mageutil v0.0.0-20230125210925-54e8a70427c1/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
github.com/livekit/mediatransportutil v0.0.0-20250310153736-45596af895b6 h1:6ZhtnY9I9knfm3ieIPpznQSEU2rDECO8yliW/ANLQ7U=
github.com/livekit/mediatransportutil v0.0.0-20250310153736-45596af895b6/go.mod h1:36s+wwmU3O40IAhE+MjBWP3W71QRiEE9SfooSBvtBqY=
github.com/livekit/protocol v1.36.2-0.20250408143132-c193b8d080da h1:KZ2almsG7lNk0/4FhpLEuX5JOq5QVh8eCVhfsf4821M=
github.com/livekit/protocol v1.36.2-0.20250408143132-c193b8d080da/go.mod h1:WrT/CYRxtMNOVUjnIPm5OjWtEkmreffTeE1PRZwlRg4=
github.com/livekit/protocol v1.36.2-0.20250408183714-0975d348643e h1:uCdTqLPDVdJeJdXkSx7hlfUlY1MBmfBo8fOk2TF28cU=
github.com/livekit/protocol v1.36.2-0.20250408183714-0975d348643e/go.mod h1:WrT/CYRxtMNOVUjnIPm5OjWtEkmreffTeE1PRZwlRg4=
github.com/livekit/psrpc v0.6.1-0.20250205181828-a0beed2e4126 h1:fzuYpAQbCid7ySPpQWWePfQOWUrs8x6dJ0T3Wl07n+Y=
github.com/livekit/psrpc v0.6.1-0.20250205181828-a0beed2e4126/go.mod h1:X5WtEZ7OnEs72Fi5/J+i0on3964F1aynQpCalcgMqRo=
github.com/mackerelio/go-osstat v0.2.5 h1:+MqTbZUhoIt4m8qzkVoXUJg1EuifwlAJSk4Yl2GXh+o=
@@ -367,8 +367,8 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM=
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -399,8 +399,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -471,8 +471,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+1 -5
View File
@@ -903,11 +903,7 @@ func (p *ParticipantImpl) HandleOffer(offer webrtc.SessionDescription) error {
}
offer = p.setCodecPreferencesForPublisher(offer)
err := p.TransportManager.HandleOffer(offer, shouldPend)
if p.params.UseOneShotSignallingMode {
p.updateState(livekit.ParticipantInfo_ACTIVE)
}
return err
return p.TransportManager.HandleOffer(offer, shouldPend)
}
func (p *ParticipantImpl) onPublisherAnswer(answer webrtc.SessionDescription) error {
+189 -2
View File
@@ -93,6 +93,11 @@ var (
ErrMidNotFound = errors.New("mid not found")
ErrNotSynchronousPeerConnectionMode = errors.New("not using synchronous peer connection mode")
ErrNoRemoteDescription = errors.New("no remote description")
ErrNoLocalDescription = errors.New("no local description")
ErrInvalidSDPFragment = errors.New("invalid sdp fragment")
ErrNoBundleMid = errors.New("could not get bundle mid")
ErrMidMismatch = errors.New("media mid does not match bundle mid")
ErrICECredentialMismatch = errors.New("ice credential mismatch")
)
// -------------------------------------------------------------------------
@@ -871,7 +876,7 @@ func (t *PCTransport) isFullyEstablished() bool {
t.lock.RLock()
defer t.lock.RUnlock()
dataChannelReady := t.firstOfferNoDataChannel || (t.reliableDCOpened && t.lossyDCOpened)
dataChannelReady := t.params.UseOneShotSignallingMode || t.firstOfferNoDataChannel || (t.reliableDCOpened && t.lossyDCOpened)
return dataChannelReady && !t.connectedAt.IsZero()
}
@@ -1317,6 +1322,188 @@ func (t *PCTransport) GetAnswer() (webrtc.SessionDescription, error) {
return *cld, nil
}
func (t *PCTransport) GetICESessionUfrag() (string, error) {
cld := t.pc.CurrentLocalDescription()
if cld == nil {
return "", ErrNoLocalDescription
}
parsed, err := cld.Unmarshal()
if err != nil {
return "", err
}
ufrag, _, err := lksdp.ExtractICECredential(parsed)
if err != nil {
return "", err
}
return ufrag, nil
}
// Handles SDP Fragment for ICE Trickle in WHIP
func (t *PCTransport) HandleICETrickleSDPFragment(sdpFragment string) error {
if !t.params.UseOneShotSignallingMode {
return ErrNotSynchronousPeerConnectionMode
}
parsedFragment := &lksdp.SDPFragment{}
if err := parsedFragment.Unmarshal(sdpFragment); err != nil {
t.params.Logger.Warnw("could not parse SDP fragment", err, "sdpFragment", sdpFragment)
return ErrInvalidSDPFragment
}
crd := t.pc.CurrentRemoteDescription()
if crd == nil {
t.params.Logger.Warnw("no remote description", nil)
return ErrNoRemoteDescription
}
parsedRemote, err := crd.Unmarshal()
if err != nil {
t.params.Logger.Warnw("could not parse remote description", err, "offer", crd)
return err
}
// check if BUNDLE mid matches the "mid" in the SDP fragment
bundleMid, found := lksdp.GetBundleMid(parsedRemote)
if !found {
return ErrNoBundleMid
}
if parsedFragment.Mid() != bundleMid {
t.params.Logger.Warnw("incorrect mid", nil, "sdpFragment", sdpFragment)
return ErrMidMismatch
}
fragmentICEUfrag, fragmentICEPwd, err := parsedFragment.ExtractICECredential()
if err != nil {
t.params.Logger.Warnw(
"could not get ICE crendential from fragment", err,
"sdpFragment", sdpFragment,
)
return ErrInvalidSDPFragment
}
remoteICEUfrag, remoteICEPwd, err := lksdp.ExtractICECredential(parsedRemote)
if err != nil {
t.params.Logger.Warnw("could not get ICE crendential from remote description", err, "sdpFragment", sdpFragment, "remoteDescription", crd)
return err
}
if fragmentICEUfrag != "" && fragmentICEUfrag != remoteICEUfrag {
t.params.Logger.Warnw(
"ice ufrag mismatch", nil,
"remoteICEUfrag", remoteICEUfrag,
"fragmentICEUfrag", fragmentICEUfrag,
"sdpFragment", sdpFragment,
"remoteDescription", crd,
)
return ErrICECredentialMismatch
}
if fragmentICEPwd != "" && fragmentICEPwd != remoteICEPwd {
t.params.Logger.Warnw(
"ice pwd mismatch", nil,
"remoteICEPwd", remoteICEPwd,
"fragmentICEPwd", fragmentICEPwd,
"sdpFragment", sdpFragment,
"remoteDescription", crd,
)
return ErrICECredentialMismatch
}
// add candidates from media description
for _, ic := range parsedFragment.Candidates() {
c, err := ice.UnmarshalCandidate(ic)
if err == nil {
t.connectionDetails.AddRemoteICECandidate(c, false, false, false)
}
candidate := webrtc.ICECandidateInit{
Candidate: ic,
}
if err := t.pc.AddICECandidate(candidate); err != nil {
t.params.Logger.Warnw("failed to add ICE candidate", err, "candidate", candidate)
} else {
t.params.Logger.Debugw("added ICE candidate", "candidate", candidate)
}
}
return nil
}
// Handles SDP Fragment for ICE Restart in WHIP
func (t *PCTransport) HandleICERestartSDPFragment(sdpFragment string) (string, error) {
if !t.params.UseOneShotSignallingMode {
return "", ErrNotSynchronousPeerConnectionMode
}
parsedFragment := &lksdp.SDPFragment{}
if err := parsedFragment.Unmarshal(sdpFragment); err != nil {
t.params.Logger.Warnw("could not parse SDP fragment", err, "sdpFragment", sdpFragment)
return "", ErrInvalidSDPFragment
}
crd := t.pc.CurrentRemoteDescription()
if crd == nil {
t.params.Logger.Warnw("no remote description", nil)
return "", ErrNoRemoteDescription
}
parsedRemote, err := crd.Unmarshal()
if err != nil {
t.params.Logger.Warnw("could not parse remote description", err, "offer", crd)
return "", err
}
if err := parsedFragment.PatchICECredentialIntoSDP(parsedRemote); err != nil {
t.params.Logger.Warnw("could not patch SDP fragment into remote description", err, "offer", crd, "sdpFragment", sdpFragment)
return "", err
}
bytes, err := parsedRemote.Marshal()
if err != nil {
t.params.Logger.Warnw("could not marshal SDP with patched remote", err)
return "", err
}
sd := webrtc.SessionDescription{
SDP: string(bytes),
Type: webrtc.SDPTypeOffer,
}
if err := t.pc.SetRemoteDescription(sd); err != nil {
t.params.Logger.Warnw("could not set remote description", err)
return "", err
}
ans, err := t.pc.CreateAnswer(nil)
if err != nil {
t.params.Logger.Warnw("could not create answer", err)
return "", err
}
if err = t.pc.SetLocalDescription(ans); err != nil {
t.params.Logger.Warnw("could not set local description", err)
return "", err
}
parsedAnswer, err := ans.Unmarshal()
if err != nil {
t.params.Logger.Warnw("could not parse local description", err)
return "", err
}
parsedFragmentAnswer, err := lksdp.ExtractSDPFragment(parsedAnswer)
if err != nil {
t.params.Logger.Warnw("could not extract SDP fragment", err)
return "", err
}
answerFragment, err := parsedFragmentAnswer.Marshal()
if err != nil {
t.params.Logger.Warnw("could not marshal answer SDP fragment", err)
return "", err
}
return answerFragment, nil
}
func (t *PCTransport) OnNegotiationStateChanged(f func(state transport.NegotiationState)) {
t.lock.Lock()
t.onNegotiationStateChanged = f
@@ -1752,7 +1939,7 @@ func (t *PCTransport) handleRemoteICECandidate(e event) error {
}
if err := t.pc.AddICECandidate(*c); err != nil {
t.params.Logger.Warnw("failed to add cached ICE candidate", err, "candidate", c)
t.params.Logger.Warnw("failed to add ICE candidate", err, "candidate", c)
return errors.Wrap(err, "add ice candidate failed")
} else {
t.params.Logger.Debugw("added ICE candidate", "candidate", c)
+12
View File
@@ -462,6 +462,18 @@ func (t *TransportManager) GetAnswer() (webrtc.SessionDescription, error) {
return answer, err
}
func (t *TransportManager) GetPublisherICESessionUfrag() (string, error) {
return t.publisher.GetICESessionUfrag()
}
func (t *TransportManager) HandleICETrickleSDPFragment(sdpFragment string) error {
return t.publisher.HandleICETrickleSDPFragment(sdpFragment)
}
func (t *TransportManager) HandleICERestartSDPFragment(sdpFragment string) (string, error) {
return t.publisher.HandleICERestartSDPFragment(sdpFragment)
}
func (t *TransportManager) ProcessPendingPublisherOffer() {
t.lock.Lock()
pendingOffer := t.pendingOfferPublisher
+3
View File
@@ -340,6 +340,7 @@ type LocalParticipant interface {
GetICEConnectionInfo() []*ICEConnectionInfo
HasConnected() bool
GetEnabledPublishCodecs() []*livekit.Codec
GetPublisherICESessionUfrag() (string, error)
SetResponseSink(sink routing.MessageSink)
CloseSignalConnection(reason SignallingCloseReason)
@@ -367,6 +368,8 @@ type LocalParticipant interface {
AddICECandidate(candidate webrtc.ICECandidateInit, target livekit.SignalTarget)
HandleOffer(sdp webrtc.SessionDescription) error
GetAnswer() (webrtc.SessionDescription, error)
HandleICETrickleSDPFragment(sdpFragment string) error
HandleICERestartSDPFragment(sdpFragment string) (string, error)
AddTrack(req *livekit.AddTrackRequest)
SetTrackMuted(trackID livekit.TrackID, muted bool, fromAdmin bool) *livekit.TrackInfo
@@ -390,6 +390,18 @@ type FakeLocalParticipant struct {
getPublishedTracksReturnsOnCall map[int]struct {
result1 []types.MediaTrack
}
GetPublisherICESessionUfragStub func() (string, error)
getPublisherICESessionUfragMutex sync.RWMutex
getPublisherICESessionUfragArgsForCall []struct {
}
getPublisherICESessionUfragReturns struct {
result1 string
result2 error
}
getPublisherICESessionUfragReturnsOnCall map[int]struct {
result1 string
result2 error
}
GetSubscribedParticipantsStub func() []livekit.ParticipantID
getSubscribedParticipantsMutex sync.RWMutex
getSubscribedParticipantsArgsForCall []struct {
@@ -425,6 +437,30 @@ type FakeLocalParticipant struct {
handleAnswerArgsForCall []struct {
arg1 webrtc.SessionDescription
}
HandleICERestartSDPFragmentStub func(string) (string, error)
handleICERestartSDPFragmentMutex sync.RWMutex
handleICERestartSDPFragmentArgsForCall []struct {
arg1 string
}
handleICERestartSDPFragmentReturns struct {
result1 string
result2 error
}
handleICERestartSDPFragmentReturnsOnCall map[int]struct {
result1 string
result2 error
}
HandleICETrickleSDPFragmentStub func(string) error
handleICETrickleSDPFragmentMutex sync.RWMutex
handleICETrickleSDPFragmentArgsForCall []struct {
arg1 string
}
handleICETrickleSDPFragmentReturns struct {
result1 error
}
handleICETrickleSDPFragmentReturnsOnCall map[int]struct {
result1 error
}
HandleMetricsStub func(livekit.ParticipantID, *livekit.MetricsBatch) error
handleMetricsMutex sync.RWMutex
handleMetricsArgsForCall []struct {
@@ -3124,6 +3160,62 @@ func (fake *FakeLocalParticipant) GetPublishedTracksReturnsOnCall(i int, result1
}{result1}
}
func (fake *FakeLocalParticipant) GetPublisherICESessionUfrag() (string, error) {
fake.getPublisherICESessionUfragMutex.Lock()
ret, specificReturn := fake.getPublisherICESessionUfragReturnsOnCall[len(fake.getPublisherICESessionUfragArgsForCall)]
fake.getPublisherICESessionUfragArgsForCall = append(fake.getPublisherICESessionUfragArgsForCall, struct {
}{})
stub := fake.GetPublisherICESessionUfragStub
fakeReturns := fake.getPublisherICESessionUfragReturns
fake.recordInvocation("GetPublisherICESessionUfrag", []interface{}{})
fake.getPublisherICESessionUfragMutex.Unlock()
if stub != nil {
return stub()
}
if specificReturn {
return ret.result1, ret.result2
}
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeLocalParticipant) GetPublisherICESessionUfragCallCount() int {
fake.getPublisherICESessionUfragMutex.RLock()
defer fake.getPublisherICESessionUfragMutex.RUnlock()
return len(fake.getPublisherICESessionUfragArgsForCall)
}
func (fake *FakeLocalParticipant) GetPublisherICESessionUfragCalls(stub func() (string, error)) {
fake.getPublisherICESessionUfragMutex.Lock()
defer fake.getPublisherICESessionUfragMutex.Unlock()
fake.GetPublisherICESessionUfragStub = stub
}
func (fake *FakeLocalParticipant) GetPublisherICESessionUfragReturns(result1 string, result2 error) {
fake.getPublisherICESessionUfragMutex.Lock()
defer fake.getPublisherICESessionUfragMutex.Unlock()
fake.GetPublisherICESessionUfragStub = nil
fake.getPublisherICESessionUfragReturns = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeLocalParticipant) GetPublisherICESessionUfragReturnsOnCall(i int, result1 string, result2 error) {
fake.getPublisherICESessionUfragMutex.Lock()
defer fake.getPublisherICESessionUfragMutex.Unlock()
fake.GetPublisherICESessionUfragStub = nil
if fake.getPublisherICESessionUfragReturnsOnCall == nil {
fake.getPublisherICESessionUfragReturnsOnCall = make(map[int]struct {
result1 string
result2 error
})
}
fake.getPublisherICESessionUfragReturnsOnCall[i] = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeLocalParticipant) GetSubscribedParticipants() []livekit.ParticipantID {
fake.getSubscribedParticipantsMutex.Lock()
ret, specificReturn := fake.getSubscribedParticipantsReturnsOnCall[len(fake.getSubscribedParticipantsArgsForCall)]
@@ -3315,6 +3407,131 @@ func (fake *FakeLocalParticipant) HandleAnswerArgsForCall(i int) webrtc.SessionD
return argsForCall.arg1
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragment(arg1 string) (string, error) {
fake.handleICERestartSDPFragmentMutex.Lock()
ret, specificReturn := fake.handleICERestartSDPFragmentReturnsOnCall[len(fake.handleICERestartSDPFragmentArgsForCall)]
fake.handleICERestartSDPFragmentArgsForCall = append(fake.handleICERestartSDPFragmentArgsForCall, struct {
arg1 string
}{arg1})
stub := fake.HandleICERestartSDPFragmentStub
fakeReturns := fake.handleICERestartSDPFragmentReturns
fake.recordInvocation("HandleICERestartSDPFragment", []interface{}{arg1})
fake.handleICERestartSDPFragmentMutex.Unlock()
if stub != nil {
return stub(arg1)
}
if specificReturn {
return ret.result1, ret.result2
}
return fakeReturns.result1, fakeReturns.result2
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragmentCallCount() int {
fake.handleICERestartSDPFragmentMutex.RLock()
defer fake.handleICERestartSDPFragmentMutex.RUnlock()
return len(fake.handleICERestartSDPFragmentArgsForCall)
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragmentCalls(stub func(string) (string, error)) {
fake.handleICERestartSDPFragmentMutex.Lock()
defer fake.handleICERestartSDPFragmentMutex.Unlock()
fake.HandleICERestartSDPFragmentStub = stub
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragmentArgsForCall(i int) string {
fake.handleICERestartSDPFragmentMutex.RLock()
defer fake.handleICERestartSDPFragmentMutex.RUnlock()
argsForCall := fake.handleICERestartSDPFragmentArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragmentReturns(result1 string, result2 error) {
fake.handleICERestartSDPFragmentMutex.Lock()
defer fake.handleICERestartSDPFragmentMutex.Unlock()
fake.HandleICERestartSDPFragmentStub = nil
fake.handleICERestartSDPFragmentReturns = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeLocalParticipant) HandleICERestartSDPFragmentReturnsOnCall(i int, result1 string, result2 error) {
fake.handleICERestartSDPFragmentMutex.Lock()
defer fake.handleICERestartSDPFragmentMutex.Unlock()
fake.HandleICERestartSDPFragmentStub = nil
if fake.handleICERestartSDPFragmentReturnsOnCall == nil {
fake.handleICERestartSDPFragmentReturnsOnCall = make(map[int]struct {
result1 string
result2 error
})
}
fake.handleICERestartSDPFragmentReturnsOnCall[i] = struct {
result1 string
result2 error
}{result1, result2}
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragment(arg1 string) error {
fake.handleICETrickleSDPFragmentMutex.Lock()
ret, specificReturn := fake.handleICETrickleSDPFragmentReturnsOnCall[len(fake.handleICETrickleSDPFragmentArgsForCall)]
fake.handleICETrickleSDPFragmentArgsForCall = append(fake.handleICETrickleSDPFragmentArgsForCall, struct {
arg1 string
}{arg1})
stub := fake.HandleICETrickleSDPFragmentStub
fakeReturns := fake.handleICETrickleSDPFragmentReturns
fake.recordInvocation("HandleICETrickleSDPFragment", []interface{}{arg1})
fake.handleICETrickleSDPFragmentMutex.Unlock()
if stub != nil {
return stub(arg1)
}
if specificReturn {
return ret.result1
}
return fakeReturns.result1
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragmentCallCount() int {
fake.handleICETrickleSDPFragmentMutex.RLock()
defer fake.handleICETrickleSDPFragmentMutex.RUnlock()
return len(fake.handleICETrickleSDPFragmentArgsForCall)
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragmentCalls(stub func(string) error) {
fake.handleICETrickleSDPFragmentMutex.Lock()
defer fake.handleICETrickleSDPFragmentMutex.Unlock()
fake.HandleICETrickleSDPFragmentStub = stub
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragmentArgsForCall(i int) string {
fake.handleICETrickleSDPFragmentMutex.RLock()
defer fake.handleICETrickleSDPFragmentMutex.RUnlock()
argsForCall := fake.handleICETrickleSDPFragmentArgsForCall[i]
return argsForCall.arg1
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragmentReturns(result1 error) {
fake.handleICETrickleSDPFragmentMutex.Lock()
defer fake.handleICETrickleSDPFragmentMutex.Unlock()
fake.HandleICETrickleSDPFragmentStub = nil
fake.handleICETrickleSDPFragmentReturns = struct {
result1 error
}{result1}
}
func (fake *FakeLocalParticipant) HandleICETrickleSDPFragmentReturnsOnCall(i int, result1 error) {
fake.handleICETrickleSDPFragmentMutex.Lock()
defer fake.handleICETrickleSDPFragmentMutex.Unlock()
fake.HandleICETrickleSDPFragmentStub = nil
if fake.handleICETrickleSDPFragmentReturnsOnCall == nil {
fake.handleICETrickleSDPFragmentReturnsOnCall = make(map[int]struct {
result1 error
})
}
fake.handleICETrickleSDPFragmentReturnsOnCall[i] = struct {
result1 error
}{result1}
}
func (fake *FakeLocalParticipant) HandleMetrics(arg1 livekit.ParticipantID, arg2 *livekit.MetricsBatch) error {
fake.handleMetricsMutex.Lock()
ret, specificReturn := fake.handleMetricsReturnsOnCall[len(fake.handleMetricsArgsForCall)]
@@ -7702,6 +7919,8 @@ func (fake *FakeLocalParticipant) Invocations() map[string][][]interface{} {
defer fake.getPublishedTrackMutex.RUnlock()
fake.getPublishedTracksMutex.RLock()
defer fake.getPublishedTracksMutex.RUnlock()
fake.getPublisherICESessionUfragMutex.RLock()
defer fake.getPublisherICESessionUfragMutex.RUnlock()
fake.getSubscribedParticipantsMutex.RLock()
defer fake.getSubscribedParticipantsMutex.RUnlock()
fake.getSubscribedTracksMutex.RLock()
@@ -7710,6 +7929,10 @@ func (fake *FakeLocalParticipant) Invocations() map[string][][]interface{} {
defer fake.getTrailerMutex.RUnlock()
fake.handleAnswerMutex.RLock()
defer fake.handleAnswerMutex.RUnlock()
fake.handleICERestartSDPFragmentMutex.RLock()
defer fake.handleICERestartSDPFragmentMutex.RUnlock()
fake.handleICETrickleSDPFragmentMutex.RLock()
defer fake.handleICETrickleSDPFragmentMutex.RUnlock()
fake.handleMetricsMutex.RLock()
defer fake.handleMetricsMutex.RUnlock()
fake.handleOfferMutex.RLock()