@xtr-dev/rondevu-client 0.7.0 → 0.7.2
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.
- package/dist/peer/answering-state.js +3 -15
- package/dist/peer/creating-offer-state.js +5 -16
- package/dist/peer/index.d.ts +4 -0
- package/dist/peer/index.js +21 -4
- package/dist/peer/state.d.ts +6 -0
- package/dist/peer/state.js +24 -1
- package/package.json +1 -1
|
@@ -16,25 +16,13 @@ export class AnsweringState extends PeerState {
|
|
|
16
16
|
type: 'offer',
|
|
17
17
|
sdp: offerSdp
|
|
18
18
|
});
|
|
19
|
+
// Enable trickle ICE - set up handler before ICE gathering starts
|
|
20
|
+
this.setupIceCandidateHandler();
|
|
19
21
|
// Create answer
|
|
20
22
|
const answer = await this.peer.pc.createAnswer();
|
|
21
|
-
await this.peer.pc.setLocalDescription(answer);
|
|
23
|
+
await this.peer.pc.setLocalDescription(answer); // ICE gathering starts here
|
|
22
24
|
// Send answer to server immediately (don't wait for ICE)
|
|
23
25
|
await this.peer.offersApi.answer(offerId, answer.sdp);
|
|
24
|
-
// Enable trickle ICE - send candidates as they arrive
|
|
25
|
-
this.peer.pc.onicecandidate = async (event) => {
|
|
26
|
-
if (event.candidate && offerId) {
|
|
27
|
-
const candidateData = event.candidate.toJSON();
|
|
28
|
-
if (candidateData.candidate && candidateData.candidate !== '') {
|
|
29
|
-
try {
|
|
30
|
-
await this.peer.offersApi.addIceCandidates(offerId, [candidateData]);
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
console.error('Error sending ICE candidate:', err);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
26
|
// Transition to exchanging ICE
|
|
39
27
|
const { ExchangingIceState } = await import('./exchanging-ice-state.js');
|
|
40
28
|
this.peer.setState(new ExchangingIceState(this.peer, offerId, options));
|
|
@@ -16,9 +16,12 @@ export class CreatingOfferState extends PeerState {
|
|
|
16
16
|
const channel = this.peer.pc.createDataChannel(options.dataChannelLabel || 'data');
|
|
17
17
|
this.peer.emitEvent('datachannel', channel);
|
|
18
18
|
}
|
|
19
|
+
// Enable trickle ICE - set up handler before ICE gathering starts
|
|
20
|
+
// Handler will check this.peer.offerId before sending
|
|
21
|
+
this.setupIceCandidateHandler();
|
|
19
22
|
// Create WebRTC offer
|
|
20
23
|
const offer = await this.peer.pc.createOffer();
|
|
21
|
-
await this.peer.pc.setLocalDescription(offer);
|
|
24
|
+
await this.peer.pc.setLocalDescription(offer); // ICE gathering starts here
|
|
22
25
|
// Send offer to server immediately (don't wait for ICE)
|
|
23
26
|
const offers = await this.peer.offersApi.create([{
|
|
24
27
|
sdp: offer.sdp,
|
|
@@ -26,21 +29,7 @@ export class CreatingOfferState extends PeerState {
|
|
|
26
29
|
ttl: options.ttl || 300000
|
|
27
30
|
}]);
|
|
28
31
|
const offerId = offers[0].id;
|
|
29
|
-
this.peer.offerId = offerId;
|
|
30
|
-
// Enable trickle ICE - send candidates as they arrive
|
|
31
|
-
this.peer.pc.onicecandidate = async (event) => {
|
|
32
|
-
if (event.candidate && offerId) {
|
|
33
|
-
const candidateData = event.candidate.toJSON();
|
|
34
|
-
if (candidateData.candidate && candidateData.candidate !== '') {
|
|
35
|
-
try {
|
|
36
|
-
await this.peer.offersApi.addIceCandidates(offerId, [candidateData]);
|
|
37
|
-
}
|
|
38
|
-
catch (err) {
|
|
39
|
-
console.error('Error sending ICE candidate:', err);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
32
|
+
this.peer.offerId = offerId; // Now handler can send candidates
|
|
44
33
|
// Transition to waiting for answer
|
|
45
34
|
const { WaitingForAnswerState } = await import('./waiting-for-answer-state.js');
|
|
46
35
|
this.peer.setState(new WaitingForAnswerState(this.peer, offerId, options));
|
package/dist/peer/index.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export default class RondevuPeer extends EventEmitter<PeerEvents> {
|
|
|
13
13
|
offerId?: string;
|
|
14
14
|
role?: 'offerer' | 'answerer';
|
|
15
15
|
private _state;
|
|
16
|
+
private connectionStateChangeHandler?;
|
|
17
|
+
private dataChannelHandler?;
|
|
18
|
+
private trackHandler?;
|
|
19
|
+
private iceCandidateErrorHandler?;
|
|
16
20
|
/**
|
|
17
21
|
* Current connection state name
|
|
18
22
|
*/
|
package/dist/peer/index.js
CHANGED
|
@@ -42,7 +42,7 @@ export default class RondevuPeer extends EventEmitter {
|
|
|
42
42
|
* Set up peer connection event handlers
|
|
43
43
|
*/
|
|
44
44
|
setupPeerConnection() {
|
|
45
|
-
this.
|
|
45
|
+
this.connectionStateChangeHandler = () => {
|
|
46
46
|
switch (this.pc.connectionState) {
|
|
47
47
|
case 'connected':
|
|
48
48
|
this.setState(new ConnectedState(this));
|
|
@@ -60,15 +60,19 @@ export default class RondevuPeer extends EventEmitter {
|
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
this.pc.
|
|
63
|
+
this.pc.addEventListener('connectionstatechange', this.connectionStateChangeHandler);
|
|
64
|
+
this.dataChannelHandler = (event) => {
|
|
64
65
|
this.emitEvent('datachannel', event.channel);
|
|
65
66
|
};
|
|
66
|
-
this.pc.
|
|
67
|
+
this.pc.addEventListener('datachannel', this.dataChannelHandler);
|
|
68
|
+
this.trackHandler = (event) => {
|
|
67
69
|
this.emitEvent('track', event);
|
|
68
70
|
};
|
|
69
|
-
this.pc.
|
|
71
|
+
this.pc.addEventListener('track', this.trackHandler);
|
|
72
|
+
this.iceCandidateErrorHandler = (event) => {
|
|
70
73
|
console.error('ICE candidate error:', event);
|
|
71
74
|
};
|
|
75
|
+
this.pc.addEventListener('icecandidateerror', this.iceCandidateErrorHandler);
|
|
72
76
|
}
|
|
73
77
|
/**
|
|
74
78
|
* Set new state and emit state change event
|
|
@@ -107,6 +111,19 @@ export default class RondevuPeer extends EventEmitter {
|
|
|
107
111
|
* Close the connection and clean up
|
|
108
112
|
*/
|
|
109
113
|
async close() {
|
|
114
|
+
// Remove RTCPeerConnection event listeners
|
|
115
|
+
if (this.connectionStateChangeHandler) {
|
|
116
|
+
this.pc.removeEventListener('connectionstatechange', this.connectionStateChangeHandler);
|
|
117
|
+
}
|
|
118
|
+
if (this.dataChannelHandler) {
|
|
119
|
+
this.pc.removeEventListener('datachannel', this.dataChannelHandler);
|
|
120
|
+
}
|
|
121
|
+
if (this.trackHandler) {
|
|
122
|
+
this.pc.removeEventListener('track', this.trackHandler);
|
|
123
|
+
}
|
|
124
|
+
if (this.iceCandidateErrorHandler) {
|
|
125
|
+
this.pc.removeEventListener('icecandidateerror', this.iceCandidateErrorHandler);
|
|
126
|
+
}
|
|
110
127
|
await this._state.close();
|
|
111
128
|
this.removeAllListeners();
|
|
112
129
|
}
|
package/dist/peer/state.d.ts
CHANGED
|
@@ -6,12 +6,18 @@ import type RondevuPeer from './index.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export declare abstract class PeerState {
|
|
8
8
|
protected peer: RondevuPeer;
|
|
9
|
+
protected iceCandidateHandler?: (event: RTCPeerConnectionIceEvent) => void;
|
|
9
10
|
constructor(peer: RondevuPeer);
|
|
10
11
|
abstract get name(): string;
|
|
11
12
|
createOffer(options: PeerOptions): Promise<string>;
|
|
12
13
|
answer(offerId: string, offerSdp: string, options: PeerOptions): Promise<void>;
|
|
13
14
|
handleAnswer(sdp: string): Promise<void>;
|
|
14
15
|
handleIceCandidate(candidate: any): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Setup trickle ICE candidate handler
|
|
18
|
+
* Sends local ICE candidates to server as they are discovered
|
|
19
|
+
*/
|
|
20
|
+
protected setupIceCandidateHandler(): void;
|
|
15
21
|
cleanup(): void;
|
|
16
22
|
close(): Promise<void>;
|
|
17
23
|
}
|
package/dist/peer/state.js
CHANGED
|
@@ -21,8 +21,31 @@ export class PeerState {
|
|
|
21
21
|
await this.peer.pc.addIceCandidate(new RTCIceCandidate(candidate));
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Setup trickle ICE candidate handler
|
|
26
|
+
* Sends local ICE candidates to server as they are discovered
|
|
27
|
+
*/
|
|
28
|
+
setupIceCandidateHandler() {
|
|
29
|
+
this.iceCandidateHandler = async (event) => {
|
|
30
|
+
if (event.candidate && this.peer.offerId) {
|
|
31
|
+
const candidateData = event.candidate.toJSON();
|
|
32
|
+
if (candidateData.candidate && candidateData.candidate !== '') {
|
|
33
|
+
try {
|
|
34
|
+
await this.peer.offersApi.addIceCandidates(this.peer.offerId, [candidateData]);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error('Error sending ICE candidate:', err);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
this.peer.pc.addEventListener('icecandidate', this.iceCandidateHandler);
|
|
43
|
+
}
|
|
24
44
|
cleanup() {
|
|
25
|
-
//
|
|
45
|
+
// Clean up ICE candidate handler if it exists
|
|
46
|
+
if (this.iceCandidateHandler) {
|
|
47
|
+
this.peer.pc.removeEventListener('icecandidate', this.iceCandidateHandler);
|
|
48
|
+
}
|
|
26
49
|
}
|
|
27
50
|
async close() {
|
|
28
51
|
this.cleanup();
|