@live-change/peer-connection-frontend 0.8.34 → 0.8.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,329 +1,313 @@
1
- //import Vue from "vue"
1
+ import { ref, isRef, onUnmounted, getCurrentInstance, unref, reactive, computed, watch } from 'vue'
2
+ import { path, live, actions, api as useApi, inboxReader } from '@live-change/vue3-ssr'
2
3
 
3
4
  const createPeerConnection = (peer, to) => {
4
- return new Vue({
5
- data: {
6
- waitingMessages: [],
7
- state: "created",
8
- rtc: null,
9
- rtcSignalingState: "",
10
- iceGatheringState: "",
11
- iceConnectionState: "",
12
- rtpSenders: [],
13
- offerOptions: null,
14
- answerOptions: null,
15
- remoteTracks: [],
16
- restartOnDisconnect: false // because could not set rtc configuration(firefox)
17
- },
18
- computed: {
19
- to() {
20
- return to
21
- },
22
- summary() {
23
- return {
24
- to: this.to,
25
- state: this.state,
26
- waitingMessages: this.waitingMessages.length,
27
- rtpSenders: this.rtpSenders.map(({ sender, stream }) => {
28
- const { id, kind, label } = sender.track
29
- return { id, kind, label, stream: stream.id }
30
- }),
31
- rtcSignalingState: this.rtcSignalingState,
32
- iceGatheringState: this.iceGatheringState,
33
- iceConnectionState: this.iceConnectionState,
34
- remoteTracks: this.remoteTracks.map(({ track, stream }) => {
35
- const { id, kind, label, muted } = track
36
- return { id, kind, label, muted, stream: stream.id }
37
- }),
38
- }
39
- },
40
- localTracks() {
41
- return peer.localTracks
42
- },
43
- isEnabled() {
44
- return this.state != 'closed' && this.state != 'created'
45
- },
46
- rtcConfiguration() {
47
- return peer.rtcConfiguration
48
- },
49
- clientIp() {
50
- return peer.clientIp
51
- },
52
- isPolite() {
53
- return peer.peerId < this.to
5
+ const waitingMessages = ref([])
6
+ const state = ref("created")
7
+ const rtc = ref(null)
8
+ const rtcSignalingState = ref("")
9
+ const iceGatheringState = ref("")
10
+ const iceConnectionState = ref("")
11
+ const rtpSenders = ref([])
12
+ const offerOptions = ref(null)
13
+ const answerOptions = ref(null)
14
+ const remoteTracks = ref([])
15
+ const restartOnDisconnect = ref(false) // because could not set rtc configuration(firefox)
16
+
17
+ const localTracks = computed(() => peer.localTracks.value)
18
+ const rtcConfiguration = computed(() => peer.rtcConfiguration.value)
19
+ const clientIp = computed(() => peer.clientIp.value)
20
+ const isPolite = computed(() => peer.peerId < to)
21
+
22
+ const isEnabled = computed(() => state.value !== 'closed' && state.value !== 'created')
23
+
24
+ function synchronizeLocalTracks() {
25
+ console.log("SYNCHRONIZE LOCAL TRACKS")
26
+ const tracks = isEnabled.value ? localTracks.value : []
27
+ let removedSenders = []
28
+ for(const senderInfo of rtpSenders.value) {
29
+ const trackInfo = tracks.find(trackInfo => trackInfo.track === senderInfo.sender.track)
30
+ if(!trackInfo) {
31
+ rtc.value.removeTrack(senderInfo.sender)
32
+ removedSenders.push(senderInfo)
33
+ } else if(senderInfo.stream !== trackInfo.stream) {
34
+ senderInfo.stream = trackInfo.stream
35
+ senderInfo.sender.setStreams(trackInfo.stream)
54
36
  }
55
- },
56
- watch: {
57
- isEnabled() {
58
- this.synchronizeLocalTracks()
59
- },
60
- localTracks() {
61
- this.synchronizeLocalTracks()
62
- },
63
- rtcConfiguration(configuration) {
64
- if(this.rtc) {
65
- if(this.rtc.setConfiguration) {
66
- this.rtc.setConfiguration(configuration)
67
- } else {
68
- this.restartOnDisconnect = true
69
- }
70
- }
71
- },
72
- clientIp(newIp, oldIp) {
73
- if(this.rtc) {
74
- this.restartConnection()
75
- }
37
+ }
38
+ for(const removedSenderInfo of removedSenders) {
39
+ rtpSenders.value.splice(rtpSenders.value.indexOf(removedSenderInfo), 1)
40
+ }
41
+ for(const trackInfo of tracks) {
42
+ if(rtpSenders.value.find(senderInfo => senderInfo.sender.track === trackInfo.track)) continue; // existing track
43
+ const sender = rtc.value.addTrack(trackInfo.track, trackInfo.stream)
44
+ rtpSenders.value.push({ sender, stream: trackInfo.stream })
45
+ }
46
+ }
47
+
48
+ watch(() => isEnabled.value && localTracks.value, () => synchronizeLocalTracks(), { immediate: true, deep: true })
49
+
50
+ watch(rtcConfiguration, configuration => {
51
+ if(rtc.value) {
52
+ if(rtc.value.setConfiguration) {
53
+ rtc.value.setConfiguration(configuration)
54
+ } else {
55
+ restartOnDisconnect.value = true
76
56
  }
77
- },
78
- methods: {
79
- async connect() {
80
- console.log("PeerConnection connect")
81
- if(this.rtc) throw new Error("can't connect twice!")
82
- this.state = 'connecting'
83
- this.rtc = new RTCPeerConnection(this.rtcConfiguration)
84
- this.rtcSignalingState = this.rtc.signalingState
85
- this.iceGatheringState = this.rtc.iceGatheringState
86
- this.iceConnectionState = this.rtc.iceConnectionState
87
- this.rtc.addEventListener('negotiationneeded', this.negotiationNeededHandler)
88
- this.rtc.addEventListener('signalingstatechange', this.signalingStateChangeHandler)
89
- this.rtc.addEventListener('icecandidate', this.iceCandidateHandler)
90
- this.rtc.addEventListener('track', this.trackHandler)
91
- this.rtc.addEventListener('icegatheringstatechange', this.iceGatheringStateChangeHandler)
92
- this.rtc.addEventListener('iceconnectionstatechange', this.iceConnectionStateChangeHandler)
93
- for(const message of this.waitingMessages) {
94
- try {
95
- await this.handleMessage(message)
96
- } catch(error) {
97
- console.error("MESSAGE", message, "HANDLING ERROR", error)
98
- }
99
- }
100
- this.waitingMessages = []
101
- },
102
- close() {
103
- console.log("PeerConnection close")
104
- this.state = 'closed'
105
- if(this.rtc) {
106
- this.rtc.close()
107
- this.rtc = null
57
+ }
58
+ })
59
+
60
+ async function restartConnection() {
61
+ console.log("RESTARTING CONNECTION")
62
+ /*if(false && rtc.value.restartIce) {
63
+ console.log("RESTART ICE!")
64
+ rtc.value.restartIce()
65
+ } else {*/
66
+ console.log("RESTART OFFER!")
67
+ const offer =
68
+ await rtc.value.createOffer({ ...offerOptions.value, iceRestart: true })
69
+ if(rtc.value.signalingState !== "stable") {
70
+ console.log("RTC GOT OUT OF STABLE WHILE CREATING OFFER. IGNORE GENERATED OFFER!")
71
+ return
72
+ }
73
+ await rtc.value.setLocalDescription(offer)
74
+ peer.sendMessage({ to, type: "sdp", data: offer })
75
+ }
76
+
77
+ watch(clientIp, ip => {
78
+ if(rtc.value) restartConnection()
79
+ })
80
+
81
+ async function handleNegotiationNeeded(event) {
82
+ console.log("NEGOTIATION NEEDED! IN STATE", rtc.value.signalingState)
83
+ if(!isEnabled.value) return
84
+ if(state.value === 'negotiating') {
85
+ console.log("SKIP NESTED NEGOTIATIONS WITH", to)
86
+ //return
87
+ }
88
+ state.value = 'negotiating'
89
+ // if it's disabled there is no need for offer
90
+ console.log("UPDATING OFFER")
91
+ const offer = await rtc.value.createOffer(offerOptions.value || undefined)
92
+ if(rtc.value.signalingState !== "stable") {
93
+ console.log("RTC GOT OUT OF STABLE WHILE CREATING OFFER. IGNORE GENERATED OFFER!")
94
+ return;
95
+ }
96
+ await rtc.value.setLocalDescription(offer)
97
+ peer.sendMessage({ to, type: "sdp", data: offer })
98
+ console.log("SDP OFFER SET! RTC IN STATE", rtc.value.signalingState)
99
+ }
100
+
101
+ async function handleSignalingStateChange(event) {
102
+ if(state.value === 'closed') return
103
+ console.log("RTC SIGNALING STATE CHANGE", rtc.value.signalingState)
104
+ rtc.valueSignalingState = rtc.value.signalingState
105
+ }
106
+ async function handleIceCandidate(event) {
107
+ if(state.value === 'closed') return
108
+ //console.log("GOT ICE CANDIDATE", event.candidate && event.candidate.candidate)
109
+ peer.sendMessage({ to, type: "ice", data: event.candidate })
110
+ }
111
+ function handleTrack(event) {
112
+ if(state.value === 'closed') return
113
+ const track = event.track
114
+ let stream = event.streams && event.streams[0]
115
+ if(!stream) {
116
+ console.error(`Streamless track ${track.id} ${track.kind} from peer ${to} - something is wrong!`)
117
+ stream = new MediaStream([track])
118
+ }
119
+ const trackInfo = {
120
+ track: event.track,
121
+ stream,
122
+ muted: track.muted,
123
+ removeTrackHandler: () => {
124
+ const trackIndex = remoteTracks.value.findIndex(remoteTrack =>
125
+ remoteTrack.track === track && remoteTrack.stream === stream)
126
+ if(trackIndex !== -1) {
127
+ const trackInfo = remoteTracks.value[trackIndex]
128
+ trackInfo.track.removeEventListener('mute', trackInfo.muteHandler)
129
+ trackInfo.track.removeEventListener('unmute', trackInfo.unmuteHandler)
130
+ remoteTracks.value.splice(trackIndex, 1)
108
131
  }
109
132
  },
110
- async handleMessage(message) {
111
- //console.log("PC", to, "HANDLE MESSAGE", message)
112
- if(this.state == 'created') {
113
- console.log("ADD MESSAGE TO WAITING QUEUE")
114
- this.waitingMessages.push(message)
115
- return
116
- }
117
- if(this.state == 'close') return;
118
- //console.log("DO HANDLE MESSAGE")
119
- switch(message.type) {
120
- case "sdp": {
121
- console.log("RECEIVED SDP", message.data.type, "IN STATE", this.rtc.signalingState)
122
- if(message.data.type == 'offer') {
123
- if(this.rtc.signalingState != "stable") {
124
- console.log("SDP CONFLICT, RECEIVED OFFER IN UNSTABLE STATE")
125
- if(this.isPolite) {
126
- console.log("I AM POLITE SO I WILL ROLLBACK RTC STATE MACHINE")
127
- await this.rtc.setLocalDescription({type: "rollback"}),
128
- await this.rtc.setRemoteDescription(message.data)
129
- console.log("ROLLBACK DONE")
130
- const answer = await this.rtc.createAnswer(this.answerOptions || undefined)
131
- console.log("GOT RTC ANSWER IN STATE", this.rtc.signalingState)
132
- await this.rtc.setLocalDescription(answer)
133
- console.log("LOCAL ANSWER DESCRIPTION SET! SENDING ANSWER!")
134
- peer.sendMessage({ to, type: "sdp", data: answer })
135
- } else {
136
- console.log("I AM NOT POLITE SO I WILL IGNORE OFFER")
137
- }
138
- } else {
139
- console.log("SDP STATE GOOD!")
140
- await this.rtc.setRemoteDescription(message.data)
141
- const answer = await this.rtc.createAnswer(this.answerOptions || undefined)
142
- console.log("GOT RTC ANSWER IN STATE", this.rtc.signalingState)
143
- await this.rtc.setLocalDescription(answer)
144
- console.log("LOCAL ANSWER DESCRIPTION SET! SENDING ANSWER!")
145
- peer.sendMessage({ to, type: "sdp", data: answer })
146
- }
133
+ muteHandler: () => trackInfo.muted = track.muted,
134
+ unmuteHandler: () => trackInfo.muted = track.muted
135
+ }
136
+ if(stream) {
137
+ stream.addEventListener('removetrack', trackInfo.removeTrackHandler)
138
+ }
139
+ const existingTrackInfo = remoteTracks.value.find(remoteTrack => remoteTrack.track === track)
140
+ if(existingTrackInfo) {
141
+ existingTrackInfo.stream = stream // Track stream changed
142
+ } else {
143
+ trackInfo.track.addEventListener('mute', trackInfo.muteHandler)
144
+ trackInfo.track.addEventListener('unmute', trackInfo.unmuteHandler)
145
+ remoteTracks.value.push(trackInfo)
146
+ }
147
+ }
148
+ function handleIceGatheringStateChange(event) {
149
+ if(state.value === 'closed') return
150
+ console.log("ICE GATHERING STATE CHANGED", rtc.value.iceGatheringState)
151
+ iceGatheringState.value = rtc.value.iceGatheringState
152
+ }
153
+ function handleIceConnectionStateChange(event) {
154
+ if(state.value === 'closed') return
155
+ iceConnectionState.value = rtc.value.iceConnectionState
156
+ console.log("ICE GATHERING STATE CHANGED", rtc.value.iceConnectionState)
157
+ if(iceConnectionState.value === 'connected') {
158
+ state.value = 'connected'
159
+ }
160
+ if(iceConnectionState.value === 'failed') {
161
+ state.value = 'failed'
162
+ restartConnection()
163
+ }
164
+ if(iceConnectionState.value === 'disconnected') {
165
+ state.value = 'disconnected'
166
+ }
167
+ }
168
+
169
+ async function handleMessage(message) {
170
+ //console.log("PC", to, "HANDLE MESSAGE", message)
171
+ if(state.value === 'created') {
172
+ console.log("ADD MESSAGE TO WAITING QUEUE")
173
+ waitingMessages.value.push(message)
174
+ return
175
+ }
176
+ if(state.value === 'close') return
177
+ //console.log("DO HANDLE MESSAGE")
178
+ switch(message.type) {
179
+ case "sdp": {
180
+ console.log("RECEIVED SDP", message.data.type, "IN STATE", rtc.value.signalingState)
181
+ if(message.data.type === 'offer') {
182
+ if(rtc.value.signalingState !== "stable") {
183
+ console.log("SDP CONFLICT, RECEIVED OFFER IN UNSTABLE STATE")
184
+ if(isPolite.value) {
185
+ console.log("I AM POLITE SO I WILL ROLLBACK RTC STATE MACHINE")
186
+ await rtc.value.setLocalDescription({ type: "rollback" })
187
+ await rtc.value.setRemoteDescription(message.data)
188
+ console.log("ROLLBACK DONE")
189
+ const answer =
190
+ await rtc.value.createAnswer(answerOptions.value || undefined)
191
+ console.log("GOT RTC ANSWER IN STATE", rtc.value.signalingState)
192
+ await rtc.value.setLocalDescription(answer)
193
+ console.log("LOCAL ANSWER DESCRIPTION SET! SENDING ANSWER!")
194
+ peer.sendMessage({ to, type: "sdp", data: answer })
147
195
  } else {
148
- console.log("GOT ANSWER FROM REMOTE PEER")
149
- await this.rtc.setRemoteDescription(message.data)
150
- }
151
- } break;
152
- case "ice": {
153
- console.log("RECEIVED ICE! IN STATE", this.rtc.signalingState)
154
- let ice = message.data
155
- //if(ice && ice.candidate === "") break;
156
- if(ice && ice.candidate != "") {
157
- console.log("ADDING ICE CANDIDATE", ice.candidate)
158
- await this.rtc.addIceCandidate(new RTCIceCandidate(ice))
159
- } else if(window.RTCPeerConnection.prototype.addIceCandidate.length === 0){
160
- await this.rtc.addIceCandidate()
196
+ console.log("I AM NOT POLITE SO I WILL IGNORE OFFER")
161
197
  }
162
- //console.log("REMOTE ICE CANDIDATE ADDED", ice && ice.candidate)
163
- } break;
164
- case "ping": {
165
- peer.sendMessage({ to, type: "pong", data: message.data})
166
- } break;
167
- case "pong": break; // ignore pong
168
- default:
169
- console.error("Unknown peer message", message)
170
- }
171
- },
172
- synchronizeLocalTracks() {
173
- const tracks = this.isEnabled ? this.localTracks : []
174
- let removedSenders = []
175
- let somethingChanged = false
176
- for(const senderInfo of this.rtpSenders) {
177
- const trackInfo = tracks.find(trackInfo => trackInfo.track == senderInfo.sender.track)
178
- if(!trackInfo) {
179
- this.rtc.removeTrack(senderInfo.sender)
180
- removedSenders.push(senderInfo)
181
- somethingChanged = true
182
- } else if(senderInfo.stream != trackInfo.stream) {
183
- senderInfo.stream = trackInfo.stream
184
- senderInfo.sender.setStreams(trackInfo.stream)
185
- somethingChanged = true
198
+ } else {
199
+ console.log("SDP STATE GOOD!")
200
+ await rtc.value.setRemoteDescription(message.data)
201
+ const answer =
202
+ await rtc.value.createAnswer(answerOptions.value || undefined)
203
+ console.log("GOT RTC ANSWER IN STATE", rtc.value.signalingState)
204
+ await rtc.value.setLocalDescription(answer)
205
+ console.log("LOCAL ANSWER DESCRIPTION SET! SENDING ANSWER!")
206
+ peer.sendMessage({ to, type: "sdp", data: answer })
186
207
  }
187
- }
188
- for(const removedSenderInfo of removedSenders) {
189
- this.rtpSenders.splice(this.rtpSenders.indexOf(removedSenderInfo), 1)
190
- }
191
- for(const trackInfo of tracks) {
192
- if(this.rtpSenders.find(senderInfo => senderInfo.sender.track == trackInfo.track)) continue; // existing track
193
- const sender = this.rtc.addTrack(trackInfo.track, trackInfo.stream)
194
- this.rtpSenders.push({ sender, stream: trackInfo.stream })
195
- somethingChanged = true
196
- }
197
- if(somethingChanged) {
198
- //this.updateOffer() // wait for onnegotiationneeded
199
- }
200
- },
201
- async handleNegotiationNeeded(event) {
202
- console.log("NEGOTIATION NEEDED! IN STATE", this.rtc.signalingState)
203
- if(!this.isEnabled) return
204
- if(this.state == 'negotiating') {
205
- console.log("SKIP NESTED NEGOTIATIONS WITH", this.to)
206
- //return
207
- }
208
- this.state = 'negotiating'
209
- // if it's disabled there is no need for offer
210
- console.log("UPDATING OFFER")
211
- const offer = await this.rtc.createOffer(this.offerOptions || undefined)
212
- if(this.rtc.signalingState != "stable") {
213
- console.log("RTC GOT OUT OF STABLE WHILE CREATING OFFER. IGNORE GENERATED OFFER!")
214
- return;
215
- }
216
- await this.rtc.setLocalDescription(offer)
217
- peer.sendMessage({ to, type: "sdp", data: offer })
218
- console.log("SDP OFFER SET! RTC IN STATE", this.rtc.signalingState)
219
-
220
- },
221
- async handleSignalingStateChange(event) {
222
- if(this.state == 'closed') return;
223
- console.log("RTC SIGNALING STATE CHANGE", this.rtc.signalingState)
224
- this.rtcSignalingState = this.rtc.signalingState
225
- },
226
- async handleIceCandidate(event) {
227
- if(this.state == 'closed') return
228
- //console.log("GOT ICE CANDIDATE", event.candidate && event.candidate.candidate)
229
- peer.sendMessage({ to, type: "ice", data: event.candidate })
230
- },
231
- handleTrack(event) {
232
- if(this.state == 'closed') return
233
- const track = event.track
234
- let stream = event.streams && event.streams[0]
235
- if(!stream) {
236
- console.error(`Streamless track ${track.id} ${track.kind} from peer ${to} - something is wrong!`)
237
- stream = new MediaStream([track])
238
- }
239
- const trackInfo = {
240
- track: event.track,
241
- stream,
242
- muted: track.muted,
243
- removeTrackHandler: () => {
244
- const trackIndex = this.remoteTracks.findIndex(remoteTrack =>
245
- remoteTrack.track == track && remoteTrack.stream == stream)
246
- if(trackIndex != -1) {
247
- const trackInfo = this.remoteTracks[trackIndex]
248
- trackInfo.track.removeEventListener('mute', trackInfo.muteHandler)
249
- trackInfo.track.removeEventListener('unmute', trackInfo.unmuteHandler)
250
- this.remoteTracks.splice(trackIndex, 1)
251
- }
252
- },
253
- muteHandler: () => trackInfo.muted = track.muted,
254
- unmuteHandler: () => trackInfo.muted = track.muted
255
- }
256
- if(stream) {
257
- stream.addEventListener('removetrack', trackInfo.removeTrackHandler)
258
- }
259
- const existingTrackInfo = this.remoteTracks.find(remoteTrack => remoteTrack.track == track)
260
- if(existingTrackInfo) {
261
- existingTrackInfo.stream = stream // Track stream changed
262
208
  } else {
263
- trackInfo.track.addEventListener('mute', trackInfo.muteHandler)
264
- trackInfo.track.addEventListener('unmute', trackInfo.unmuteHandler)
265
- this.remoteTracks.push(trackInfo)
266
- }
267
- },
268
- handleIceGatheringStateChange(event) {
269
- if(this.state == 'closed') return
270
- console.log("ICE GATHERING STATE CHANGED", this.rtc.iceGatheringState)
271
- this.iceGatheringState = this.rtc.iceGatheringState
272
- },
273
- handleIceConnectionStateChange(event) {
274
- if(this.state == 'closed') return
275
- this.iceConnectionState = this.rtc.iceConnectionState
276
- console.log("ICE GATHERING STATE CHANGED", this.rtc.iceConnectionState)
277
- if(this.iceConnectionState == 'connected') {
278
- this.state = 'connected'
279
- }
280
- if(this.iceConnectionState == 'failed') {
281
- this.state = 'failed'
282
- this.restartConnection()
209
+ console.log("GOT ANSWER FROM REMOTE PEER")
210
+ await rtc.value.setRemoteDescription(message.data)
283
211
  }
284
- if(this.iceConnectionState == 'disconnected') {
285
- this.state = 'disconnected'
212
+ } break;
213
+ case "ice": {
214
+ console.log("RECEIVED ICE! IN STATE", rtc.value.signalingState)
215
+ let ice = message.data
216
+ //if(ice && ice.candidate === "") break;
217
+ if(ice && ice.candidate !== "") {
218
+ console.log("ADDING ICE CANDIDATE", ice.candidate)
219
+ await rtc.value.addIceCandidate(new RTCIceCandidate(ice))
220
+ } else if(window.RTCPeerConnection.prototype.addIceCandidate.length === 0){
221
+ await rtc.value.addIceCandidate()
286
222
  }
287
- },
288
- async restartConnection() {
289
- console.log("RESTARTING CONNECTION")
290
- if(false && this.rtc.restartIce) {
291
- console.log("RESTART ICE!")
292
- this.rtc.restartIce()
293
- } else {
294
- console.log("RESTART OFFER!")
295
- const offer = await this.rtc.createOffer({ ...this.offerOptions, iceRestart: true })
296
- if(this.rtc.signalingState != "stable") {
297
- console.log("RTC GOT OUT OF STABLE WHILE CREATING OFFER. IGNORE GENERATED OFFER!")
298
- return;
299
- }
300
- await this.rtc.setLocalDescription(offer)
301
- peer.sendMessage({ to, type: "sdp", data: offer })
302
- }
303
- }
304
- },
305
- created() {
306
- this.negotiationNeededHandler = (e) => this.handleNegotiationNeeded(e)
307
- this.signalingStateChangeHandler = (e) => this.handleSignalingStateChange(e)
308
- this.iceCandidateHandler = (e) => this.handleIceCandidate(e)
309
- this.trackHandler = (e) => this.handleTrack(e)
310
- this.iceGatheringStateChangeHandler = (e) => this.handleIceGatheringStateChange(e)
311
- this.iceConnectionStateChangeHandler = (e) => this.handleIceConnectionStateChange(e)
312
- },
313
- beforeDestroy() {
314
- if(this.state != 'closed') {
315
- this.close()
316
- }
317
- if(this.rtc) {
318
- this.rtc.removeEventListener('negotiationneeded', this.negotiationNeededHandler)
319
- this.rtc.removeEventListener('signalingstatechange', this.signalingStateChangeHandler)
320
- this.rtc.removeEventListener('icecandidate', this.iceCandidateHandler)
321
- this.rtc.removeEventListener('track', this.trackHandler)
322
- this.rtc.removeEventListener('icegatheringstatechanged', this.iceGatheringStateChangeHandler)
323
- this.rtc.removeEventListener('iceconnectionstatechanged', this.iceConnectionStateChangeHandler)
223
+ //console.log("REMOTE ICE CANDIDATE ADDED", ice && ice.candidate)
224
+ } break;
225
+ case "ping": {
226
+ peer.sendMessage({ to, type: "pong", data: message.data})
227
+ } break;
228
+ case "pong": break; // ignore pong
229
+ default:
230
+ console.error("Unknown peer message", message)
231
+ }
232
+ }
233
+
234
+ async function connect() {
235
+ console.log("PeerConnection connect")
236
+ if(rtc.value) throw new Error("can't connect twice!")
237
+ state.value = 'connecting'
238
+ rtc.value = new RTCPeerConnection(rtcConfiguration.value)
239
+ rtcSignalingState.value = rtc.value.signalingState
240
+ iceGatheringState.value = rtc.value.iceGatheringState
241
+ iceConnectionState.value = rtc.value.iceConnectionState
242
+ rtc.value.addEventListener('negotiationneeded', handleNegotiationNeeded)
243
+ rtc.value.addEventListener('signalingstatechange', handleSignalingStateChange)
244
+ rtc.value.addEventListener('icecandidate', handleIceCandidate)
245
+ rtc.value.addEventListener('track', handleTrack)
246
+ rtc.value.addEventListener('icegatheringstatechange', handleIceGatheringStateChange)
247
+ rtc.value.addEventListener('iceconnectionstatechange', handleIceConnectionStateChange)
248
+ for(const message of waitingMessages.value) {
249
+ try {
250
+ await handleMessage(message)
251
+ } catch(error) {
252
+ console.error("MESSAGE", message, "HANDLING ERROR", error)
324
253
  }
325
254
  }
326
- })
255
+ waitingMessages.value = []
256
+ }
257
+ function close() {
258
+ console.log("PeerConnection close")
259
+ state.value = 'closed'
260
+ if(rtc.value) {
261
+ rtc.value.removeEventListener('negotiationneeded', handleNegotiationNeeded)
262
+ rtc.value.removeEventListener('signalingstatechange', handleSignalingStateChange)
263
+ rtc.value.removeEventListener('icecandidate', handleIceCandidate)
264
+ rtc.value.removeEventListener('track', handleTrack)
265
+ rtc.value.removeEventListener('icegatheringstatechanged', handleIceGatheringStateChange)
266
+ rtc.value.removeEventListener('iceconnectionstatechanged', handleIceConnectionStateChange)
267
+ rtc.value.close()
268
+ rtpSenders.value = []
269
+ rtc.value = null
270
+ }
271
+ }
272
+
273
+ function dispose() {
274
+ if(state.value !== 'closed') {
275
+ close()
276
+ }
277
+ }
278
+
279
+ const summary = computed(() => ({
280
+ to: to,
281
+ state: state.value,
282
+ isPolite: isPolite.value,
283
+ waitingMessages: waitingMessages.value.length,
284
+ rtpSenders: rtpSenders.value.map(({ sender, stream }) => {
285
+ const { id, kind, label } = sender.track
286
+ return { id, kind, label, stream: stream.id }
287
+ }),
288
+ rtcSignalingState: rtcSignalingState.value,
289
+ iceGatheringState: iceGatheringState.value,
290
+ iceConnectionState: iceConnectionState.value,
291
+ remoteTracks: remoteTracks.value.map(({ track, stream }) => {
292
+ const { id, kind, label, muted } = track
293
+ return { id, kind, label, muted, stream: stream.id }
294
+ }),
295
+ }))
296
+
297
+ return {
298
+ to,
299
+ state,
300
+ isPolite,
301
+ isEnabled,
302
+ summary,
303
+ remoteTracks,
304
+ connect,
305
+ close,
306
+ restartConnection,
307
+ handleMessage,
308
+ dispose,
309
+ }
310
+
327
311
  }
328
312
 
329
313
  export { createPeerConnection }