@@ -24,6 +24,7 @@ type ICECandidate struct {
24
24
TCPType string `json:"tcpType"`
25
25
SDPMid string `json:"sdpMid"`
26
26
SDPMLineIndex uint16 `json:"sdpMLineIndex"`
27
+ extensions string
27
28
}
28
29
29
30
// Conversion for package ice.
@@ -69,6 +70,8 @@ func newICECandidateFromICE(candidate ice.Candidate, sdpMid string, sdpMLineInde
69
70
SDPMLineIndex : sdpMLineIndex ,
70
71
}
71
72
73
+ newCandidate .setExtensions (candidate .Extensions ())
74
+
72
75
if candidate .RelatedAddress () != nil {
73
76
newCandidate .RelatedAddress = candidate .RelatedAddress ().Address
74
77
newCandidate .RelatedPort = uint16 (candidate .RelatedAddress ().Port ) //nolint:gosec // G115
@@ -77,7 +80,7 @@ func newICECandidateFromICE(candidate ice.Candidate, sdpMid string, sdpMLineInde
77
80
return newCandidate , nil
78
81
}
79
82
80
- func (c ICECandidate ) toICE () (ice.Candidate , error ) {
83
+ func (c ICECandidate ) toICE () (cand ice.Candidate , err error ) {
81
84
candidateID := c .statsID
82
85
switch c .Typ {
83
86
case ICECandidateTypeHost :
@@ -92,7 +95,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
92
95
Priority : c .Priority ,
93
96
}
94
97
95
- return ice .NewCandidateHost (& config )
98
+ cand , err = ice .NewCandidateHost (& config )
96
99
case ICECandidateTypeSrflx :
97
100
config := ice.CandidateServerReflexiveConfig {
98
101
CandidateID : candidateID ,
@@ -106,7 +109,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
106
109
RelPort : int (c .RelatedPort ),
107
110
}
108
111
109
- return ice .NewCandidateServerReflexive (& config )
112
+ cand , err = ice .NewCandidateServerReflexive (& config )
110
113
case ICECandidateTypePrflx :
111
114
config := ice.CandidatePeerReflexiveConfig {
112
115
CandidateID : candidateID ,
@@ -120,7 +123,7 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
120
123
RelPort : int (c .RelatedPort ),
121
124
}
122
125
123
- return ice .NewCandidatePeerReflexive (& config )
126
+ cand , err = ice .NewCandidatePeerReflexive (& config )
124
127
case ICECandidateTypeRelay :
125
128
config := ice.CandidateRelayConfig {
126
129
CandidateID : candidateID ,
@@ -134,10 +137,64 @@ func (c ICECandidate) toICE() (ice.Candidate, error) {
134
137
RelPort : int (c .RelatedPort ),
135
138
}
136
139
137
- return ice .NewCandidateRelay (& config )
140
+ cand , err = ice .NewCandidateRelay (& config )
138
141
default :
139
142
return nil , fmt .Errorf ("%w: %s" , errICECandidateTypeUnknown , c .Typ )
140
143
}
144
+
145
+ if cand != nil && err == nil {
146
+ err = c .exportExtensions (cand )
147
+ }
148
+
149
+ return cand , err
150
+ }
151
+
152
+ func (c * ICECandidate ) setExtensions (ext []ice.CandidateExtension ) {
153
+ var extensions string
154
+
155
+ for i := range ext {
156
+ if i > 0 {
157
+ extensions += " "
158
+ }
159
+
160
+ extensions += ext [i ].Key + " " + ext [i ].Value
161
+ }
162
+
163
+ c .extensions = extensions
164
+ }
165
+
166
+ func (c * ICECandidate ) exportExtensions (cand ice.Candidate ) error {
167
+ extensions := c .extensions
168
+ var ext ice.CandidateExtension
169
+ var field string
170
+
171
+ for i , start := 0 , 0 ; i < len (extensions ); i ++ {
172
+ switch {
173
+ case extensions [i ] == ' ' :
174
+ field = extensions [start :i ]
175
+ start = i + 1
176
+ case i == len (extensions )- 1 :
177
+ field = extensions [start :]
178
+ default :
179
+ continue
180
+ }
181
+
182
+ // Extension keys can't be empty
183
+ hasKey := ext .Key != ""
184
+ if ! hasKey {
185
+ ext .Key = field
186
+ } else {
187
+ ext .Value = field
188
+ }
189
+
190
+ // Extension value can be empty
191
+ if hasKey || i == len (extensions )- 1 {
192
+ cand .AddExtension (ext )
193
+ ext = ice.CandidateExtension {}
194
+ }
195
+ }
196
+
197
+ return nil
141
198
}
142
199
143
200
func convertTypeFromICE (t ice.CandidateType ) (ICECandidateType , error ) {
0 commit comments