summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/webrtc/v3/icetransport.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pion/webrtc/v3/icetransport.go')
-rw-r--r--vendor/github.com/pion/webrtc/v3/icetransport.go368
1 files changed, 368 insertions, 0 deletions
diff --git a/vendor/github.com/pion/webrtc/v3/icetransport.go b/vendor/github.com/pion/webrtc/v3/icetransport.go
new file mode 100644
index 0000000..ba20ec1
--- /dev/null
+++ b/vendor/github.com/pion/webrtc/v3/icetransport.go
@@ -0,0 +1,368 @@
+// +build !js
+
+package webrtc
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/pion/ice/v2"
+ "github.com/pion/logging"
+ "github.com/pion/webrtc/v3/internal/mux"
+)
+
+// ICETransport allows an application access to information about the ICE
+// transport over which packets are sent and received.
+type ICETransport struct {
+ lock sync.RWMutex
+
+ role ICERole
+ // Component ICEComponent
+ // State ICETransportState
+ // gatheringState ICEGathererState
+
+ onConnectionStateChangeHandler atomic.Value // func(ICETransportState)
+ onSelectedCandidatePairChangeHandler atomic.Value // func(*ICECandidatePair)
+
+ state atomic.Value // ICETransportState
+
+ gatherer *ICEGatherer
+ conn *ice.Conn
+ mux *mux.Mux
+
+ ctx context.Context
+ ctxCancel func()
+
+ loggerFactory logging.LoggerFactory
+
+ log logging.LeveledLogger
+}
+
+// func (t *ICETransport) GetLocalCandidates() []ICECandidate {
+//
+// }
+//
+// func (t *ICETransport) GetRemoteCandidates() []ICECandidate {
+//
+// }
+//
+// func (t *ICETransport) GetSelectedCandidatePair() ICECandidatePair {
+//
+// }
+//
+// func (t *ICETransport) GetLocalParameters() ICEParameters {
+//
+// }
+//
+// func (t *ICETransport) GetRemoteParameters() ICEParameters {
+//
+// }
+
+// NewICETransport creates a new NewICETransport.
+func NewICETransport(gatherer *ICEGatherer, loggerFactory logging.LoggerFactory) *ICETransport {
+ iceTransport := &ICETransport{
+ gatherer: gatherer,
+ loggerFactory: loggerFactory,
+ log: loggerFactory.NewLogger("ortc"),
+ }
+ iceTransport.setState(ICETransportStateNew)
+ return iceTransport
+}
+
+// Start incoming connectivity checks based on its configured role.
+func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role *ICERole) error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ if t.State() != ICETransportStateNew {
+ return errICETransportNotInNew
+ }
+
+ if gatherer != nil {
+ t.gatherer = gatherer
+ }
+
+ if err := t.ensureGatherer(); err != nil {
+ return err
+ }
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return fmt.Errorf("%w: unable to start ICETransport", errICEAgentNotExist)
+ }
+
+ if err := agent.OnConnectionStateChange(func(iceState ice.ConnectionState) {
+ state := newICETransportStateFromICE(iceState)
+
+ t.setState(state)
+ t.onConnectionStateChange(state)
+ }); err != nil {
+ return err
+ }
+ if err := agent.OnSelectedCandidatePairChange(func(local, remote ice.Candidate) {
+ candidates, err := newICECandidatesFromICE([]ice.Candidate{local, remote})
+ if err != nil {
+ t.log.Warnf("%w: %s", errICECandiatesCoversionFailed, err)
+ return
+ }
+ t.onSelectedCandidatePairChange(NewICECandidatePair(&candidates[0], &candidates[1]))
+ }); err != nil {
+ return err
+ }
+
+ if role == nil {
+ controlled := ICERoleControlled
+ role = &controlled
+ }
+ t.role = *role
+
+ t.ctx, t.ctxCancel = context.WithCancel(context.Background())
+
+ // Drop the lock here to allow ICE candidates to be
+ // added so that the agent can complete a connection
+ t.lock.Unlock()
+
+ var iceConn *ice.Conn
+ var err error
+ switch *role {
+ case ICERoleControlling:
+ iceConn, err = agent.Dial(t.ctx,
+ params.UsernameFragment,
+ params.Password)
+
+ case ICERoleControlled:
+ iceConn, err = agent.Accept(t.ctx,
+ params.UsernameFragment,
+ params.Password)
+
+ default:
+ err = errICERoleUnknown
+ }
+
+ // Reacquire the lock to set the connection/mux
+ t.lock.Lock()
+ if err != nil {
+ return err
+ }
+
+ t.conn = iceConn
+
+ config := mux.Config{
+ Conn: t.conn,
+ BufferSize: receiveMTU,
+ LoggerFactory: t.loggerFactory,
+ }
+ t.mux = mux.NewMux(config)
+
+ return nil
+}
+
+// restart is not exposed currently because ORTC has users create a whole new ICETransport
+// so for now lets keep it private so we don't cause ORTC users to depend on non-standard APIs
+func (t *ICETransport) restart() error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return fmt.Errorf("%w: unable to restart ICETransport", errICEAgentNotExist)
+ }
+
+ if err := agent.Restart(t.gatherer.api.settingEngine.candidates.UsernameFragment, t.gatherer.api.settingEngine.candidates.Password); err != nil {
+ return err
+ }
+ return t.gatherer.Gather()
+}
+
+// Stop irreversibly stops the ICETransport.
+func (t *ICETransport) Stop() error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ t.setState(ICETransportStateClosed)
+
+ if t.ctxCancel != nil {
+ t.ctxCancel()
+ }
+
+ if t.mux != nil {
+ return t.mux.Close()
+ } else if t.gatherer != nil {
+ return t.gatherer.Close()
+ }
+ return nil
+}
+
+// OnSelectedCandidatePairChange sets a handler that is invoked when a new
+// ICE candidate pair is selected
+func (t *ICETransport) OnSelectedCandidatePairChange(f func(*ICECandidatePair)) {
+ t.onSelectedCandidatePairChangeHandler.Store(f)
+}
+
+func (t *ICETransport) onSelectedCandidatePairChange(pair *ICECandidatePair) {
+ handler := t.onSelectedCandidatePairChangeHandler.Load()
+ if handler != nil {
+ handler.(func(*ICECandidatePair))(pair)
+ }
+}
+
+// OnConnectionStateChange sets a handler that is fired when the ICE
+// connection state changes.
+func (t *ICETransport) OnConnectionStateChange(f func(ICETransportState)) {
+ t.onConnectionStateChangeHandler.Store(f)
+}
+
+func (t *ICETransport) onConnectionStateChange(state ICETransportState) {
+ handler := t.onConnectionStateChangeHandler.Load()
+ if handler != nil {
+ handler.(func(ICETransportState))(state)
+ }
+}
+
+// Role indicates the current role of the ICE transport.
+func (t *ICETransport) Role() ICERole {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ return t.role
+}
+
+// SetRemoteCandidates sets the sequence of candidates associated with the remote ICETransport.
+func (t *ICETransport) SetRemoteCandidates(remoteCandidates []ICECandidate) error {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ if err := t.ensureGatherer(); err != nil {
+ return err
+ }
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return fmt.Errorf("%w: unable to set remote candidates", errICEAgentNotExist)
+ }
+
+ for _, c := range remoteCandidates {
+ i, err := c.toICE()
+ if err != nil {
+ return err
+ }
+
+ if err = agent.AddRemoteCandidate(i); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// AddRemoteCandidate adds a candidate associated with the remote ICETransport.
+func (t *ICETransport) AddRemoteCandidate(remoteCandidate *ICECandidate) error {
+ t.lock.RLock()
+ defer t.lock.RUnlock()
+
+ var (
+ c ice.Candidate
+ err error
+ )
+
+ if err = t.ensureGatherer(); err != nil {
+ return err
+ }
+
+ if remoteCandidate != nil {
+ if c, err = remoteCandidate.toICE(); err != nil {
+ return err
+ }
+ }
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return fmt.Errorf("%w: unable to add remote candidates", errICEAgentNotExist)
+ }
+
+ return agent.AddRemoteCandidate(c)
+}
+
+// State returns the current ice transport state.
+func (t *ICETransport) State() ICETransportState {
+ if v := t.state.Load(); v != nil {
+ return v.(ICETransportState)
+ }
+ return ICETransportState(0)
+}
+
+func (t *ICETransport) setState(i ICETransportState) {
+ t.state.Store(i)
+}
+
+// NewEndpoint registers a new endpoint on the underlying mux.
+func (t *ICETransport) NewEndpoint(f mux.MatchFunc) *mux.Endpoint {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+ return t.mux.NewEndpoint(f)
+}
+
+func (t *ICETransport) ensureGatherer() error {
+ if t.gatherer == nil {
+ return errICEGathererNotStarted
+ } else if t.gatherer.getAgent() == nil {
+ if err := t.gatherer.createAgent(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (t *ICETransport) collectStats(collector *statsReportCollector) {
+ t.lock.Lock()
+ conn := t.conn
+ t.lock.Unlock()
+
+ collector.Collecting()
+
+ stats := TransportStats{
+ Timestamp: statsTimestampFrom(time.Now()),
+ Type: StatsTypeTransport,
+ ID: "iceTransport",
+ }
+
+ if conn != nil {
+ stats.BytesSent = conn.BytesSent()
+ stats.BytesReceived = conn.BytesReceived()
+ }
+
+ collector.Collect(stats.ID, stats)
+}
+
+func (t *ICETransport) haveRemoteCredentialsChange(newUfrag, newPwd string) bool {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return false
+ }
+
+ uFrag, uPwd, err := agent.GetRemoteUserCredentials()
+ if err != nil {
+ return false
+ }
+
+ return uFrag != newUfrag || uPwd != newPwd
+}
+
+func (t *ICETransport) setRemoteCredentials(newUfrag, newPwd string) error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ agent := t.gatherer.getAgent()
+ if agent == nil {
+ return fmt.Errorf("%w: unable to SetRemoteCredentials", errICEAgentNotExist)
+ }
+
+ return agent.SetRemoteCredentials(newUfrag, newPwd)
+}