1package webrtc 2 3import ( 4 "fmt" 5 6 "github.com/pion/ice" 7 "github.com/pion/sdp/v2" 8) 9 10// ICECandidate represents a ice candidate 11type ICECandidate struct { 12 statsID string 13 Foundation string `json:"foundation"` 14 Priority uint32 `json:"priority"` 15 Address string `json:"address"` 16 Protocol ICEProtocol `json:"protocol"` 17 Port uint16 `json:"port"` 18 Typ ICECandidateType `json:"type"` 19 Component uint16 `json:"component"` 20 RelatedAddress string `json:"relatedAddress"` 21 RelatedPort uint16 `json:"relatedPort"` 22} 23 24// Conversion for package ice 25 26func newICECandidatesFromICE(iceCandidates []ice.Candidate) ([]ICECandidate, error) { 27 candidates := []ICECandidate{} 28 29 for _, i := range iceCandidates { 30 c, err := newICECandidateFromICE(i) 31 if err != nil { 32 return nil, err 33 } 34 candidates = append(candidates, c) 35 } 36 37 return candidates, nil 38} 39 40func newICECandidateFromICE(i ice.Candidate) (ICECandidate, error) { 41 typ, err := convertTypeFromICE(i.Type()) 42 if err != nil { 43 return ICECandidate{}, err 44 } 45 protocol, err := NewICEProtocol(i.NetworkType().NetworkShort()) 46 if err != nil { 47 return ICECandidate{}, err 48 } 49 50 c := ICECandidate{ 51 statsID: i.ID(), 52 Foundation: "foundation", 53 Priority: i.Priority(), 54 Address: i.Address(), 55 Protocol: protocol, 56 Port: uint16(i.Port()), 57 Component: i.Component(), 58 Typ: typ, 59 } 60 61 if i.RelatedAddress() != nil { 62 c.RelatedAddress = i.RelatedAddress().Address 63 c.RelatedPort = uint16(i.RelatedAddress().Port) 64 } 65 66 return c, nil 67} 68 69func (c ICECandidate) toICE() (ice.Candidate, error) { 70 candidateID := c.statsID 71 switch c.Typ { 72 case ICECandidateTypeHost: 73 config := ice.CandidateHostConfig{ 74 CandidateID: candidateID, 75 Network: c.Protocol.String(), 76 Address: c.Address, 77 Port: int(c.Port), 78 Component: c.Component, 79 } 80 return ice.NewCandidateHost(&config) 81 case ICECandidateTypeSrflx: 82 config := ice.CandidateServerReflexiveConfig{ 83 CandidateID: candidateID, 84 Network: c.Protocol.String(), 85 Address: c.Address, 86 Port: int(c.Port), 87 Component: c.Component, 88 RelAddr: c.RelatedAddress, 89 RelPort: int(c.RelatedPort), 90 } 91 return ice.NewCandidateServerReflexive(&config) 92 case ICECandidateTypePrflx: 93 config := ice.CandidatePeerReflexiveConfig{ 94 CandidateID: candidateID, 95 Network: c.Protocol.String(), 96 Address: c.Address, 97 Port: int(c.Port), 98 Component: c.Component, 99 RelAddr: c.RelatedAddress, 100 RelPort: int(c.RelatedPort), 101 } 102 return ice.NewCandidatePeerReflexive(&config) 103 case ICECandidateTypeRelay: 104 config := ice.CandidateRelayConfig{ 105 CandidateID: candidateID, 106 Network: c.Protocol.String(), 107 Address: c.Address, 108 Port: int(c.Port), 109 Component: c.Component, 110 RelAddr: c.RelatedAddress, 111 RelPort: int(c.RelatedPort), 112 } 113 return ice.NewCandidateRelay(&config) 114 default: 115 return nil, fmt.Errorf("unknown candidate type: %s", c.Typ) 116 } 117} 118 119func convertTypeFromICE(t ice.CandidateType) (ICECandidateType, error) { 120 switch t { 121 case ice.CandidateTypeHost: 122 return ICECandidateTypeHost, nil 123 case ice.CandidateTypeServerReflexive: 124 return ICECandidateTypeSrflx, nil 125 case ice.CandidateTypePeerReflexive: 126 return ICECandidateTypePrflx, nil 127 case ice.CandidateTypeRelay: 128 return ICECandidateTypeRelay, nil 129 default: 130 return ICECandidateType(t), fmt.Errorf("unknown ICE candidate type: %s", t) 131 } 132} 133 134func (c ICECandidate) String() string { 135 ic, err := c.toICE() 136 if err != nil { 137 return fmt.Sprintf("%#v failed to convert to ICE: %s", c, err) 138 } 139 return ic.String() 140} 141 142func iceCandidateToSDP(c ICECandidate) sdp.ICECandidate { 143 return sdp.ICECandidate{ 144 Foundation: c.Foundation, 145 Priority: c.Priority, 146 Address: c.Address, 147 Protocol: c.Protocol.String(), 148 Port: c.Port, 149 Component: c.Component, 150 Typ: c.Typ.String(), 151 RelatedAddress: c.RelatedAddress, 152 RelatedPort: c.RelatedPort, 153 } 154} 155 156// ToJSON returns an ICECandidateInit 157// as indicated by the spec https://w3c.github.io/webrtc-pc/#dom-rtcicecandidate-tojson 158func (c ICECandidate) ToJSON() ICECandidateInit { 159 var sdpmLineIndex uint16 160 return ICECandidateInit{ 161 Candidate: fmt.Sprintf("candidate:%s", iceCandidateToSDP(c).Marshal()), 162 SDPMLineIndex: &sdpmLineIndex, 163 } 164} 165