Add stats reporting
This commit is contained in:
		
					parent
					
						
							
								a231154bd7
							
						
					
				
			
			
				commit
				
					
						56d1c9fa33
					
				
			
		
					 3 changed files with 321 additions and 5 deletions
				
			
		| 
						 | 
					@ -188,6 +188,7 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
      const userId = call.opponentMember.userId;
 | 
					      const userId = call.opponentMember.userId;
 | 
				
			||||||
      this._addCall(call, userId);
 | 
					      this._addCall(call, userId);
 | 
				
			||||||
      call.answer();
 | 
					      call.answer();
 | 
				
			||||||
 | 
					      this._observePeerConnection(call);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.pendingCalls = [];
 | 
					    this.pendingCalls = [];
 | 
				
			||||||
| 
						 | 
					@ -199,7 +200,10 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    const roomId = event.getRoomId();
 | 
					    const roomId = event.getRoomId();
 | 
				
			||||||
    const type = event.getType();
 | 
					    const type = event.getType();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (roomId === this.roomId && type.startsWith("m.call.")) {
 | 
					    if (
 | 
				
			||||||
 | 
					      roomId === this.roomId &&
 | 
				
			||||||
 | 
					      (type.startsWith("m.call.") || type === "me.robertlong.call.info")
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
      const sender = event.getSender();
 | 
					      const sender = event.getSender();
 | 
				
			||||||
      const { call_id } = event.getContent();
 | 
					      const { call_id } = event.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -333,7 +337,298 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const call = this.client.createCall(this.roomId, userId);
 | 
					    const call = this.client.createCall(this.roomId, userId);
 | 
				
			||||||
    this._addCall(call, userId);
 | 
					    this._addCall(call, userId);
 | 
				
			||||||
    call.placeVideoCall();
 | 
					    call.placeVideoCall().then(() => {
 | 
				
			||||||
 | 
					      this._observePeerConnection(call);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _observePeerConnection(call) {
 | 
				
			||||||
 | 
					    const peerConnection = call.peerConn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!peerConnection) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const sendWebRTCInfoEvent = async (eventType) => {
 | 
				
			||||||
 | 
					      const event = {
 | 
				
			||||||
 | 
					        call_id: call.callId,
 | 
				
			||||||
 | 
					        eventType,
 | 
				
			||||||
 | 
					        iceConnectionState: peerConnection.iceConnectionState,
 | 
				
			||||||
 | 
					        iceGatheringState: peerConnection.iceGatheringState,
 | 
				
			||||||
 | 
					        signalingState: peerConnection.signalingState,
 | 
				
			||||||
 | 
					        selectedCandidatePair: null,
 | 
				
			||||||
 | 
					        localCandidate: null,
 | 
				
			||||||
 | 
					        remoteCandidate: null,
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // getStats doesn't support selectors in Firefox so get all stats by passing null.
 | 
				
			||||||
 | 
					      // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/getStats#browser_compatibility
 | 
				
			||||||
 | 
					      const stats = await peerConnection.getStats(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const statsArr = Array.from(stats.values());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Matrix doesn't support floats so we convert time in seconds to ms
 | 
				
			||||||
 | 
					      function secToMs(time) {
 | 
				
			||||||
 | 
					        if (time === undefined) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Math.round(time * 1000);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processTransportStats(transportStats) {
 | 
				
			||||||
 | 
					        if (!transportStats) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          packetsSent: transportStats.packetsSent,
 | 
				
			||||||
 | 
					          packetsReceived: transportStats.packetsReceived,
 | 
				
			||||||
 | 
					          bytesSent: transportStats.bytesSent,
 | 
				
			||||||
 | 
					          bytesReceived: transportStats.bytesReceived,
 | 
				
			||||||
 | 
					          iceRole: transportStats.iceRole,
 | 
				
			||||||
 | 
					          iceState: transportStats.iceState,
 | 
				
			||||||
 | 
					          dtlsState: transportStats.dtlsState,
 | 
				
			||||||
 | 
					          dtlsCipher: transportStats.dtlsCipher,
 | 
				
			||||||
 | 
					          tlsVersion: transportStats.tlsVersion,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processCandidateStats(candidateStats) {
 | 
				
			||||||
 | 
					        if (!candidateStats) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO: Figure out how to normalize ip and address across browsers
 | 
				
			||||||
 | 
					        // networkType property excluded for privacy reasons:
 | 
				
			||||||
 | 
					        // https://www.w3.org/TR/webrtc-stats/#sotd
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          protocol: candidateStats.protocol,
 | 
				
			||||||
 | 
					          address: candidateStats.address || candidateStats.ip,
 | 
				
			||||||
 | 
					          port: candidateStats.port,
 | 
				
			||||||
 | 
					          url: candidateStats.url,
 | 
				
			||||||
 | 
					          relayProtocol: candidateStats.relayProtocol,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processCandidatePair(candidatePairStats) {
 | 
				
			||||||
 | 
					        if (!candidatePairStats) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const localCandidateStats = statsArr.find(
 | 
				
			||||||
 | 
					          (stat) => stat.id === candidatePairStats.localCandidateId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        event.localCandidate = processCandidateStats(localCandidateStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const remoteCandidateStats = statsArr.find(
 | 
				
			||||||
 | 
					          (stat) => stat.id === candidatePairStats.remoteCandidateId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        event.remoteCandidate = processCandidateStats(remoteCandidateStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const transportStats = statsArr.find(
 | 
				
			||||||
 | 
					          (stat) => stat.id === candidatePairStats.transportId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        event.transport = processTransportStats(transportStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          state: candidatePairStats.state,
 | 
				
			||||||
 | 
					          bytesSent: candidatePairStats.bytesSent,
 | 
				
			||||||
 | 
					          bytesReceived: candidatePairStats.bytesReceived,
 | 
				
			||||||
 | 
					          requestsSent: candidatePairStats.requestsSent,
 | 
				
			||||||
 | 
					          requestsReceived: candidatePairStats.requestsReceived,
 | 
				
			||||||
 | 
					          responsesSent: candidatePairStats.responsesSent,
 | 
				
			||||||
 | 
					          responsesReceived: candidatePairStats.responsesReceived,
 | 
				
			||||||
 | 
					          currentRoundTripTime: secToMs(
 | 
				
			||||||
 | 
					            candidatePairStats.currentRoundTripTime
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          totalRoundTripTime: secToMs(candidatePairStats.totalRoundTripTime),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Firefox uses the deprecated "selected" property for the nominated ice candidate.
 | 
				
			||||||
 | 
					      const selectedCandidatePair = statsArr.find(
 | 
				
			||||||
 | 
					        (stat) =>
 | 
				
			||||||
 | 
					          stat.type === "candidate-pair" && (stat.selected || stat.nominated)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      event.selectedCandidatePair = processCandidatePair(selectedCandidatePair);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processCodecStats(codecStats) {
 | 
				
			||||||
 | 
					        if (!codecStats) {
 | 
				
			||||||
 | 
					          return undefined;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Payload type enums and MIME types listed here:
 | 
				
			||||||
 | 
					        // https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          mimeType: codecStats.mimeType,
 | 
				
			||||||
 | 
					          clockRate: codecStats.clockRate,
 | 
				
			||||||
 | 
					          payloadType: codecStats.payloadType,
 | 
				
			||||||
 | 
					          channels: codecStats.channels,
 | 
				
			||||||
 | 
					          sdpFmtpLine: codecStats.sdpFmtpLine,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processRTPStreamStats(rtpStreamStats) {
 | 
				
			||||||
 | 
					        const codecStats = statsArr.find(
 | 
				
			||||||
 | 
					          (stat) => stat.id === rtpStreamStats.codecId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const codec = processCodecStats(codecStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          kind: rtpStreamStats.kind,
 | 
				
			||||||
 | 
					          codec,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processInboundRTPStats(inboundRTPStats) {
 | 
				
			||||||
 | 
					        const rtpStreamStats = processRTPStreamStats(inboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          ...rtpStreamStats,
 | 
				
			||||||
 | 
					          decoderImplementation: inboundRTPStats.decoderImplementation,
 | 
				
			||||||
 | 
					          bytesReceived: inboundRTPStats.bytesReceived,
 | 
				
			||||||
 | 
					          packetsReceived: inboundRTPStats.packetsReceived,
 | 
				
			||||||
 | 
					          packetsLost: inboundRTPStats.packetsLost,
 | 
				
			||||||
 | 
					          jitter: secToMs(inboundRTPStats.jitter),
 | 
				
			||||||
 | 
					          frameWidth: inboundRTPStats.frameWidth,
 | 
				
			||||||
 | 
					          frameHeight: inboundRTPStats.frameHeight,
 | 
				
			||||||
 | 
					          frameBitDepth: inboundRTPStats.frameBitDepth,
 | 
				
			||||||
 | 
					          framesPerSecond:
 | 
				
			||||||
 | 
					            inboundRTPStats.framesPerSecond &&
 | 
				
			||||||
 | 
					            inboundRTPStats.framesPerSecond.toString(),
 | 
				
			||||||
 | 
					          framesReceived: inboundRTPStats.framesReceived,
 | 
				
			||||||
 | 
					          framesDecoded: inboundRTPStats.framesDecoded,
 | 
				
			||||||
 | 
					          framesDropped: inboundRTPStats.framesDropped,
 | 
				
			||||||
 | 
					          totalSamplesDecoded: inboundRTPStats.totalSamplesDecoded,
 | 
				
			||||||
 | 
					          totalDecodeTime: secToMs(inboundRTPStats.totalDecodeTime),
 | 
				
			||||||
 | 
					          totalProcessingDelay: secToMs(inboundRTPStats.totalProcessingDelay),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processOutboundRTPStats(outboundRTPStats) {
 | 
				
			||||||
 | 
					        const rtpStreamStats = processRTPStreamStats(outboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          ...rtpStreamStats,
 | 
				
			||||||
 | 
					          encoderImplementation: outboundRTPStats.encoderImplementation,
 | 
				
			||||||
 | 
					          bytesSent: outboundRTPStats.bytesSent,
 | 
				
			||||||
 | 
					          packetsSent: outboundRTPStats.packetsSent,
 | 
				
			||||||
 | 
					          frameWidth: outboundRTPStats.frameWidth,
 | 
				
			||||||
 | 
					          frameHeight: outboundRTPStats.frameHeight,
 | 
				
			||||||
 | 
					          frameBitDepth: outboundRTPStats.frameBitDepth,
 | 
				
			||||||
 | 
					          framesPerSecond:
 | 
				
			||||||
 | 
					            outboundRTPStats.framesPerSecond &&
 | 
				
			||||||
 | 
					            outboundRTPStats.framesPerSecond.toString(),
 | 
				
			||||||
 | 
					          framesSent: outboundRTPStats.framesSent,
 | 
				
			||||||
 | 
					          framesEncoded: outboundRTPStats.framesEncoded,
 | 
				
			||||||
 | 
					          qualityLimitationReason: outboundRTPStats.qualityLimitationReason,
 | 
				
			||||||
 | 
					          qualityLimitationResolutionChanges:
 | 
				
			||||||
 | 
					            outboundRTPStats.qualityLimitationResolutionChanges,
 | 
				
			||||||
 | 
					          totalEncodeTime: secToMs(outboundRTPStats.totalEncodeTime),
 | 
				
			||||||
 | 
					          totalPacketSendDelay: secToMs(outboundRTPStats.totalPacketSendDelay),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processRemoteInboundRTPStats(remoteInboundRTPStats) {
 | 
				
			||||||
 | 
					        const rtpStreamStats = processRTPStreamStats(remoteInboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          ...rtpStreamStats,
 | 
				
			||||||
 | 
					          packetsReceived: remoteInboundRTPStats.packetsReceived,
 | 
				
			||||||
 | 
					          packetsLost: remoteInboundRTPStats.packetsLost,
 | 
				
			||||||
 | 
					          jitter: secToMs(remoteInboundRTPStats.jitter),
 | 
				
			||||||
 | 
					          framesDropped: remoteInboundRTPStats.framesDropped,
 | 
				
			||||||
 | 
					          roundTripTime: secToMs(remoteInboundRTPStats.roundTripTime),
 | 
				
			||||||
 | 
					          totalRoundTripTime: secToMs(remoteInboundRTPStats.totalRoundTripTime),
 | 
				
			||||||
 | 
					          fractionLost:
 | 
				
			||||||
 | 
					            remoteInboundRTPStats.fractionLost !== undefined &&
 | 
				
			||||||
 | 
					            remoteInboundRTPStats.fractionLost.toString(),
 | 
				
			||||||
 | 
					          reportsReceived: remoteInboundRTPStats.reportsReceived,
 | 
				
			||||||
 | 
					          roundTripTimeMeasurements:
 | 
				
			||||||
 | 
					            remoteInboundRTPStats.roundTripTimeMeasurements,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      function processRemoteOutboundRTPStats(remoteOutboundRTPStats) {
 | 
				
			||||||
 | 
					        const rtpStreamStats = processRTPStreamStats(remoteOutboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          ...rtpStreamStats,
 | 
				
			||||||
 | 
					          encoderImplementation: remoteOutboundRTPStats.encoderImplementation,
 | 
				
			||||||
 | 
					          bytesSent: remoteOutboundRTPStats.bytesSent,
 | 
				
			||||||
 | 
					          packetsSent: remoteOutboundRTPStats.packetsSent,
 | 
				
			||||||
 | 
					          roundTripTime: secToMs(remoteOutboundRTPStats.roundTripTime),
 | 
				
			||||||
 | 
					          totalRoundTripTime: secToMs(
 | 
				
			||||||
 | 
					            remoteOutboundRTPStats.totalRoundTripTime
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          reportsSent: remoteOutboundRTPStats.reportsSent,
 | 
				
			||||||
 | 
					          roundTripTimeMeasurements:
 | 
				
			||||||
 | 
					            remoteOutboundRTPStats.roundTripTimeMeasurements,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      event.inboundRTP = statsArr
 | 
				
			||||||
 | 
					        .filter((stat) => stat.type === "inbound-rtp")
 | 
				
			||||||
 | 
					        .map(processInboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      event.outboundRTP = statsArr
 | 
				
			||||||
 | 
					        .filter((stat) => stat.type === "outbound-rtp")
 | 
				
			||||||
 | 
					        .map(processOutboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      event.remoteInboundRTP = statsArr
 | 
				
			||||||
 | 
					        .filter((stat) => stat.type === "remote-inbound-rtp")
 | 
				
			||||||
 | 
					        .map(processRemoteInboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      event.remoteOutboundRTP = statsArr
 | 
				
			||||||
 | 
					        .filter((stat) => stat.type === "remote-outbound-rtp")
 | 
				
			||||||
 | 
					        .map(processRemoteOutboundRTPStats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.client.sendEvent(this.roomId, "me.robertlong.call.info", event);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let statsTimeout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const sendStats = () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("stats");
 | 
				
			||||||
 | 
					      statsTimeout = setTimeout(sendStats, 30 * 1000);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(sendStats, 30 * 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    peerConnection.addEventListener("iceconnectionstatechange", () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("iceconnectionstatechange");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    peerConnection.addEventListener("icegatheringstatechange", () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("icegatheringstatechange");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    peerConnection.addEventListener("negotiationneeded", () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("negotiationneeded");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    peerConnection.addEventListener("track", () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("track");
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // NOTE: Not available on Firefox
 | 
				
			||||||
 | 
					    // https://bugzilla.mozilla.org/show_bug.cgi?id=1561441
 | 
				
			||||||
 | 
					    peerConnection.addEventListener(
 | 
				
			||||||
 | 
					      "icecandidateerror",
 | 
				
			||||||
 | 
					      ({ errorCode, url, errorText }) => {
 | 
				
			||||||
 | 
					        this.client.sendEvent(this.roomId, "me.robertlong.call.ice_error", {
 | 
				
			||||||
 | 
					          call_id: call.callId,
 | 
				
			||||||
 | 
					          errorCode,
 | 
				
			||||||
 | 
					          url,
 | 
				
			||||||
 | 
					          errorText,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    peerConnection.addEventListener("signalingstatechange", () => {
 | 
				
			||||||
 | 
					      sendWebRTCInfoEvent("signalingstatechange");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (peerConnection.signalingState === "closed") {
 | 
				
			||||||
 | 
					        clearTimeout(statsTimeout);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _onIncomingCall = (call) => {
 | 
					  _onIncomingCall = (call) => {
 | 
				
			||||||
| 
						 | 
					@ -376,6 +671,7 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    const userId = call.opponentMember.userId;
 | 
					    const userId = call.opponentMember.userId;
 | 
				
			||||||
    this._addCall(call, userId);
 | 
					    this._addCall(call, userId);
 | 
				
			||||||
    call.answer();
 | 
					    call.answer();
 | 
				
			||||||
 | 
					    this._observePeerConnection(call);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _addCall(call, userId) {
 | 
					  _addCall(call, userId) {
 | 
				
			||||||
| 
						 | 
					@ -485,6 +781,7 @@ export class ConferenceCallManager extends EventEmitter {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    remoteParticipant.call = newCall;
 | 
					    remoteParticipant.call = newCall;
 | 
				
			||||||
 | 
					    this._observePeerConnection(newCall);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,19 +155,33 @@ function EventContainer({ title, state, events, ...rest }) {
 | 
				
			||||||
function EventItem({ event, showCallId, showSender, onSelect }) {
 | 
					function EventItem({ event, showCallId, showSender, onSelect }) {
 | 
				
			||||||
  const type = event.getType();
 | 
					  const type = event.getType();
 | 
				
			||||||
  const sender = event.getSender();
 | 
					  const sender = event.getSender();
 | 
				
			||||||
  const { call_id, invitee, reason } = event.getContent();
 | 
					  const { call_id, invitee, reason, eventType, ...rest } = event.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let eventValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (eventType === "icegatheringstatechange") {
 | 
				
			||||||
 | 
					    eventValue = rest.iceGatheringState;
 | 
				
			||||||
 | 
					  } else if (eventType === "iceconnectionstatechange") {
 | 
				
			||||||
 | 
					    eventValue = rest.iceConnectionState;
 | 
				
			||||||
 | 
					  } else if (eventType === "signalingstatechange") {
 | 
				
			||||||
 | 
					    eventValue = rest.signalingState;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className={styles.event} onClick={() => onSelect(event)}>
 | 
					    <div className={styles.event} onClick={() => onSelect(event)}>
 | 
				
			||||||
      {showSender && sender && (
 | 
					      {showSender && sender && (
 | 
				
			||||||
        <UserId className={styles.eventDetails} userId={sender} />
 | 
					        <UserId className={styles.eventDetails} userId={sender} />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
      <span className={styles.eventType}>{type}</span>
 | 
					      <span className={styles.eventType}>
 | 
				
			||||||
 | 
					        {type.replace("me.robertlong.", "x.")}
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
      {showCallId && call_id && (
 | 
					      {showCallId && call_id && (
 | 
				
			||||||
        <CallId className={styles.eventDetails} callId={call_id} />
 | 
					        <CallId className={styles.eventDetails} callId={call_id} />
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
      {invitee && <UserId className={styles.eventDetails} userId={invitee} />}
 | 
					      {invitee && <UserId className={styles.eventDetails} userId={invitee} />}
 | 
				
			||||||
      {reason && <span className={styles.eventDetails}>{reason}</span>}
 | 
					      {reason && <span className={styles.eventDetails}>{reason}</span>}
 | 
				
			||||||
 | 
					      {eventType && <span className={styles.eventDetails}>{eventType}</span>}
 | 
				
			||||||
 | 
					      {eventValue && <span className={styles.eventDetails}>{eventValue}</span>}
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,7 @@
 | 
				
			||||||
  flex-direction: column;
 | 
					  flex-direction: column;
 | 
				
			||||||
  flex: 1;
 | 
					  flex: 1;
 | 
				
			||||||
  background-color: #555;
 | 
					  background-color: #555;
 | 
				
			||||||
  min-width: 320px;
 | 
					  min-width: 512px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.userId {
 | 
					.userId {
 | 
				
			||||||
| 
						 | 
					@ -64,12 +64,17 @@
 | 
				
			||||||
  font-family: monospace;
 | 
					  font-family: monospace;
 | 
				
			||||||
  padding: 4px 12px;
 | 
					  padding: 4px 12px;
 | 
				
			||||||
  background-color: #333;
 | 
					  background-color: #333;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.event:nth-child(even) {
 | 
					.event:nth-child(even) {
 | 
				
			||||||
  background-color: #444;
 | 
					  background-color: #444;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.event:hover {
 | 
				
			||||||
 | 
					  background-color: #555;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.event > * {
 | 
					.event > * {
 | 
				
			||||||
  margin-right: 4px;
 | 
					  margin-right: 4px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue