@noatgnu/cupcake-mint-chocolate 1.2.3 → 1.2.5
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/README.md +83 -36
- package/fesm2022/noatgnu-cupcake-mint-chocolate.mjs +639 -19
- package/fesm2022/noatgnu-cupcake-mint-chocolate.mjs.map +1 -1
- package/index.d.ts +204 -5
- package/package.json +3 -3
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Component, Injectable, inject } from '@angular/core';
|
|
3
|
+
import * as i1 from '@noatgnu/cupcake-core';
|
|
3
4
|
import { BaseApiService } from '@noatgnu/cupcake-core';
|
|
4
5
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
|
5
6
|
import { Subject, BehaviorSubject } from 'rxjs';
|
|
6
7
|
import { filter } from 'rxjs/operators';
|
|
8
|
+
import { webSocket } from 'rxjs/webSocket';
|
|
7
9
|
|
|
8
10
|
class CupcakeMintChocolate {
|
|
9
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
10
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.
|
|
11
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CupcakeMintChocolate, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.7", type: CupcakeMintChocolate, isStandalone: true, selector: "ccmc-cupcake-mint-chocolate", ngImport: i0, template: `
|
|
11
13
|
<p>
|
|
12
14
|
cupcake-mint-chocolate works!
|
|
13
15
|
</p>
|
|
14
16
|
`, isInline: true, styles: [""] });
|
|
15
17
|
}
|
|
16
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
18
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CupcakeMintChocolate, decorators: [{
|
|
17
19
|
type: Component,
|
|
18
20
|
args: [{ selector: 'ccmc-cupcake-mint-chocolate', imports: [], template: `
|
|
19
21
|
<p>
|
|
@@ -85,6 +87,40 @@ const MessageTypeLabels = {
|
|
|
85
87
|
[MessageType.SYSTEM]: 'System Message'
|
|
86
88
|
};
|
|
87
89
|
|
|
90
|
+
var WebRTCSessionType;
|
|
91
|
+
(function (WebRTCSessionType) {
|
|
92
|
+
WebRTCSessionType["VIDEO_CALL"] = "video_call";
|
|
93
|
+
WebRTCSessionType["AUDIO_CALL"] = "audio_call";
|
|
94
|
+
WebRTCSessionType["SCREEN_SHARE"] = "screen_share";
|
|
95
|
+
WebRTCSessionType["DATA_CHANNEL"] = "data_channel";
|
|
96
|
+
})(WebRTCSessionType || (WebRTCSessionType = {}));
|
|
97
|
+
var WebRTCSessionStatus;
|
|
98
|
+
(function (WebRTCSessionStatus) {
|
|
99
|
+
WebRTCSessionStatus["WAITING"] = "waiting";
|
|
100
|
+
WebRTCSessionStatus["ACTIVE"] = "active";
|
|
101
|
+
WebRTCSessionStatus["ENDED"] = "ended";
|
|
102
|
+
})(WebRTCSessionStatus || (WebRTCSessionStatus = {}));
|
|
103
|
+
var PeerRole;
|
|
104
|
+
(function (PeerRole) {
|
|
105
|
+
PeerRole["HOST"] = "host";
|
|
106
|
+
PeerRole["VIEWER"] = "viewer";
|
|
107
|
+
PeerRole["PARTICIPANT"] = "participant";
|
|
108
|
+
})(PeerRole || (PeerRole = {}));
|
|
109
|
+
var PeerConnectionState;
|
|
110
|
+
(function (PeerConnectionState) {
|
|
111
|
+
PeerConnectionState["CONNECTING"] = "connecting";
|
|
112
|
+
PeerConnectionState["CONNECTED"] = "connected";
|
|
113
|
+
PeerConnectionState["DISCONNECTED"] = "disconnected";
|
|
114
|
+
PeerConnectionState["FAILED"] = "failed";
|
|
115
|
+
})(PeerConnectionState || (PeerConnectionState = {}));
|
|
116
|
+
var SignalType;
|
|
117
|
+
(function (SignalType) {
|
|
118
|
+
SignalType["OFFER"] = "offer";
|
|
119
|
+
SignalType["ANSWER"] = "answer";
|
|
120
|
+
SignalType["ICE_CANDIDATE"] = "ice_candidate";
|
|
121
|
+
SignalType["CHECK"] = "check";
|
|
122
|
+
})(SignalType || (SignalType = {}));
|
|
123
|
+
|
|
88
124
|
class NotificationService extends BaseApiService {
|
|
89
125
|
/**
|
|
90
126
|
* Get all notifications with optional filtering
|
|
@@ -177,10 +213,10 @@ class NotificationService extends BaseApiService {
|
|
|
177
213
|
getNotificationsByStatus(status) {
|
|
178
214
|
return this.getNotifications({ deliveryStatus: status });
|
|
179
215
|
}
|
|
180
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
181
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
216
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NotificationService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
217
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NotificationService, providedIn: 'root' });
|
|
182
218
|
}
|
|
183
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: NotificationService, decorators: [{
|
|
184
220
|
type: Injectable,
|
|
185
221
|
args: [{
|
|
186
222
|
providedIn: 'root'
|
|
@@ -291,10 +327,10 @@ class MessageThreadService extends BaseApiService {
|
|
|
291
327
|
getThreadsByCreator(creatorId) {
|
|
292
328
|
return this.getMessageThreads({ creator: creatorId });
|
|
293
329
|
}
|
|
294
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
295
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
330
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageThreadService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
331
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageThreadService, providedIn: 'root' });
|
|
296
332
|
}
|
|
297
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
333
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageThreadService, decorators: [{
|
|
298
334
|
type: Injectable,
|
|
299
335
|
args: [{
|
|
300
336
|
providedIn: 'root'
|
|
@@ -407,10 +443,10 @@ class MessageService extends BaseApiService {
|
|
|
407
443
|
};
|
|
408
444
|
return this.createMessage(message);
|
|
409
445
|
}
|
|
410
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
411
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
446
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
447
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageService, providedIn: 'root' });
|
|
412
448
|
}
|
|
413
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
449
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: MessageService, decorators: [{
|
|
414
450
|
type: Injectable,
|
|
415
451
|
args: [{
|
|
416
452
|
providedIn: 'root'
|
|
@@ -512,10 +548,10 @@ class ThreadParticipantService {
|
|
|
512
548
|
getMyModerations() {
|
|
513
549
|
return this.http.get(`${this.apiUrl}/thread-participants/my_moderations/`);
|
|
514
550
|
}
|
|
515
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
516
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
551
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ThreadParticipantService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
552
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ThreadParticipantService, providedIn: 'root' });
|
|
517
553
|
}
|
|
518
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
554
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: ThreadParticipantService, decorators: [{
|
|
519
555
|
type: Injectable,
|
|
520
556
|
args: [{
|
|
521
557
|
providedIn: 'root'
|
|
@@ -635,16 +671,600 @@ class CommunicationWebSocketService {
|
|
|
635
671
|
getConnectionState() {
|
|
636
672
|
return this.connectionStateSubject.value;
|
|
637
673
|
}
|
|
638
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
639
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
674
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CommunicationWebSocketService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
675
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CommunicationWebSocketService, providedIn: 'root' });
|
|
640
676
|
}
|
|
641
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
677
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CommunicationWebSocketService, decorators: [{
|
|
642
678
|
type: Injectable,
|
|
643
679
|
args: [{
|
|
644
680
|
providedIn: 'root'
|
|
645
681
|
}]
|
|
646
682
|
}] });
|
|
647
683
|
|
|
684
|
+
class WebRTCSignallingService {
|
|
685
|
+
authService;
|
|
686
|
+
zone;
|
|
687
|
+
ws;
|
|
688
|
+
wsSubscription;
|
|
689
|
+
baseUrl = '';
|
|
690
|
+
_connected = new BehaviorSubject(false);
|
|
691
|
+
_peerId = new BehaviorSubject(null);
|
|
692
|
+
_sessionId = new BehaviorSubject(null);
|
|
693
|
+
_peers = new BehaviorSubject([]);
|
|
694
|
+
_messages = new Subject();
|
|
695
|
+
_iceServers = new BehaviorSubject([]);
|
|
696
|
+
connected$ = this._connected.asObservable();
|
|
697
|
+
peerId$ = this._peerId.asObservable();
|
|
698
|
+
sessionId$ = this._sessionId.asObservable();
|
|
699
|
+
peers$ = this._peers.asObservable();
|
|
700
|
+
messages$ = this._messages.asObservable();
|
|
701
|
+
iceServers$ = this._iceServers.asObservable();
|
|
702
|
+
constructor(authService, zone) {
|
|
703
|
+
this.authService = authService;
|
|
704
|
+
this.zone = zone;
|
|
705
|
+
this.baseUrl = this.getBaseUrl();
|
|
706
|
+
}
|
|
707
|
+
getBaseUrl() {
|
|
708
|
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
709
|
+
const host = window.location.host;
|
|
710
|
+
return `${protocol}//${host}`;
|
|
711
|
+
}
|
|
712
|
+
connect(sessionId) {
|
|
713
|
+
this.disconnect();
|
|
714
|
+
const token = this.authService.getAccessToken();
|
|
715
|
+
if (!token) {
|
|
716
|
+
console.error('No authentication token available');
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
const wsUrl = `${this.baseUrl}/ws/ccmc/webrtc/${sessionId}/?token=${token}`;
|
|
720
|
+
this.ws = webSocket({
|
|
721
|
+
url: wsUrl,
|
|
722
|
+
openObserver: {
|
|
723
|
+
next: () => {
|
|
724
|
+
console.log('WebRTC signalling connection opened');
|
|
725
|
+
this.zone.run(() => {
|
|
726
|
+
this._connected.next(true);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
closeObserver: {
|
|
731
|
+
next: () => {
|
|
732
|
+
console.log('WebRTC signalling connection closed');
|
|
733
|
+
this.zone.run(() => {
|
|
734
|
+
this._connected.next(false);
|
|
735
|
+
this._peerId.next(null);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
deserializer: msg => {
|
|
740
|
+
try {
|
|
741
|
+
return JSON.parse(msg.data);
|
|
742
|
+
}
|
|
743
|
+
catch (e) {
|
|
744
|
+
console.error('Error parsing WebSocket message:', e);
|
|
745
|
+
return msg.data;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
this.wsSubscription = this.ws.subscribe({
|
|
750
|
+
next: (message) => {
|
|
751
|
+
this.zone.run(() => {
|
|
752
|
+
this.handleMessage(message);
|
|
753
|
+
});
|
|
754
|
+
},
|
|
755
|
+
error: (error) => {
|
|
756
|
+
console.error('WebRTC signalling error:', error);
|
|
757
|
+
this.zone.run(() => {
|
|
758
|
+
this._connected.next(false);
|
|
759
|
+
});
|
|
760
|
+
setTimeout(() => {
|
|
761
|
+
if (this._sessionId.value) {
|
|
762
|
+
console.log('Attempting to reconnect...');
|
|
763
|
+
this.connect(this._sessionId.value);
|
|
764
|
+
}
|
|
765
|
+
}, 5000);
|
|
766
|
+
},
|
|
767
|
+
complete: () => {
|
|
768
|
+
console.log('WebRTC signalling connection completed');
|
|
769
|
+
this.zone.run(() => {
|
|
770
|
+
this._connected.next(false);
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
disconnect() {
|
|
776
|
+
if (this.wsSubscription) {
|
|
777
|
+
this.wsSubscription.unsubscribe();
|
|
778
|
+
this.wsSubscription = undefined;
|
|
779
|
+
}
|
|
780
|
+
if (this.ws) {
|
|
781
|
+
this.ws.complete();
|
|
782
|
+
this.ws = undefined;
|
|
783
|
+
}
|
|
784
|
+
this._connected.next(false);
|
|
785
|
+
this._peerId.next(null);
|
|
786
|
+
this._sessionId.next(null);
|
|
787
|
+
this._peers.next([]);
|
|
788
|
+
}
|
|
789
|
+
sendCheck(peerRole = PeerRole.PARTICIPANT) {
|
|
790
|
+
this.send({
|
|
791
|
+
type: 'check',
|
|
792
|
+
peerRole: peerRole
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
sendOffer(toPeerId, sdp) {
|
|
796
|
+
this.send({
|
|
797
|
+
type: 'offer',
|
|
798
|
+
toPeerId: toPeerId,
|
|
799
|
+
sdp: sdp
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
sendAnswer(toPeerId, sdp) {
|
|
803
|
+
this.send({
|
|
804
|
+
type: 'answer',
|
|
805
|
+
toPeerId: toPeerId,
|
|
806
|
+
sdp: sdp
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
sendIceCandidate(toPeerId, candidate) {
|
|
810
|
+
this.send({
|
|
811
|
+
type: 'ice_candidate',
|
|
812
|
+
toPeerId: toPeerId,
|
|
813
|
+
candidate: candidate
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
sendPeerState(connectionState, hasVideo, hasAudio, hasScreenShare) {
|
|
817
|
+
this.send({
|
|
818
|
+
type: 'peer_state',
|
|
819
|
+
connectionState,
|
|
820
|
+
hasVideo,
|
|
821
|
+
hasAudio,
|
|
822
|
+
hasScreenShare
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
send(message) {
|
|
826
|
+
if (!this.ws) {
|
|
827
|
+
console.error('WebSocket not connected');
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
try {
|
|
831
|
+
this.ws.next(message);
|
|
832
|
+
}
|
|
833
|
+
catch (error) {
|
|
834
|
+
console.error('Error sending message:', error);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
handleMessage(message) {
|
|
838
|
+
switch (message.type) {
|
|
839
|
+
case 'connection.established':
|
|
840
|
+
this.handleConnectionEstablished(message);
|
|
841
|
+
break;
|
|
842
|
+
case 'check.response':
|
|
843
|
+
this.handleCheckResponse(message);
|
|
844
|
+
break;
|
|
845
|
+
case 'peer.check':
|
|
846
|
+
case 'offer':
|
|
847
|
+
case 'answer':
|
|
848
|
+
case 'ice_candidate':
|
|
849
|
+
case 'peer.state_update':
|
|
850
|
+
this._messages.next(message);
|
|
851
|
+
break;
|
|
852
|
+
case 'error':
|
|
853
|
+
console.error('WebRTC signalling error:', message.message);
|
|
854
|
+
break;
|
|
855
|
+
default:
|
|
856
|
+
console.warn('Unknown message type:', message.type);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
handleConnectionEstablished(message) {
|
|
860
|
+
if (message.peerId) {
|
|
861
|
+
this._peerId.next(message.peerId);
|
|
862
|
+
}
|
|
863
|
+
if (message.sessionId) {
|
|
864
|
+
this._sessionId.next(message.sessionId);
|
|
865
|
+
}
|
|
866
|
+
if (message.iceServers) {
|
|
867
|
+
this._iceServers.next(message.iceServers);
|
|
868
|
+
}
|
|
869
|
+
console.log('WebRTC signalling connection established:', message);
|
|
870
|
+
}
|
|
871
|
+
handleCheckResponse(message) {
|
|
872
|
+
if (message.peers) {
|
|
873
|
+
this._peers.next(message.peers);
|
|
874
|
+
console.log('Received peer list:', message.peers);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
get peerId() {
|
|
878
|
+
return this._peerId.value;
|
|
879
|
+
}
|
|
880
|
+
get sessionId() {
|
|
881
|
+
return this._sessionId.value;
|
|
882
|
+
}
|
|
883
|
+
get connected() {
|
|
884
|
+
return this._connected.value;
|
|
885
|
+
}
|
|
886
|
+
get peers() {
|
|
887
|
+
return this._peers.value;
|
|
888
|
+
}
|
|
889
|
+
get iceServers() {
|
|
890
|
+
return this._iceServers.value;
|
|
891
|
+
}
|
|
892
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCSignallingService, deps: [{ token: i1.AuthService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
893
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCSignallingService, providedIn: 'root' });
|
|
894
|
+
}
|
|
895
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCSignallingService, decorators: [{
|
|
896
|
+
type: Injectable,
|
|
897
|
+
args: [{
|
|
898
|
+
providedIn: 'root'
|
|
899
|
+
}]
|
|
900
|
+
}], ctorParameters: () => [{ type: i1.AuthService }, { type: i0.NgZone }] });
|
|
901
|
+
|
|
902
|
+
class WebRTCService {
|
|
903
|
+
signalling;
|
|
904
|
+
zone;
|
|
905
|
+
peerConnections = new Map();
|
|
906
|
+
localStream;
|
|
907
|
+
signallingSubscription;
|
|
908
|
+
_localStreamReady = new BehaviorSubject(false);
|
|
909
|
+
_remoteStreams = new BehaviorSubject(new Map());
|
|
910
|
+
_connectionState = new BehaviorSubject('disconnected');
|
|
911
|
+
_activePeers = new BehaviorSubject([]);
|
|
912
|
+
localStreamReady$ = this._localStreamReady.asObservable();
|
|
913
|
+
remoteStreams$ = this._remoteStreams.asObservable();
|
|
914
|
+
connectionState$ = this._connectionState.asObservable();
|
|
915
|
+
activePeers$ = this._activePeers.asObservable();
|
|
916
|
+
defaultConfig = {
|
|
917
|
+
iceServers: [
|
|
918
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
919
|
+
{ urls: 'stun:stun1.l.google.com:19302' }
|
|
920
|
+
],
|
|
921
|
+
iceCandidatePoolSize: 10,
|
|
922
|
+
iceTransportPolicy: 'all',
|
|
923
|
+
bundlePolicy: 'max-bundle',
|
|
924
|
+
rtcpMuxPolicy: 'require'
|
|
925
|
+
};
|
|
926
|
+
defaultMediaConstraints = {
|
|
927
|
+
video: {
|
|
928
|
+
width: { ideal: 1280 },
|
|
929
|
+
height: { ideal: 720 },
|
|
930
|
+
frameRate: { ideal: 30 }
|
|
931
|
+
},
|
|
932
|
+
audio: true
|
|
933
|
+
};
|
|
934
|
+
constructor(signalling, zone) {
|
|
935
|
+
this.signalling = signalling;
|
|
936
|
+
this.zone = zone;
|
|
937
|
+
}
|
|
938
|
+
async startSession(sessionId, role = PeerRole.PARTICIPANT, enableVideo = true, enableAudio = true) {
|
|
939
|
+
this._connectionState.next('connecting');
|
|
940
|
+
if (role === PeerRole.HOST || enableVideo || enableAudio) {
|
|
941
|
+
await this.startLocalMedia(enableVideo, enableAudio);
|
|
942
|
+
}
|
|
943
|
+
this.signalling.connect(sessionId);
|
|
944
|
+
this.signallingSubscription = this.signalling.messages$.subscribe({
|
|
945
|
+
next: (message) => {
|
|
946
|
+
this.handleSignallingMessage(message);
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
setTimeout(() => {
|
|
950
|
+
this.signalling.sendCheck(role);
|
|
951
|
+
}, 1000);
|
|
952
|
+
this.signalling.peers$.subscribe(peers => {
|
|
953
|
+
this._activePeers.next(peers);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
async startLocalMedia(enableVideo = true, enableAudio = true) {
|
|
957
|
+
try {
|
|
958
|
+
const constraints = {
|
|
959
|
+
video: enableVideo ? this.defaultMediaConstraints.video : false,
|
|
960
|
+
audio: enableAudio ? this.defaultMediaConstraints.audio : false
|
|
961
|
+
};
|
|
962
|
+
this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
963
|
+
this._localStreamReady.next(true);
|
|
964
|
+
this.updatePeerState(undefined, enableVideo, enableAudio, false);
|
|
965
|
+
console.log('Local media started:', this.localStream);
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
console.error('Error accessing media devices:', error);
|
|
969
|
+
throw error;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
async startScreenShare() {
|
|
973
|
+
try {
|
|
974
|
+
const screenStream = await navigator.mediaDevices.getDisplayMedia({
|
|
975
|
+
video: true,
|
|
976
|
+
audio: false
|
|
977
|
+
});
|
|
978
|
+
if (this.localStream) {
|
|
979
|
+
this.localStream.getTracks().forEach(track => track.stop());
|
|
980
|
+
}
|
|
981
|
+
this.localStream = screenStream;
|
|
982
|
+
this._localStreamReady.next(true);
|
|
983
|
+
this.replaceTracksInAllPeers();
|
|
984
|
+
this.updatePeerState(undefined, false, false, true);
|
|
985
|
+
screenStream.getVideoTracks()[0].addEventListener('ended', () => {
|
|
986
|
+
this.stopScreenShare();
|
|
987
|
+
});
|
|
988
|
+
console.log('Screen sharing started');
|
|
989
|
+
}
|
|
990
|
+
catch (error) {
|
|
991
|
+
console.error('Error starting screen share:', error);
|
|
992
|
+
throw error;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
stopScreenShare() {
|
|
996
|
+
if (this.localStream) {
|
|
997
|
+
this.localStream.getTracks().forEach(track => track.stop());
|
|
998
|
+
this.localStream = undefined;
|
|
999
|
+
this._localStreamReady.next(false);
|
|
1000
|
+
}
|
|
1001
|
+
this.updatePeerState(undefined, false, false, false);
|
|
1002
|
+
console.log('Screen sharing stopped');
|
|
1003
|
+
}
|
|
1004
|
+
endSession() {
|
|
1005
|
+
this.peerConnections.forEach((conn, peerId) => {
|
|
1006
|
+
this.closePeerConnection(peerId);
|
|
1007
|
+
});
|
|
1008
|
+
if (this.localStream) {
|
|
1009
|
+
this.localStream.getTracks().forEach(track => track.stop());
|
|
1010
|
+
this.localStream = undefined;
|
|
1011
|
+
this._localStreamReady.next(false);
|
|
1012
|
+
}
|
|
1013
|
+
if (this.signallingSubscription) {
|
|
1014
|
+
this.signallingSubscription.unsubscribe();
|
|
1015
|
+
}
|
|
1016
|
+
this.signalling.disconnect();
|
|
1017
|
+
this._connectionState.next('disconnected');
|
|
1018
|
+
this._remoteStreams.next(new Map());
|
|
1019
|
+
this._activePeers.next([]);
|
|
1020
|
+
console.log('WebRTC session ended');
|
|
1021
|
+
}
|
|
1022
|
+
async handleSignallingMessage(message) {
|
|
1023
|
+
try {
|
|
1024
|
+
switch (message.type) {
|
|
1025
|
+
case 'peer.check':
|
|
1026
|
+
if (message.fromPeerId) {
|
|
1027
|
+
await this.handlePeerCheck(message.fromPeerId, message.fromUserId, message.fromUsername, message.peerRole);
|
|
1028
|
+
}
|
|
1029
|
+
break;
|
|
1030
|
+
case 'offer':
|
|
1031
|
+
if (message.fromPeerId && message.sdp) {
|
|
1032
|
+
await this.handleOffer(message.fromPeerId, message.fromUserId, message.fromUsername, message.sdp);
|
|
1033
|
+
}
|
|
1034
|
+
break;
|
|
1035
|
+
case 'answer':
|
|
1036
|
+
if (message.fromPeerId && message.sdp) {
|
|
1037
|
+
await this.handleAnswer(message.fromPeerId, message.sdp);
|
|
1038
|
+
}
|
|
1039
|
+
break;
|
|
1040
|
+
case 'ice_candidate':
|
|
1041
|
+
if (message.fromPeerId && message.candidate) {
|
|
1042
|
+
await this.handleIceCandidate(message.fromPeerId, message.candidate);
|
|
1043
|
+
}
|
|
1044
|
+
break;
|
|
1045
|
+
case 'peer.state_update':
|
|
1046
|
+
this.handlePeerStateUpdate(message);
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
catch (error) {
|
|
1051
|
+
console.error('Error handling signalling message:', error);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
async handlePeerCheck(peerId, userId, username, role) {
|
|
1055
|
+
if (!this.peerConnections.has(peerId)) {
|
|
1056
|
+
console.log(`New peer discovered: ${username} (${peerId}) as ${role}`);
|
|
1057
|
+
const pc = await this.createPeerConnection(peerId, userId, username, role);
|
|
1058
|
+
const shouldInitiate = this.shouldInitiateConnection(role);
|
|
1059
|
+
if (shouldInitiate) {
|
|
1060
|
+
const offer = await pc.createOffer();
|
|
1061
|
+
await pc.setLocalDescription(offer);
|
|
1062
|
+
if (pc.localDescription) {
|
|
1063
|
+
this.signalling.sendOffer(peerId, pc.localDescription);
|
|
1064
|
+
const connection = this.peerConnections.get(peerId);
|
|
1065
|
+
if (connection) {
|
|
1066
|
+
connection.offered = true;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
async handleOffer(peerId, userId, username, sdp) {
|
|
1073
|
+
let pc;
|
|
1074
|
+
if (!this.peerConnections.has(peerId)) {
|
|
1075
|
+
pc = await this.createPeerConnection(peerId, userId, username, PeerRole.PARTICIPANT);
|
|
1076
|
+
}
|
|
1077
|
+
else {
|
|
1078
|
+
pc = this.peerConnections.get(peerId).pc;
|
|
1079
|
+
}
|
|
1080
|
+
await pc.setRemoteDescription(new RTCSessionDescription(sdp));
|
|
1081
|
+
const answer = await pc.createAnswer();
|
|
1082
|
+
await pc.setLocalDescription(answer);
|
|
1083
|
+
if (pc.localDescription) {
|
|
1084
|
+
this.signalling.sendAnswer(peerId, pc.localDescription);
|
|
1085
|
+
const connection = this.peerConnections.get(peerId);
|
|
1086
|
+
if (connection) {
|
|
1087
|
+
connection.answered = true;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
const connection = this.peerConnections.get(peerId);
|
|
1091
|
+
if (connection && connection.queuedCandidates.length > 0) {
|
|
1092
|
+
await Promise.all(connection.queuedCandidates.map(candidate => pc.addIceCandidate(candidate)));
|
|
1093
|
+
connection.queuedCandidates = [];
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
async handleAnswer(peerId, sdp) {
|
|
1097
|
+
const connection = this.peerConnections.get(peerId);
|
|
1098
|
+
if (!connection) {
|
|
1099
|
+
console.warn(`Received answer from unknown peer: ${peerId}`);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
await connection.pc.setRemoteDescription(new RTCSessionDescription(sdp));
|
|
1103
|
+
if (connection.queuedCandidates.length > 0) {
|
|
1104
|
+
await Promise.all(connection.queuedCandidates.map(candidate => connection.pc.addIceCandidate(candidate)));
|
|
1105
|
+
connection.queuedCandidates = [];
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
async handleIceCandidate(peerId, candidate) {
|
|
1109
|
+
const connection = this.peerConnections.get(peerId);
|
|
1110
|
+
if (!connection) {
|
|
1111
|
+
console.warn(`Received ICE candidate from unknown peer: ${peerId}`);
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const iceCandidate = new RTCIceCandidate(candidate);
|
|
1115
|
+
if (connection.pc.remoteDescription) {
|
|
1116
|
+
await connection.pc.addIceCandidate(iceCandidate);
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
connection.queuedCandidates.push(iceCandidate);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
handlePeerStateUpdate(message) {
|
|
1123
|
+
console.log('Peer state update:', message);
|
|
1124
|
+
}
|
|
1125
|
+
async createPeerConnection(peerId, userId, username, role) {
|
|
1126
|
+
const iceServers = this.signalling.iceServers;
|
|
1127
|
+
const config = iceServers.length > 0
|
|
1128
|
+
? { ...this.defaultConfig, iceServers }
|
|
1129
|
+
: this.defaultConfig;
|
|
1130
|
+
const pc = new RTCPeerConnection(config);
|
|
1131
|
+
const dataChannel = pc.createDataChannel('data', { ordered: true });
|
|
1132
|
+
this.setupDataChannelHandlers(dataChannel, peerId);
|
|
1133
|
+
if (this.localStream) {
|
|
1134
|
+
this.localStream.getTracks().forEach(track => {
|
|
1135
|
+
pc.addTrack(track, this.localStream);
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
this.setupPeerConnectionHandlers(pc, peerId);
|
|
1139
|
+
const connection = {
|
|
1140
|
+
peerId,
|
|
1141
|
+
userId,
|
|
1142
|
+
username,
|
|
1143
|
+
pc,
|
|
1144
|
+
dataChannel,
|
|
1145
|
+
role,
|
|
1146
|
+
offered: false,
|
|
1147
|
+
answered: false,
|
|
1148
|
+
connected: false,
|
|
1149
|
+
queuedCandidates: []
|
|
1150
|
+
};
|
|
1151
|
+
this.peerConnections.set(peerId, connection);
|
|
1152
|
+
console.log(`Created peer connection for ${username} (${peerId})`);
|
|
1153
|
+
return pc;
|
|
1154
|
+
}
|
|
1155
|
+
setupPeerConnectionHandlers(pc, peerId) {
|
|
1156
|
+
pc.onicecandidate = (event) => {
|
|
1157
|
+
if (event.candidate) {
|
|
1158
|
+
this.signalling.sendIceCandidate(peerId, event.candidate.toJSON());
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
pc.ontrack = (event) => {
|
|
1162
|
+
console.log(`Received track from peer ${peerId}:`, event.track.kind);
|
|
1163
|
+
this.zone.run(() => {
|
|
1164
|
+
const stream = event.streams[0];
|
|
1165
|
+
const connection = this.peerConnections.get(peerId);
|
|
1166
|
+
if (connection) {
|
|
1167
|
+
connection.stream = stream;
|
|
1168
|
+
}
|
|
1169
|
+
const streams = this._remoteStreams.value;
|
|
1170
|
+
streams.set(peerId, stream);
|
|
1171
|
+
this._remoteStreams.next(streams);
|
|
1172
|
+
});
|
|
1173
|
+
};
|
|
1174
|
+
pc.onconnectionstatechange = () => {
|
|
1175
|
+
console.log(`Connection state with peer ${peerId}: ${pc.connectionState}`);
|
|
1176
|
+
this.zone.run(() => {
|
|
1177
|
+
const connection = this.peerConnections.get(peerId);
|
|
1178
|
+
if (!connection)
|
|
1179
|
+
return;
|
|
1180
|
+
if (pc.connectionState === 'connected') {
|
|
1181
|
+
connection.connected = true;
|
|
1182
|
+
this._connectionState.next('connected');
|
|
1183
|
+
}
|
|
1184
|
+
else if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {
|
|
1185
|
+
this.closePeerConnection(peerId);
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
};
|
|
1189
|
+
pc.ondatachannel = (event) => {
|
|
1190
|
+
const receivedChannel = event.channel;
|
|
1191
|
+
this.setupDataChannelHandlers(receivedChannel, peerId);
|
|
1192
|
+
const connection = this.peerConnections.get(peerId);
|
|
1193
|
+
if (connection) {
|
|
1194
|
+
connection.dataChannel = receivedChannel;
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
setupDataChannelHandlers(dataChannel, peerId) {
|
|
1199
|
+
dataChannel.onopen = () => {
|
|
1200
|
+
console.log(`Data channel opened with peer ${peerId}`);
|
|
1201
|
+
};
|
|
1202
|
+
dataChannel.onmessage = (event) => {
|
|
1203
|
+
console.log(`Data received from peer ${peerId}:`, event.data);
|
|
1204
|
+
};
|
|
1205
|
+
dataChannel.onclose = () => {
|
|
1206
|
+
console.log(`Data channel closed with peer ${peerId}`);
|
|
1207
|
+
};
|
|
1208
|
+
dataChannel.onerror = (error) => {
|
|
1209
|
+
console.error(`Data channel error with peer ${peerId}:`, error);
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
closePeerConnection(peerId) {
|
|
1213
|
+
const connection = this.peerConnections.get(peerId);
|
|
1214
|
+
if (!connection)
|
|
1215
|
+
return;
|
|
1216
|
+
connection.pc.close();
|
|
1217
|
+
this.peerConnections.delete(peerId);
|
|
1218
|
+
const streams = this._remoteStreams.value;
|
|
1219
|
+
streams.delete(peerId);
|
|
1220
|
+
this._remoteStreams.next(streams);
|
|
1221
|
+
console.log(`Closed peer connection with ${peerId}`);
|
|
1222
|
+
}
|
|
1223
|
+
shouldInitiateConnection(peerRole) {
|
|
1224
|
+
const myPeers = Array.from(this.peerConnections.values());
|
|
1225
|
+
const iAmHost = myPeers.some(p => p.role === PeerRole.HOST);
|
|
1226
|
+
return iAmHost && peerRole !== PeerRole.HOST;
|
|
1227
|
+
}
|
|
1228
|
+
replaceTracksInAllPeers() {
|
|
1229
|
+
if (!this.localStream)
|
|
1230
|
+
return;
|
|
1231
|
+
this.peerConnections.forEach((connection) => {
|
|
1232
|
+
const senders = connection.pc.getSenders();
|
|
1233
|
+
this.localStream.getTracks().forEach(track => {
|
|
1234
|
+
const sender = senders.find(s => s.track?.kind === track.kind);
|
|
1235
|
+
if (sender) {
|
|
1236
|
+
sender.replaceTrack(track).catch(error => {
|
|
1237
|
+
console.error(`Error replacing ${track.kind} track:`, error);
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
else {
|
|
1241
|
+
connection.pc.addTrack(track, this.localStream);
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
updatePeerState(connectionState, hasVideo, hasAudio, hasScreenShare) {
|
|
1247
|
+
this.signalling.sendPeerState(connectionState, hasVideo, hasAudio, hasScreenShare);
|
|
1248
|
+
}
|
|
1249
|
+
get localMediaStream() {
|
|
1250
|
+
return this.localStream;
|
|
1251
|
+
}
|
|
1252
|
+
get isConnected() {
|
|
1253
|
+
return this._connectionState.value === 'connected';
|
|
1254
|
+
}
|
|
1255
|
+
get activePeerConnections() {
|
|
1256
|
+
return Array.from(this.peerConnections.values());
|
|
1257
|
+
}
|
|
1258
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCService, deps: [{ token: WebRTCSignallingService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1259
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCService, providedIn: 'root' });
|
|
1260
|
+
}
|
|
1261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCService, decorators: [{
|
|
1262
|
+
type: Injectable,
|
|
1263
|
+
args: [{
|
|
1264
|
+
providedIn: 'root'
|
|
1265
|
+
}]
|
|
1266
|
+
}], ctorParameters: () => [{ type: WebRTCSignallingService }, { type: i0.NgZone }] });
|
|
1267
|
+
|
|
648
1268
|
// Communication and messaging services
|
|
649
1269
|
|
|
650
1270
|
/*
|
|
@@ -655,5 +1275,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImpor
|
|
|
655
1275
|
* Generated bundle index. Do not edit.
|
|
656
1276
|
*/
|
|
657
1277
|
|
|
658
|
-
export { CommunicationWebSocketService, CupcakeMintChocolate, DeliveryStatus, DeliveryStatusLabels, MessageService, MessageThreadService, MessageType, MessageTypeLabels, NotificationPriority, NotificationPriorityLabels, NotificationService, NotificationType, NotificationTypeLabels, ThreadParticipantService };
|
|
1278
|
+
export { CommunicationWebSocketService, CupcakeMintChocolate, DeliveryStatus, DeliveryStatusLabels, MessageService, MessageThreadService, MessageType, MessageTypeLabels, NotificationPriority, NotificationPriorityLabels, NotificationService, NotificationType, NotificationTypeLabels, PeerConnectionState, PeerRole, SignalType, ThreadParticipantService, WebRTCService, WebRTCSessionStatus, WebRTCSessionType, WebRTCSignallingService };
|
|
659
1279
|
//# sourceMappingURL=noatgnu-cupcake-mint-chocolate.mjs.map
|