Group events by calls or users
This commit is contained in:
		
					parent
					
						
							
								87660e8873
							
						
					
				
			
			
				commit
				
					
						661e3dd98e
					
				
			
		
					 6 changed files with 211 additions and 162 deletions
				
			
		
							
								
								
									
										11
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
    "": {
 | 
					    "": {
 | 
				
			||||||
      "version": "0.0.0",
 | 
					      "version": "0.0.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "classnames": "^2.3.1",
 | 
				
			||||||
        "color-hash": "^2.0.1",
 | 
					        "color-hash": "^2.0.1",
 | 
				
			||||||
        "events": "^3.3.0",
 | 
					        "events": "^3.3.0",
 | 
				
			||||||
        "matrix-js-sdk": "^12.0.1",
 | 
					        "matrix-js-sdk": "^12.0.1",
 | 
				
			||||||
| 
						 | 
					@ -588,6 +589,11 @@
 | 
				
			||||||
        "node": ">=4"
 | 
					        "node": ">=4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/classnames": {
 | 
				
			||||||
 | 
					      "version": "2.3.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/color-convert": {
 | 
					    "node_modules/color-convert": {
 | 
				
			||||||
      "version": "1.9.3",
 | 
					      "version": "1.9.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
				
			||||||
| 
						 | 
					@ -2039,6 +2045,11 @@
 | 
				
			||||||
        "supports-color": "^5.3.0"
 | 
					        "supports-color": "^5.3.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "classnames": {
 | 
				
			||||||
 | 
					      "version": "2.3.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "color-convert": {
 | 
					    "color-convert": {
 | 
				
			||||||
      "version": "1.9.3",
 | 
					      "version": "1.9.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
    "serve": "vite preview"
 | 
					    "serve": "vite preview"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "classnames": "^2.3.1",
 | 
				
			||||||
    "color-hash": "^2.0.1",
 | 
					    "color-hash": "^2.0.1",
 | 
				
			||||||
    "events": "^3.3.0",
 | 
					    "events": "^3.3.0",
 | 
				
			||||||
    "matrix-js-sdk": "^12.0.1",
 | 
					    "matrix-js-sdk": "^12.0.1",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,9 +134,10 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    this.client = client;
 | 
					    this.client = client;
 | 
				
			||||||
    this.joined = false;
 | 
					    this.joined = false;
 | 
				
			||||||
    this.room = null;
 | 
					    this.room = null;
 | 
				
			||||||
 | 
					    const localUserId = client.getUserId();
 | 
				
			||||||
    this.localParticipant = {
 | 
					    this.localParticipant = {
 | 
				
			||||||
      local: true,
 | 
					      local: true,
 | 
				
			||||||
      userId: client.getUserId(),
 | 
					      userId: localUserId,
 | 
				
			||||||
      feed: null,
 | 
					      feed: null,
 | 
				
			||||||
      call: null,
 | 
					      call: null,
 | 
				
			||||||
      muted: true,
 | 
					      muted: true,
 | 
				
			||||||
| 
						 | 
					@ -144,20 +145,24 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    this.participants = [this.localParticipant];
 | 
					    this.participants = [this.localParticipant];
 | 
				
			||||||
    this.pendingCalls = [];
 | 
					    this.pendingCalls = [];
 | 
				
			||||||
    this.callUserMap = new Map();
 | 
					    this.callUserMap = new Map();
 | 
				
			||||||
    this.debugState = new Map();
 | 
					    this.debugState = {
 | 
				
			||||||
    this._setDebugState(client.getUserId(), "you");
 | 
					      users: new Map(),
 | 
				
			||||||
 | 
					      calls: new Map(),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    this.client.on("event", this._onEvent);
 | 
					    this.client.on("event", this._onEvent);
 | 
				
			||||||
    this.client.on("RoomState.members", this._onMemberChanged);
 | 
					    this.client.on("RoomState.members", this._onMemberChanged);
 | 
				
			||||||
    this.client.on("Call.incoming", this._onIncomingCall);
 | 
					    this.client.on("Call.incoming", this._onIncomingCall);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  join(roomId) {
 | 
					  setRoom(roomId) {
 | 
				
			||||||
    this.joined = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this._addDebugEvent(this.client.getUserId(), "joined call");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.roomId = roomId;
 | 
					    this.roomId = roomId;
 | 
				
			||||||
    this.room = this.client.getRoom(this.roomId);
 | 
					    this.room = this.client.getRoom(this.roomId);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  join() {
 | 
				
			||||||
 | 
					    this.joined = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._setDebugState(this.client.getUserId(), null, "you");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const activeConf = this.room.currentState
 | 
					    const activeConf = this.room.currentState
 | 
				
			||||||
      .getStateEvents(CONF_ROOM, "")
 | 
					      .getStateEvents(CONF_ROOM, "")
 | 
				
			||||||
| 
						 | 
					@ -169,18 +174,12 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const roomMemberIds = this.room.getMembers().map(({ userId }) => userId);
 | 
					    const roomMemberIds = this.room.getMembers().map(({ userId }) => userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const userId of this.debugState.keys()) {
 | 
					 | 
				
			||||||
      if (roomMemberIds.indexOf(userId) === -1) {
 | 
					 | 
				
			||||||
        this.debugState.delete(userId);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    roomMemberIds.forEach((userId) => {
 | 
					    roomMemberIds.forEach((userId) => {
 | 
				
			||||||
      this._processMember(userId);
 | 
					      this._processMember(userId);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const { call, onHangup, onReplaced } of this.pendingCalls) {
 | 
					    for (const { call, onHangup, onReplaced } of this.pendingCalls) {
 | 
				
			||||||
      if (call.roomId !== roomId) {
 | 
					      if (call.roomId !== this.roomId) {
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -200,31 +199,66 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    const roomId = event.getRoomId();
 | 
					    const roomId = event.getRoomId();
 | 
				
			||||||
    const type = event.getType();
 | 
					    const type = event.getType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (type.startsWith("m.call.") || type.startsWith("me.robertlong.conf")) {
 | 
					    if (roomId === this.roomId && type.startsWith("m.call.")) {
 | 
				
			||||||
      const content = event.getContent();
 | 
					      const sender = event.getSender();
 | 
				
			||||||
      const details = { content: event.toJSON(), roomId };
 | 
					      const { call_id } = event.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (content.invitee && content.call_id) {
 | 
					      if (call_id) {
 | 
				
			||||||
        this.callUserMap.set(content.call_id, content.invitee);
 | 
					        if (this.debugState.calls.has(call_id)) {
 | 
				
			||||||
        details.to = content.invitee;
 | 
					          const callState = this.debugState.calls.get(call_id);
 | 
				
			||||||
      } else if (content.call_id) {
 | 
					          callState.events.push(event);
 | 
				
			||||||
        details.to = this.callUserMap.get(content.call_id);
 | 
					        } else {
 | 
				
			||||||
 | 
					          this.debugState.calls.set(call_id, {
 | 
				
			||||||
 | 
					            state: "unknown",
 | 
				
			||||||
 | 
					            events: [event],
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      switch (type) {
 | 
					      if (this.debugState.users.has(sender)) {
 | 
				
			||||||
        case "m.call.invite":
 | 
					        const userState = this.debugState.users.get(sender);
 | 
				
			||||||
        case "m.call.candidates":
 | 
					        userState.events.push(event);
 | 
				
			||||||
        case "m.call.answer":
 | 
					      } else {
 | 
				
			||||||
        case "m.call.hangup":
 | 
					        this.debugState.users.set(sender, {
 | 
				
			||||||
        case "m.call.select_answer":
 | 
					          state: "unknown",
 | 
				
			||||||
          details.callId = content.call_id;
 | 
					          events: [event],
 | 
				
			||||||
          break;
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this._addDebugEvent(event.getSender(), type, details);
 | 
					      this.emit("debug");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _setDebugState(userId, callId, state) {
 | 
				
			||||||
 | 
					    if (userId) {
 | 
				
			||||||
 | 
					      const userState = this.debugState.users.get(userId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (userState) {
 | 
				
			||||||
 | 
					        userState.state = state;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.debugState.users.set(userId, {
 | 
				
			||||||
 | 
					          state,
 | 
				
			||||||
 | 
					          events: [],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (callId) {
 | 
				
			||||||
 | 
					      const callState = this.debugState.calls.get(callId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (callState) {
 | 
				
			||||||
 | 
					        callState.state = state;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.debugState.calls.set(callId, {
 | 
				
			||||||
 | 
					          state,
 | 
				
			||||||
 | 
					          events: [],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.emit("debug");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _updateParticipantState = () => {
 | 
					  _updateParticipantState = () => {
 | 
				
			||||||
    const userId = this.client.getUserId();
 | 
					    const userId = this.client.getUserId();
 | 
				
			||||||
    const currentMemberState = this.room.currentState.getStateEvents(
 | 
					    const currentMemberState = this.room.currentState.getStateEvents(
 | 
				
			||||||
| 
						 | 
					@ -286,20 +320,19 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
      new Date().getTime() - participantTimeout > PARTICIPANT_TIMEOUT
 | 
					      new Date().getTime() - participantTimeout > PARTICIPANT_TIMEOUT
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
      // Member is inactive so don't call them.
 | 
					      // Member is inactive so don't call them.
 | 
				
			||||||
      this._setDebugState(userId, "inactive");
 | 
					      this._setDebugState(userId, null, "inactive");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Only initiate a call with a user who has a userId that is lexicographically
 | 
					    // Only initiate a call with a user who has a userId that is lexicographically
 | 
				
			||||||
    // less than your own. Otherwise, that user will call you.
 | 
					    // less than your own. Otherwise, that user will call you.
 | 
				
			||||||
    if (userId < localUserId) {
 | 
					    if (userId < localUserId) {
 | 
				
			||||||
      this._setDebugState(userId, "waiting for invite");
 | 
					      this._setDebugState(userId, null, "waiting for invite");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const call = this.client.createCall(this.roomId, userId);
 | 
					    const call = this.client.createCall(this.roomId, userId);
 | 
				
			||||||
    this._addCall(call, userId);
 | 
					    this._addCall(call, userId);
 | 
				
			||||||
    this._setDebugState(userId, "calling");
 | 
					 | 
				
			||||||
    call.placeVideoCall();
 | 
					    call.placeVideoCall();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -342,7 +375,6 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const userId = call.opponentMember.userId;
 | 
					    const userId = call.opponentMember.userId;
 | 
				
			||||||
    this._addCall(call, userId);
 | 
					    this._addCall(call, userId);
 | 
				
			||||||
    this._setDebugState(userId, "answered");
 | 
					 | 
				
			||||||
    call.answer();
 | 
					    call.answer();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -365,8 +397,9 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
      call,
 | 
					      call,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this._setDebugCallId(userId, call.callId);
 | 
					    call.on("state", (state) =>
 | 
				
			||||||
 | 
					      this._setDebugState(userId, call.callId, state)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    call.on("feeds_changed", () => this._onCallFeedsChanged(call));
 | 
					    call.on("feeds_changed", () => this._onCallFeedsChanged(call));
 | 
				
			||||||
    call.on("hangup", () => this._onCallHangup(call));
 | 
					    call.on("hangup", () => this._onCallHangup(call));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -388,7 +421,6 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!this.localParticipant.feed && localFeeds.length > 0) {
 | 
					    if (!this.localParticipant.feed && localFeeds.length > 0) {
 | 
				
			||||||
      this.localParticipant.call = call;
 | 
					      this.localParticipant.call = call;
 | 
				
			||||||
      this._setDebugCallId(this.localParticipant.userId, call.callId);
 | 
					 | 
				
			||||||
      this.localParticipant.feed = localFeeds[0];
 | 
					      this.localParticipant.feed = localFeeds[0];
 | 
				
			||||||
      participantsChanged = true;
 | 
					      participantsChanged = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -400,7 +432,6 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) {
 | 
					    if (remoteFeeds.length > 0 && remoteParticipant.feed !== remoteFeeds[0]) {
 | 
				
			||||||
      remoteParticipant.feed = remoteFeeds[0];
 | 
					      remoteParticipant.feed = remoteFeeds[0];
 | 
				
			||||||
      this._setDebugState(call.opponentMember.userId, "streaming");
 | 
					 | 
				
			||||||
      participantsChanged = true;
 | 
					      participantsChanged = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -410,16 +441,14 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _onCallHangup = (call) => {
 | 
					  _onCallHangup = (call) => {
 | 
				
			||||||
    if (call.hangupReason === "replaced") {
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this._setDebugState(call.opponentMember.userId, "hungup");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const participantIndex = this.participants.findIndex(
 | 
					    const participantIndex = this.participants.findIndex(
 | 
				
			||||||
      (p) => !p.local && p.call === call
 | 
					      (p) => !p.local && p.call === call
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (call.hangupReason === "replaced") {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (participantIndex === -1) {
 | 
					    if (participantIndex === -1) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -436,16 +465,13 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (localFeeds.length > 0) {
 | 
					        if (localFeeds.length > 0) {
 | 
				
			||||||
          this.localParticipant.call = call;
 | 
					          this.localParticipant.call = call;
 | 
				
			||||||
          this._setDebugCallId(this.localParticipant.userId, call.callId);
 | 
					 | 
				
			||||||
          this.localParticipant.feed = localFeeds[0];
 | 
					          this.localParticipant.feed = localFeeds[0];
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          this.localParticipant.call = null;
 | 
					          this.localParticipant.call = null;
 | 
				
			||||||
          this._setDebugCallId(this.localParticipant.userId, null);
 | 
					 | 
				
			||||||
          this.localParticipant.feed = null;
 | 
					          this.localParticipant.feed = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        this.localParticipant.call = null;
 | 
					        this.localParticipant.call = null;
 | 
				
			||||||
        this._setDebugCallId(this.localParticipant.userId, null);
 | 
					 | 
				
			||||||
        this.localParticipant.feed = null;
 | 
					        this.localParticipant.feed = null;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -454,17 +480,11 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _onCallReplaced = (call, newCall) => {
 | 
					  _onCallReplaced = (call, newCall) => {
 | 
				
			||||||
    this._addDebugEvent(call.opponentMember.userId, "replaced", {
 | 
					 | 
				
			||||||
      callId: call.callId,
 | 
					 | 
				
			||||||
      newCallId: newCall.callId,
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const remoteParticipant = this.participants.find(
 | 
					    const remoteParticipant = this.participants.find(
 | 
				
			||||||
      (p) => !p.local && p.call === call
 | 
					      (p) => !p.local && p.call === call
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    remoteParticipant.call = newCall;
 | 
					    remoteParticipant.call = newCall;
 | 
				
			||||||
    this._setDebugCallId(remoteParticipant.userId, newCall.callId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall));
 | 
					    newCall.on("feeds_changed", () => this._onCallFeedsChanged(newCall));
 | 
				
			||||||
    newCall.on("hangup", () => this._onCallHangup(newCall));
 | 
					    newCall.on("hangup", () => this._onCallHangup(newCall));
 | 
				
			||||||
| 
						 | 
					@ -507,48 +527,10 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    this.participants = [this.localParticipant];
 | 
					    this.participants = [this.localParticipant];
 | 
				
			||||||
    this.localParticipant.feed = null;
 | 
					    this.localParticipant.feed = null;
 | 
				
			||||||
    this.localParticipant.call = null;
 | 
					    this.localParticipant.call = null;
 | 
				
			||||||
    this._setDebugCallId(this.localParticipant.userId, null);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.emit("participants_changed");
 | 
					    this.emit("participants_changed");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _addDebugEvent(sender, type, content) {
 | 
					 | 
				
			||||||
    if (!this.debugState.has(sender)) {
 | 
					 | 
				
			||||||
      this.debugState.set(sender, {
 | 
					 | 
				
			||||||
        callId: null,
 | 
					 | 
				
			||||||
        state: "unknown",
 | 
					 | 
				
			||||||
        events: [{ type, ...content }],
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      const { events } = this.debugState.get(sender);
 | 
					 | 
				
			||||||
      events.push({ type, roomId: this.roomId, ...content });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.emit("debug");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  _setDebugState(userId, state) {
 | 
					 | 
				
			||||||
    if (!this.debugState.has(userId)) {
 | 
					 | 
				
			||||||
      this.debugState.set(userId, { state, callId: null, events: [] });
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      const userState = this.debugState.get(userId);
 | 
					 | 
				
			||||||
      userState.state = state;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.emit("debug");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  _setDebugCallId(userId, callId) {
 | 
					 | 
				
			||||||
    if (!this.debugState.has(userId)) {
 | 
					 | 
				
			||||||
      this.debugState.set(userId, { state: "unknown", callId, events: [] });
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      const userState = this.debugState.get(userId);
 | 
					 | 
				
			||||||
      userState.callId = callId;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this.emit("debug");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  logout() {
 | 
					  logout() {
 | 
				
			||||||
    localStorage.removeItem("matrix-auth-store");
 | 
					    localStorage.removeItem("matrix-auth-store");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -136,6 +136,8 @@ export function useVideoRoom(manager, roomId, timeout = 5000) {
 | 
				
			||||||
      error: undefined,
 | 
					      error: undefined,
 | 
				
			||||||
    }));
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    manager.setRoom(roomId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    manager.client.joinRoom(roomId).catch((err) => {
 | 
					    manager.client.joinRoom(roomId).catch((err) => {
 | 
				
			||||||
      setState((prevState) => ({ ...prevState, loading: false, error: err }));
 | 
					      setState((prevState) => ({ ...prevState, loading: false, error: err }));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -196,7 +198,7 @@ export function useVideoRoom(manager, roomId, timeout = 5000) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    manager.on("participants_changed", onParticipantsChanged);
 | 
					    manager.on("participants_changed", onParticipantsChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    manager.join(roomId);
 | 
					    manager.join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setState((prevState) => ({
 | 
					    setState((prevState) => ({
 | 
				
			||||||
      ...prevState,
 | 
					      ...prevState,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										153
									
								
								src/DevTools.jsx
									
										
									
									
									
								
							
							
						
						
									
										153
									
								
								src/DevTools.jsx
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
 | 
					import React, { useCallback, useEffect, useRef, useState } from "react";
 | 
				
			||||||
import ColorHash from "color-hash";
 | 
					import ColorHash from "color-hash";
 | 
				
			||||||
 | 
					import classNames from "classnames";
 | 
				
			||||||
import styles from "./DevTools.module.css";
 | 
					import styles from "./DevTools.module.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const colorHash = new ColorHash({ lightness: 0.8 });
 | 
					const colorHash = new ColorHash({ lightness: 0.8 });
 | 
				
			||||||
| 
						 | 
					@ -25,13 +26,27 @@ function CallId({ callId, ...rest }) {
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function sortEntries(a, b) {
 | 
				
			||||||
 | 
					  const aInactive = a[1].state === "inactive";
 | 
				
			||||||
 | 
					  const bInactive = b[1].state === "inactive";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (aInactive && !bInactive) {
 | 
				
			||||||
 | 
					    return 1;
 | 
				
			||||||
 | 
					  } else if (bInactive && !aInactive) {
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return a[0] < b[0] ? -1 : 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function DevTools({ manager }) {
 | 
					export function DevTools({ manager }) {
 | 
				
			||||||
  const [debugState, setDebugState] = useState(manager.debugState);
 | 
					  const [debugState, setDebugState] = useState(manager.debugState);
 | 
				
			||||||
  const [selectedEvent, setSelectedEvent] = useState();
 | 
					  const [selectedEvent, setSelectedEvent] = useState();
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("users");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    function onRoomDebug() {
 | 
					    function onRoomDebug() {
 | 
				
			||||||
      setDebugState(manager.debugState);
 | 
					      setDebugState({ ...manager.debugState });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    manager.on("debug", onRoomDebug);
 | 
					    manager.on("debug", onRoomDebug);
 | 
				
			||||||
| 
						 | 
					@ -47,15 +62,50 @@ export function DevTools({ manager }) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={styles.devTools}>
 | 
					    <div className={styles.devTools}>
 | 
				
			||||||
      {Array.from(debugState.entries()).map(([userId, props]) => (
 | 
					      <div className={styles.toolbar}>
 | 
				
			||||||
        <UserState
 | 
					        <div
 | 
				
			||||||
 | 
					          className={classNames(styles.tab, {
 | 
				
			||||||
 | 
					            [styles.activeTab]: activeTab === "users",
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					          onClick={() => setActiveTab("users")}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Users
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div
 | 
				
			||||||
 | 
					          className={classNames(styles.tab, {
 | 
				
			||||||
 | 
					            [styles.activeTab]: activeTab === "calls",
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					          onClick={() => setActiveTab("calls")}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          Calls
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className={styles.devToolsContainer}>
 | 
				
			||||||
 | 
					        {activeTab === "users" &&
 | 
				
			||||||
 | 
					          Array.from(debugState.users.entries())
 | 
				
			||||||
 | 
					            .sort(sortEntries)
 | 
				
			||||||
 | 
					            .map(([userId, props]) => (
 | 
				
			||||||
 | 
					              <EventContainer
 | 
				
			||||||
                key={userId}
 | 
					                key={userId}
 | 
				
			||||||
          roomId={manager.roomId}
 | 
					                showCallId
 | 
				
			||||||
          onSelectEvent={setSelectedEvent}
 | 
					                title={<UserId userId={userId} />}
 | 
				
			||||||
          userId={userId}
 | 
					 | 
				
			||||||
                {...props}
 | 
					                {...props}
 | 
				
			||||||
 | 
					                onSelect={setSelectedEvent}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            ))}
 | 
					            ))}
 | 
				
			||||||
 | 
					        {activeTab === "calls" &&
 | 
				
			||||||
 | 
					          Array.from(debugState.calls.entries())
 | 
				
			||||||
 | 
					            .sort(sortEntries)
 | 
				
			||||||
 | 
					            .map(([callId, props]) => (
 | 
				
			||||||
 | 
					              <EventContainer
 | 
				
			||||||
 | 
					                key={callId}
 | 
				
			||||||
 | 
					                showSender
 | 
				
			||||||
 | 
					                title={<CallId callId={callId} />}
 | 
				
			||||||
 | 
					                {...props}
 | 
				
			||||||
 | 
					                onSelect={setSelectedEvent}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            ))}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      {selectedEvent && (
 | 
					      {selectedEvent && (
 | 
				
			||||||
        <EventViewer
 | 
					        <EventViewer
 | 
				
			||||||
          event={selectedEvent}
 | 
					          event={selectedEvent}
 | 
				
			||||||
| 
						 | 
					@ -66,7 +116,7 @@ export function DevTools({ manager }) {
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function UserState({ roomId, userId, state, callId, events, onSelectEvent }) {
 | 
					function EventContainer({ title, state, events, ...rest }) {
 | 
				
			||||||
  const eventsRef = useRef();
 | 
					  const eventsRef = useRef();
 | 
				
			||||||
  const [autoScroll, setAutoScroll] = useState(true);
 | 
					  const [autoScroll, setAutoScroll] = useState(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,78 +140,59 @@ function UserState({ roomId, userId, state, callId, events, onSelectEvent }) {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={styles.user}>
 | 
					    <div className={styles.user}>
 | 
				
			||||||
      <div className={styles.userId}>
 | 
					      <div className={styles.userId}>
 | 
				
			||||||
        <UserId userId={userId} />
 | 
					        <span>{title}</span>
 | 
				
			||||||
        <span>{`(${state})`}</span>
 | 
					        <span>{`(${state})`}</span>
 | 
				
			||||||
        {callId && <CallId callId={callId} />}
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div ref={eventsRef} className={styles.events} onScroll={onScroll}>
 | 
					      <div ref={eventsRef} className={styles.events} onScroll={onScroll}>
 | 
				
			||||||
        {events
 | 
					        {events.map((event, idx) => (
 | 
				
			||||||
          .filter((e) => e.roomId === roomId)
 | 
					          <EventItem key={idx} event={event} {...rest} />
 | 
				
			||||||
          .map((event, idx) => (
 | 
					 | 
				
			||||||
            <div
 | 
					 | 
				
			||||||
              className={styles.event}
 | 
					 | 
				
			||||||
              key={idx}
 | 
					 | 
				
			||||||
              onClick={() => onSelectEvent(event)}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <span className={styles.eventType}>{event.type}</span>
 | 
					 | 
				
			||||||
              {event.callId && (
 | 
					 | 
				
			||||||
                <CallId className={styles.eventDetails} callId={event.callId} />
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
              {event.newCallId && (
 | 
					 | 
				
			||||||
                <>
 | 
					 | 
				
			||||||
                  <span className={styles.eventDetails}>{"->"}</span>
 | 
					 | 
				
			||||||
                  <CallId
 | 
					 | 
				
			||||||
                    className={styles.eventDetails}
 | 
					 | 
				
			||||||
                    callId={event.newCallId}
 | 
					 | 
				
			||||||
                  />
 | 
					 | 
				
			||||||
                </>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
              {event.to && (
 | 
					 | 
				
			||||||
                <UserId className={styles.eventDetails} userId={event.to} />
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
              {event.reason && (
 | 
					 | 
				
			||||||
                <span className={styles.eventDetails}>{event.reason}</span>
 | 
					 | 
				
			||||||
              )}
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
        ))}
 | 
					        ))}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function EventItem({ event, showCallId, showSender, onSelect }) {
 | 
				
			||||||
 | 
					  const type = event.getType();
 | 
				
			||||||
 | 
					  const sender = event.getSender();
 | 
				
			||||||
 | 
					  const { call_id, invitee } = event.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className={styles.event} onClick={() => onSelect(event)}>
 | 
				
			||||||
 | 
					      {showSender && sender && (
 | 
				
			||||||
 | 
					        <UserId className={styles.eventDetails} userId={sender} />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <span className={styles.eventType}>{type}</span>
 | 
				
			||||||
 | 
					      {showCallId && call_id && (
 | 
				
			||||||
 | 
					        <CallId className={styles.eventDetails} callId={call_id} />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {invitee && <UserId className={styles.eventDetails} userId={invitee} />}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function EventViewer({ event, onClose }) {
 | 
					function EventViewer({ event, onClose }) {
 | 
				
			||||||
 | 
					  const type = event.getType();
 | 
				
			||||||
 | 
					  const sender = event.getSender();
 | 
				
			||||||
 | 
					  const { call_id, invitee } = event.getContent();
 | 
				
			||||||
 | 
					  const json = event.toJSON();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={styles.eventViewer}>
 | 
					    <div className={styles.eventViewer}>
 | 
				
			||||||
      <p>Event Type: {event.type}</p>
 | 
					      <p>Event Type: {type}</p>
 | 
				
			||||||
      {event.callId && (
 | 
					      <p>Sender: {sender}</p>
 | 
				
			||||||
 | 
					      {call_id && (
 | 
				
			||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
          Call Id: <CallId callId={event.callId} />
 | 
					          Call Id: <CallId callId={call_id} />
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
      {event.newCallId && (
 | 
					      {invitee && (
 | 
				
			||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
          New Call Id:
 | 
					          Invitee: <UserId userId={invitee} />
 | 
				
			||||||
          <CallId callId={event.newCallId} />
 | 
					 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
      {event.to && (
 | 
					      <p>Raw Event:</p>
 | 
				
			||||||
        <p>
 | 
					      <pre className={styles.content}>{JSON.stringify(json, undefined, 2)}</pre>
 | 
				
			||||||
          To: <UserId userId={event.to} />
 | 
					 | 
				
			||||||
        </p>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
      {event.reason && (
 | 
					 | 
				
			||||||
        <p>
 | 
					 | 
				
			||||||
          Reason: <span>{event.reason}</span>
 | 
					 | 
				
			||||||
        </p>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
      {event.content && (
 | 
					 | 
				
			||||||
        <>
 | 
					 | 
				
			||||||
          <p>Content:</p>
 | 
					 | 
				
			||||||
          <pre className={styles.content}>
 | 
					 | 
				
			||||||
            {JSON.stringify(event.content, undefined, 2)}
 | 
					 | 
				
			||||||
          </pre>
 | 
					 | 
				
			||||||
        </>
 | 
					 | 
				
			||||||
      )}
 | 
					 | 
				
			||||||
      <button onClick={onClose}>Close</button>
 | 
					      <button onClick={onClose}>Close</button>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,31 @@
 | 
				
			||||||
.devTools {
 | 
					.devTools {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  height: 250px;
 | 
					  flex-direction: column;
 | 
				
			||||||
  border-top: 2px solid #111;
 | 
					  border-top: 2px solid #111;
 | 
				
			||||||
  gap: 2px;
 | 
					 | 
				
			||||||
  background-color: #111;
 | 
					  background-color: #111;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.toolbar {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  background-color: #222;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tab {
 | 
				
			||||||
 | 
					  vertical-align: middle;
 | 
				
			||||||
 | 
					  padding: 4px 8px;
 | 
				
			||||||
 | 
					  background-color: #444;
 | 
				
			||||||
 | 
					  margin: 0 2px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.activeTab {
 | 
				
			||||||
 | 
					  background-color: #666;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.devToolsContainer {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  height: 250px;
 | 
				
			||||||
 | 
					  gap: 2px;
 | 
				
			||||||
  overflow-x: auto;
 | 
					  overflow-x: auto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue