@noatgnu/cupcake-mint-chocolate 1.2.4 → 1.2.6

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,9 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, Injectable, inject } from '@angular/core';
3
- import { BaseApiService } from '@noatgnu/cupcake-core';
3
+ import * as i1 from '@noatgnu/cupcake-core';
4
+ import { BaseApiService, CUPCAKE_CORE_CONFIG } 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
11
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: CupcakeMintChocolate, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -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
@@ -645,6 +681,599 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
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
+ config = inject(CUPCAKE_CORE_CONFIG);
703
+ constructor(authService, zone) {
704
+ this.authService = authService;
705
+ this.zone = zone;
706
+ this.baseUrl = this.getBaseUrl();
707
+ }
708
+ getBaseUrl() {
709
+ if (this.config && this.config.websocketUrl) {
710
+ return this.config.websocketUrl;
711
+ }
712
+ if (this.config && this.config.apiUrl) {
713
+ const apiUrl = this.config.apiUrl.replace(/^https?:\/\//, '');
714
+ const protocol = this.config.apiUrl.startsWith('https') ? 'wss:' : 'ws:';
715
+ return `${protocol}//${apiUrl}`;
716
+ }
717
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
718
+ const host = window.location.host;
719
+ return `${protocol}//${host}`;
720
+ }
721
+ connect(sessionId) {
722
+ this.disconnect();
723
+ const token = this.authService.getAccessToken();
724
+ if (!token) {
725
+ console.error('No authentication token available');
726
+ return;
727
+ }
728
+ const wsUrl = `${this.baseUrl}/ws/ccmc/webrtc/${sessionId}/?token=${token}`;
729
+ this.ws = webSocket({
730
+ url: wsUrl,
731
+ openObserver: {
732
+ next: () => {
733
+ console.log('WebRTC signalling connection opened');
734
+ this.zone.run(() => {
735
+ this._connected.next(true);
736
+ });
737
+ }
738
+ },
739
+ closeObserver: {
740
+ next: () => {
741
+ console.log('WebRTC signalling connection closed');
742
+ this.zone.run(() => {
743
+ this._connected.next(false);
744
+ this._peerId.next(null);
745
+ });
746
+ }
747
+ },
748
+ deserializer: msg => {
749
+ try {
750
+ return JSON.parse(msg.data);
751
+ }
752
+ catch (e) {
753
+ console.error('Error parsing WebSocket message:', e);
754
+ return msg.data;
755
+ }
756
+ }
757
+ });
758
+ this.wsSubscription = this.ws.subscribe({
759
+ next: (message) => {
760
+ this.zone.run(() => {
761
+ this.handleMessage(message);
762
+ });
763
+ },
764
+ error: (error) => {
765
+ console.error('WebRTC signalling error:', error);
766
+ this.zone.run(() => {
767
+ this._connected.next(false);
768
+ });
769
+ setTimeout(() => {
770
+ if (this._sessionId.value) {
771
+ console.log('Attempting to reconnect...');
772
+ this.connect(this._sessionId.value);
773
+ }
774
+ }, 5000);
775
+ },
776
+ complete: () => {
777
+ console.log('WebRTC signalling connection completed');
778
+ this.zone.run(() => {
779
+ this._connected.next(false);
780
+ });
781
+ }
782
+ });
783
+ }
784
+ disconnect() {
785
+ if (this.wsSubscription) {
786
+ this.wsSubscription.unsubscribe();
787
+ this.wsSubscription = undefined;
788
+ }
789
+ if (this.ws) {
790
+ this.ws.complete();
791
+ this.ws = undefined;
792
+ }
793
+ this._connected.next(false);
794
+ this._peerId.next(null);
795
+ this._sessionId.next(null);
796
+ this._peers.next([]);
797
+ }
798
+ sendCheck(peerRole = PeerRole.PARTICIPANT) {
799
+ this.send({
800
+ type: 'check',
801
+ peerRole: peerRole
802
+ });
803
+ }
804
+ sendOffer(toPeerId, sdp) {
805
+ this.send({
806
+ type: 'offer',
807
+ toPeerId: toPeerId,
808
+ sdp: sdp
809
+ });
810
+ }
811
+ sendAnswer(toPeerId, sdp) {
812
+ this.send({
813
+ type: 'answer',
814
+ toPeerId: toPeerId,
815
+ sdp: sdp
816
+ });
817
+ }
818
+ sendIceCandidate(toPeerId, candidate) {
819
+ this.send({
820
+ type: 'ice_candidate',
821
+ toPeerId: toPeerId,
822
+ candidate: candidate
823
+ });
824
+ }
825
+ sendPeerState(connectionState, hasVideo, hasAudio, hasScreenShare) {
826
+ this.send({
827
+ type: 'peer_state',
828
+ connectionState,
829
+ hasVideo,
830
+ hasAudio,
831
+ hasScreenShare
832
+ });
833
+ }
834
+ send(message) {
835
+ if (!this.ws) {
836
+ console.error('WebSocket not connected');
837
+ return;
838
+ }
839
+ try {
840
+ this.ws.next(message);
841
+ }
842
+ catch (error) {
843
+ console.error('Error sending message:', error);
844
+ }
845
+ }
846
+ handleMessage(message) {
847
+ switch (message.type) {
848
+ case 'connection.established':
849
+ this.handleConnectionEstablished(message);
850
+ break;
851
+ case 'check.response':
852
+ this.handleCheckResponse(message);
853
+ break;
854
+ case 'peer.check':
855
+ case 'offer':
856
+ case 'answer':
857
+ case 'ice_candidate':
858
+ case 'peer.state_update':
859
+ this._messages.next(message);
860
+ break;
861
+ case 'error':
862
+ console.error('WebRTC signalling error:', message.message);
863
+ break;
864
+ default:
865
+ console.warn('Unknown message type:', message.type);
866
+ }
867
+ }
868
+ handleConnectionEstablished(message) {
869
+ if (message.peerId) {
870
+ this._peerId.next(message.peerId);
871
+ }
872
+ if (message.sessionId) {
873
+ this._sessionId.next(message.sessionId);
874
+ }
875
+ if (message.iceServers) {
876
+ this._iceServers.next(message.iceServers);
877
+ }
878
+ console.log('WebRTC signalling connection established:', message);
879
+ }
880
+ handleCheckResponse(message) {
881
+ if (message.peers) {
882
+ this._peers.next(message.peers);
883
+ console.log('Received peer list:', message.peers);
884
+ }
885
+ }
886
+ get peerId() {
887
+ return this._peerId.value;
888
+ }
889
+ get sessionId() {
890
+ return this._sessionId.value;
891
+ }
892
+ get connected() {
893
+ return this._connected.value;
894
+ }
895
+ get peers() {
896
+ return this._peers.value;
897
+ }
898
+ get iceServers() {
899
+ return this._iceServers.value;
900
+ }
901
+ 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 });
902
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCSignallingService, providedIn: 'root' });
903
+ }
904
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCSignallingService, decorators: [{
905
+ type: Injectable,
906
+ args: [{
907
+ providedIn: 'root'
908
+ }]
909
+ }], ctorParameters: () => [{ type: i1.AuthService }, { type: i0.NgZone }] });
910
+
911
+ class WebRTCService {
912
+ signalling;
913
+ zone;
914
+ peerConnections = new Map();
915
+ localStream;
916
+ signallingSubscription;
917
+ _localStreamReady = new BehaviorSubject(false);
918
+ _remoteStreams = new BehaviorSubject(new Map());
919
+ _connectionState = new BehaviorSubject('disconnected');
920
+ _activePeers = new BehaviorSubject([]);
921
+ localStreamReady$ = this._localStreamReady.asObservable();
922
+ remoteStreams$ = this._remoteStreams.asObservable();
923
+ connectionState$ = this._connectionState.asObservable();
924
+ activePeers$ = this._activePeers.asObservable();
925
+ defaultConfig = {
926
+ iceServers: [
927
+ { urls: 'stun:stun.l.google.com:19302' },
928
+ { urls: 'stun:stun1.l.google.com:19302' }
929
+ ],
930
+ iceCandidatePoolSize: 10,
931
+ iceTransportPolicy: 'all',
932
+ bundlePolicy: 'max-bundle',
933
+ rtcpMuxPolicy: 'require'
934
+ };
935
+ defaultMediaConstraints = {
936
+ video: {
937
+ width: { ideal: 1280 },
938
+ height: { ideal: 720 },
939
+ frameRate: { ideal: 30 }
940
+ },
941
+ audio: true
942
+ };
943
+ constructor(signalling, zone) {
944
+ this.signalling = signalling;
945
+ this.zone = zone;
946
+ }
947
+ async startSession(sessionId, role = PeerRole.PARTICIPANT, enableVideo = true, enableAudio = true) {
948
+ this._connectionState.next('connecting');
949
+ if (role === PeerRole.HOST || enableVideo || enableAudio) {
950
+ await this.startLocalMedia(enableVideo, enableAudio);
951
+ }
952
+ this.signalling.connect(sessionId);
953
+ this.signallingSubscription = this.signalling.messages$.subscribe({
954
+ next: (message) => {
955
+ this.handleSignallingMessage(message);
956
+ }
957
+ });
958
+ setTimeout(() => {
959
+ this.signalling.sendCheck(role);
960
+ }, 1000);
961
+ this.signalling.peers$.subscribe(peers => {
962
+ this._activePeers.next(peers);
963
+ });
964
+ }
965
+ async startLocalMedia(enableVideo = true, enableAudio = true) {
966
+ try {
967
+ const constraints = {
968
+ video: enableVideo ? this.defaultMediaConstraints.video : false,
969
+ audio: enableAudio ? this.defaultMediaConstraints.audio : false
970
+ };
971
+ this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
972
+ this._localStreamReady.next(true);
973
+ this.updatePeerState(undefined, enableVideo, enableAudio, false);
974
+ console.log('Local media started:', this.localStream);
975
+ }
976
+ catch (error) {
977
+ console.error('Error accessing media devices:', error);
978
+ throw error;
979
+ }
980
+ }
981
+ async startScreenShare() {
982
+ try {
983
+ const screenStream = await navigator.mediaDevices.getDisplayMedia({
984
+ video: true,
985
+ audio: false
986
+ });
987
+ if (this.localStream) {
988
+ this.localStream.getTracks().forEach(track => track.stop());
989
+ }
990
+ this.localStream = screenStream;
991
+ this._localStreamReady.next(true);
992
+ this.replaceTracksInAllPeers();
993
+ this.updatePeerState(undefined, false, false, true);
994
+ screenStream.getVideoTracks()[0].addEventListener('ended', () => {
995
+ this.stopScreenShare();
996
+ });
997
+ console.log('Screen sharing started');
998
+ }
999
+ catch (error) {
1000
+ console.error('Error starting screen share:', error);
1001
+ throw error;
1002
+ }
1003
+ }
1004
+ stopScreenShare() {
1005
+ if (this.localStream) {
1006
+ this.localStream.getTracks().forEach(track => track.stop());
1007
+ this.localStream = undefined;
1008
+ this._localStreamReady.next(false);
1009
+ }
1010
+ this.updatePeerState(undefined, false, false, false);
1011
+ console.log('Screen sharing stopped');
1012
+ }
1013
+ endSession() {
1014
+ this.peerConnections.forEach((conn, peerId) => {
1015
+ this.closePeerConnection(peerId);
1016
+ });
1017
+ if (this.localStream) {
1018
+ this.localStream.getTracks().forEach(track => track.stop());
1019
+ this.localStream = undefined;
1020
+ this._localStreamReady.next(false);
1021
+ }
1022
+ if (this.signallingSubscription) {
1023
+ this.signallingSubscription.unsubscribe();
1024
+ }
1025
+ this.signalling.disconnect();
1026
+ this._connectionState.next('disconnected');
1027
+ this._remoteStreams.next(new Map());
1028
+ this._activePeers.next([]);
1029
+ console.log('WebRTC session ended');
1030
+ }
1031
+ async handleSignallingMessage(message) {
1032
+ try {
1033
+ switch (message.type) {
1034
+ case 'peer.check':
1035
+ if (message.fromPeerId) {
1036
+ await this.handlePeerCheck(message.fromPeerId, message.fromUserId, message.fromUsername, message.peerRole);
1037
+ }
1038
+ break;
1039
+ case 'offer':
1040
+ if (message.fromPeerId && message.sdp) {
1041
+ await this.handleOffer(message.fromPeerId, message.fromUserId, message.fromUsername, message.sdp);
1042
+ }
1043
+ break;
1044
+ case 'answer':
1045
+ if (message.fromPeerId && message.sdp) {
1046
+ await this.handleAnswer(message.fromPeerId, message.sdp);
1047
+ }
1048
+ break;
1049
+ case 'ice_candidate':
1050
+ if (message.fromPeerId && message.candidate) {
1051
+ await this.handleIceCandidate(message.fromPeerId, message.candidate);
1052
+ }
1053
+ break;
1054
+ case 'peer.state_update':
1055
+ this.handlePeerStateUpdate(message);
1056
+ break;
1057
+ }
1058
+ }
1059
+ catch (error) {
1060
+ console.error('Error handling signalling message:', error);
1061
+ }
1062
+ }
1063
+ async handlePeerCheck(peerId, userId, username, role) {
1064
+ if (!this.peerConnections.has(peerId)) {
1065
+ console.log(`New peer discovered: ${username} (${peerId}) as ${role}`);
1066
+ const pc = await this.createPeerConnection(peerId, userId, username, role);
1067
+ const shouldInitiate = this.shouldInitiateConnection(role);
1068
+ if (shouldInitiate) {
1069
+ const offer = await pc.createOffer();
1070
+ await pc.setLocalDescription(offer);
1071
+ if (pc.localDescription) {
1072
+ this.signalling.sendOffer(peerId, pc.localDescription);
1073
+ const connection = this.peerConnections.get(peerId);
1074
+ if (connection) {
1075
+ connection.offered = true;
1076
+ }
1077
+ }
1078
+ }
1079
+ }
1080
+ }
1081
+ async handleOffer(peerId, userId, username, sdp) {
1082
+ let pc;
1083
+ if (!this.peerConnections.has(peerId)) {
1084
+ pc = await this.createPeerConnection(peerId, userId, username, PeerRole.PARTICIPANT);
1085
+ }
1086
+ else {
1087
+ pc = this.peerConnections.get(peerId).pc;
1088
+ }
1089
+ await pc.setRemoteDescription(new RTCSessionDescription(sdp));
1090
+ const answer = await pc.createAnswer();
1091
+ await pc.setLocalDescription(answer);
1092
+ if (pc.localDescription) {
1093
+ this.signalling.sendAnswer(peerId, pc.localDescription);
1094
+ const connection = this.peerConnections.get(peerId);
1095
+ if (connection) {
1096
+ connection.answered = true;
1097
+ }
1098
+ }
1099
+ const connection = this.peerConnections.get(peerId);
1100
+ if (connection && connection.queuedCandidates.length > 0) {
1101
+ await Promise.all(connection.queuedCandidates.map(candidate => pc.addIceCandidate(candidate)));
1102
+ connection.queuedCandidates = [];
1103
+ }
1104
+ }
1105
+ async handleAnswer(peerId, sdp) {
1106
+ const connection = this.peerConnections.get(peerId);
1107
+ if (!connection) {
1108
+ console.warn(`Received answer from unknown peer: ${peerId}`);
1109
+ return;
1110
+ }
1111
+ await connection.pc.setRemoteDescription(new RTCSessionDescription(sdp));
1112
+ if (connection.queuedCandidates.length > 0) {
1113
+ await Promise.all(connection.queuedCandidates.map(candidate => connection.pc.addIceCandidate(candidate)));
1114
+ connection.queuedCandidates = [];
1115
+ }
1116
+ }
1117
+ async handleIceCandidate(peerId, candidate) {
1118
+ const connection = this.peerConnections.get(peerId);
1119
+ if (!connection) {
1120
+ console.warn(`Received ICE candidate from unknown peer: ${peerId}`);
1121
+ return;
1122
+ }
1123
+ const iceCandidate = new RTCIceCandidate(candidate);
1124
+ if (connection.pc.remoteDescription) {
1125
+ await connection.pc.addIceCandidate(iceCandidate);
1126
+ }
1127
+ else {
1128
+ connection.queuedCandidates.push(iceCandidate);
1129
+ }
1130
+ }
1131
+ handlePeerStateUpdate(message) {
1132
+ console.log('Peer state update:', message);
1133
+ }
1134
+ async createPeerConnection(peerId, userId, username, role) {
1135
+ const iceServers = this.signalling.iceServers;
1136
+ const config = iceServers.length > 0
1137
+ ? { ...this.defaultConfig, iceServers }
1138
+ : this.defaultConfig;
1139
+ const pc = new RTCPeerConnection(config);
1140
+ const dataChannel = pc.createDataChannel('data', { ordered: true });
1141
+ this.setupDataChannelHandlers(dataChannel, peerId);
1142
+ if (this.localStream) {
1143
+ this.localStream.getTracks().forEach(track => {
1144
+ pc.addTrack(track, this.localStream);
1145
+ });
1146
+ }
1147
+ this.setupPeerConnectionHandlers(pc, peerId);
1148
+ const connection = {
1149
+ peerId,
1150
+ userId,
1151
+ username,
1152
+ pc,
1153
+ dataChannel,
1154
+ role,
1155
+ offered: false,
1156
+ answered: false,
1157
+ connected: false,
1158
+ queuedCandidates: []
1159
+ };
1160
+ this.peerConnections.set(peerId, connection);
1161
+ console.log(`Created peer connection for ${username} (${peerId})`);
1162
+ return pc;
1163
+ }
1164
+ setupPeerConnectionHandlers(pc, peerId) {
1165
+ pc.onicecandidate = (event) => {
1166
+ if (event.candidate) {
1167
+ this.signalling.sendIceCandidate(peerId, event.candidate.toJSON());
1168
+ }
1169
+ };
1170
+ pc.ontrack = (event) => {
1171
+ console.log(`Received track from peer ${peerId}:`, event.track.kind);
1172
+ this.zone.run(() => {
1173
+ const stream = event.streams[0];
1174
+ const connection = this.peerConnections.get(peerId);
1175
+ if (connection) {
1176
+ connection.stream = stream;
1177
+ }
1178
+ const streams = this._remoteStreams.value;
1179
+ streams.set(peerId, stream);
1180
+ this._remoteStreams.next(streams);
1181
+ });
1182
+ };
1183
+ pc.onconnectionstatechange = () => {
1184
+ console.log(`Connection state with peer ${peerId}: ${pc.connectionState}`);
1185
+ this.zone.run(() => {
1186
+ const connection = this.peerConnections.get(peerId);
1187
+ if (!connection)
1188
+ return;
1189
+ if (pc.connectionState === 'connected') {
1190
+ connection.connected = true;
1191
+ this._connectionState.next('connected');
1192
+ }
1193
+ else if (pc.connectionState === 'failed' || pc.connectionState === 'disconnected') {
1194
+ this.closePeerConnection(peerId);
1195
+ }
1196
+ });
1197
+ };
1198
+ pc.ondatachannel = (event) => {
1199
+ const receivedChannel = event.channel;
1200
+ this.setupDataChannelHandlers(receivedChannel, peerId);
1201
+ const connection = this.peerConnections.get(peerId);
1202
+ if (connection) {
1203
+ connection.dataChannel = receivedChannel;
1204
+ }
1205
+ };
1206
+ }
1207
+ setupDataChannelHandlers(dataChannel, peerId) {
1208
+ dataChannel.onopen = () => {
1209
+ console.log(`Data channel opened with peer ${peerId}`);
1210
+ };
1211
+ dataChannel.onmessage = (event) => {
1212
+ console.log(`Data received from peer ${peerId}:`, event.data);
1213
+ };
1214
+ dataChannel.onclose = () => {
1215
+ console.log(`Data channel closed with peer ${peerId}`);
1216
+ };
1217
+ dataChannel.onerror = (error) => {
1218
+ console.error(`Data channel error with peer ${peerId}:`, error);
1219
+ };
1220
+ }
1221
+ closePeerConnection(peerId) {
1222
+ const connection = this.peerConnections.get(peerId);
1223
+ if (!connection)
1224
+ return;
1225
+ connection.pc.close();
1226
+ this.peerConnections.delete(peerId);
1227
+ const streams = this._remoteStreams.value;
1228
+ streams.delete(peerId);
1229
+ this._remoteStreams.next(streams);
1230
+ console.log(`Closed peer connection with ${peerId}`);
1231
+ }
1232
+ shouldInitiateConnection(peerRole) {
1233
+ const myPeers = Array.from(this.peerConnections.values());
1234
+ const iAmHost = myPeers.some(p => p.role === PeerRole.HOST);
1235
+ return iAmHost && peerRole !== PeerRole.HOST;
1236
+ }
1237
+ replaceTracksInAllPeers() {
1238
+ if (!this.localStream)
1239
+ return;
1240
+ this.peerConnections.forEach((connection) => {
1241
+ const senders = connection.pc.getSenders();
1242
+ this.localStream.getTracks().forEach(track => {
1243
+ const sender = senders.find(s => s.track?.kind === track.kind);
1244
+ if (sender) {
1245
+ sender.replaceTrack(track).catch(error => {
1246
+ console.error(`Error replacing ${track.kind} track:`, error);
1247
+ });
1248
+ }
1249
+ else {
1250
+ connection.pc.addTrack(track, this.localStream);
1251
+ }
1252
+ });
1253
+ });
1254
+ }
1255
+ updatePeerState(connectionState, hasVideo, hasAudio, hasScreenShare) {
1256
+ this.signalling.sendPeerState(connectionState, hasVideo, hasAudio, hasScreenShare);
1257
+ }
1258
+ get localMediaStream() {
1259
+ return this.localStream;
1260
+ }
1261
+ get isConnected() {
1262
+ return this._connectionState.value === 'connected';
1263
+ }
1264
+ get activePeerConnections() {
1265
+ return Array.from(this.peerConnections.values());
1266
+ }
1267
+ 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 });
1268
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCService, providedIn: 'root' });
1269
+ }
1270
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImport: i0, type: WebRTCService, decorators: [{
1271
+ type: Injectable,
1272
+ args: [{
1273
+ providedIn: 'root'
1274
+ }]
1275
+ }], ctorParameters: () => [{ type: WebRTCSignallingService }, { type: i0.NgZone }] });
1276
+
648
1277
  // Communication and messaging services
649
1278
 
650
1279
  /*
@@ -655,5 +1284,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.7", ngImpor
655
1284
  * Generated bundle index. Do not edit.
656
1285
  */
657
1286
 
658
- export { CommunicationWebSocketService, CupcakeMintChocolate, DeliveryStatus, DeliveryStatusLabels, MessageService, MessageThreadService, MessageType, MessageTypeLabels, NotificationPriority, NotificationPriorityLabels, NotificationService, NotificationType, NotificationTypeLabels, ThreadParticipantService };
1287
+ export { CommunicationWebSocketService, CupcakeMintChocolate, DeliveryStatus, DeliveryStatusLabels, MessageService, MessageThreadService, MessageType, MessageTypeLabels, NotificationPriority, NotificationPriorityLabels, NotificationService, NotificationType, NotificationTypeLabels, PeerConnectionState, PeerRole, SignalType, ThreadParticipantService, WebRTCService, WebRTCSessionStatus, WebRTCSessionType, WebRTCSignallingService };
659
1288
  //# sourceMappingURL=noatgnu-cupcake-mint-chocolate.mjs.map