123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /**
- * This class exports constants and factory methods related to the analytics
- * API provided by AnalyticsAdapter. In order for entries in a database to be
- * somewhat easily traceable back to the code which produced them, events sent
- * through analytics should be defined here.
- *
- * Since the AnalyticsAdapter API can be used in different ways, for some events
- * it is more convenient to just define the event name as a constant. For other
- * events a factory function is easier.
- *
- * A general approach for adding a new event:
- * 1. Determine the event type: track, UI, page, or operational. If in doubt use
- * operational.
- * 2. Determine whether the event is related to other existing events, and
- * which fields are desired to be set: name, action, actionSubject, source.
- * 3. If the name is sufficient (the other fields are not important), use a
- * constant. Otherwise use a factory function.
- *
- * Note that the AnalyticsAdapter uses the events passed to its functions for
- * its own purposes, and might modify them. Because of this, factory functions
- * should create new objects.
- *
- */
-
- export enum AnalyticsEvents {
- /**
- * The constant which identifies an event of type "operational".
- */
- TYPE_OPERATIONAL = 'operational',
-
- /**
- * The constant which identifies an event of type "page".
- */
- TYPE_PAGE = 'page',
-
- /**
- * The constant which identifies an event of type "track".
- */
- TYPE_TRACK = 'track',
-
- /**
- * The constant which identifies an event of type "ui".
- */
- TYPE_UI = 'ui',
-
- /**
- * The "action" value for Jingle events which indicates that the Jingle session
- * was restarted (TODO: verify/fix the documentation)
- */
- ACTION_JINGLE_RESTART = 'restart',
-
- /**
- * The "action" value for Jingle events which indicates that a session-accept
- * timed out (TODO: verify/fix the documentation)
- */
- ACTION_JINGLE_SA_TIMEOUT = 'session-accept.timeout',
-
- /**
- * The "action" value for Jingle events which indicates that a session-initiate
- * was received.
- */
- ACTION_JINGLE_SI_RECEIVED = 'session-initiate.received',
-
- /**
- * The "action" value for Jingle events which indicates that a session-initiate
- * not arrived within a timeout (the value is specified in
- * the {@link JingleSessionPC}.
- */
- ACTION_JINGLE_SI_TIMEOUT = 'session-initiate.timeout',
-
- /**
- * A constant for the "terminate" action for Jingle events. TODO: verify/fix
- * the documentation)
- */
- ACTION_JINGLE_TERMINATE = 'terminate',
-
- /**
- * The "action" value for Jingle events which indicates that a transport-replace
- * was received.
- */
- ACTION_JINGLE_TR_RECEIVED = 'transport-replace.received',
-
- /**
- * The "action" value for Jingle events which indicates that a transport-replace
- * succeeded (TODO: verify/fix the documentation)
- */
- ACTION_JINGLE_TR_SUCCESS = 'transport-replace.success',
-
- /**
- * The "action" value for P2P events which indicates that P2P session initiate message has been rejected by the client
- * because the mandatory requirements were not met.
- */
- ACTION_P2P_DECLINED = 'decline',
-
- /**
- * The "action" value for P2P events which indicates that a connection was
- * established (TODO: verify/fix the documentation)
- */
- ACTION_P2P_ESTABLISHED = 'established',
-
- /**
- * The "action" value for P2P events which indicates that something failed.
- */
- ACTION_P2P_FAILED = 'failed',
-
- /**
- * The "action" value for P2P events which indicates that a switch to
- * jitsi-videobridge happened.
- */
- ACTION_P2P_SWITCH_TO_JVB = 'switch.to.jvb',
-
- /**
- * The name of an event which indicates an available device. We send one such
- * event per available device once when the available devices are first known,
- * and every time that they change
- *
- * Properties:
- * audio_input_device_count: the number of audio input devices available at
- * the time the event was sent.
- * audio_output_device_count: the number of audio output devices available
- * at the time the event was sent.
- * video_input_device_count: the number of video input devices available at
- * the time the event was sent.
- * video_output_device_count: the number of video output devices available
- * at the time the event was sent.
- * device_id: an identifier of the device described in this event.
- * device_group_id:
- * device_kind: one of 'audioinput', 'audiooutput', 'videoinput' or
- * 'videooutput'.
- * device_label: a string which describes the device.
- */
- AVAILABLE_DEVICE = 'available.device',
-
- /**
- * This appears to be fired only in certain cases when the XMPP connection
- * disconnects (and it was intentional?). It is currently never observed to
- * fire in production.
- *
- * TODO: document
- *
- * Properties:
- * message: an error message
- */
- CONNECTION_DISCONNECTED = 'connection.disconnected',
-
- /**
- * Indicates that the user of the application provided feedback in terms of a
- * rating (an integer from 1 to 5) and an optional comment.
- * Properties:
- * value: the user's rating (an integer from 1 to 5)
- * comment: the user's comment
- */
- FEEDBACK = 'feedback',
-
- /**
- * Indicates the duration of a particular phase of the ICE connectivity
- * establishment.
- *
- * Properties:
- * phase: the ICE phase (e.g. 'gathering', 'checking', 'establishment')
- * value: the duration in milliseconds.
- * p2p: whether the associated ICE connection is p2p or towards a
- * jitsi-videobridge
- * initiator: whether the local Jingle peer is the initiator or responder
- * in the Jingle session. XXX we probably actually care about the ICE
- * role (controlling vs controlled), and we assume that this correlates
- * with the Jingle initiator.
- */
- ICE_DURATION = 'ice.duration',
-
- /**
- * Indicates the difference in milliseconds between the ICE establishment time
- * for the P2P and JVB connections (e.g. a value of 10 would indicate that the
- * P2P connection took 10ms more than JVB connection to establish).
- *
- * Properties:
- * value: the difference in establishment durations in milliseconds.
- *
- */
- ICE_ESTABLISHMENT_DURATION_DIFF = 'ice.establishment.duration.diff',
-
- /**
- * Indicates that the ICE state has changed.
- *
- * Properties:
- * state: the ICE state which was entered (e.g. 'checking', 'connected',
- * 'completed', etc).
- * value: the time in milliseconds (as reported by
- * window.performance.now()) that the state change occurred.
- * p2p: whether the associated ICE connection is p2p or towards a
- * jitsi-videobridge
- * signalingState: The signaling state of the associated PeerConnection
- * reconnect: whether the associated Jingle session is in the process of
- * reconnecting (or is it ICE? TODO: verify/fix the documentation)
- */
- ICE_STATE_CHANGED = 'ice.state.changed',
-
- /**
- * Indicates that no bytes have been sent for the track.
- *
- * Properties:
- * mediaType: the media type of the local track ('audio' or 'video').
- */
- NO_BYTES_SENT = 'track.no-bytes-sent',
-
- /**
- * Indicates that a track was unmuted (?).
- *
- * Properties:
- * mediaType: the media type of the local track ('audio' or 'video').
- * trackType: the type of the track ('local' or 'remote').
- * value: TODO: document
- */
- TRACK_UNMUTED = 'track.unmuted'
- }
-
- // exported for backward compatibility
- export const TYPE_OPERATIONAL = AnalyticsEvents.TYPE_OPERATIONAL;
- export const TYPE_PAGE = AnalyticsEvents.TYPE_PAGE;
- export const TYPE_TRACK = AnalyticsEvents.TYPE_TRACK;
- export const TYPE_UI = AnalyticsEvents.TYPE_UI;
- export const ACTION_JINGLE_RESTART = AnalyticsEvents.ACTION_JINGLE_RESTART;
- export const ACTION_JINGLE_SA_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SA_TIMEOUT;
- export const ACTION_JINGLE_SI_RECEIVED = AnalyticsEvents.ACTION_JINGLE_SI_RECEIVED;
- export const ACTION_JINGLE_SI_TIMEOUT = AnalyticsEvents.ACTION_JINGLE_SI_TIMEOUT;
- export const ACTION_JINGLE_TERMINATE = AnalyticsEvents.ACTION_JINGLE_TERMINATE;
- export const ACTION_JINGLE_TR_RECEIVED = AnalyticsEvents.ACTION_JINGLE_TR_RECEIVED;
- export const ACTION_JINGLE_TR_SUCCESS = AnalyticsEvents.ACTION_JINGLE_TR_SUCCESS;
- export const ACTION_P2P_DECLINED = AnalyticsEvents.ACTION_P2P_DECLINED;
- export const ACTION_P2P_ESTABLISHED = AnalyticsEvents.ACTION_P2P_ESTABLISHED;
- export const ACTION_P2P_FAILED = AnalyticsEvents.ACTION_P2P_FAILED;
- export const ACTION_P2P_SWITCH_TO_JVB = AnalyticsEvents.ACTION_P2P_SWITCH_TO_JVB;
- export const AVAILABLE_DEVICE = AnalyticsEvents.AVAILABLE_DEVICE;
- export const CONNECTION_DISCONNECTED = AnalyticsEvents.CONNECTION_DISCONNECTED;
- export const FEEDBACK = AnalyticsEvents.FEEDBACK;
- export const ICE_DURATION = AnalyticsEvents.ICE_DURATION;
- export const ICE_ESTABLISHMENT_DURATION_DIFF = AnalyticsEvents.ICE_ESTABLISHMENT_DURATION_DIFF;
- export const ICE_STATE_CHANGED = AnalyticsEvents.ICE_STATE_CHANGED;
- export const NO_BYTES_SENT = AnalyticsEvents.NO_BYTES_SENT;
- export const TRACK_UNMUTED = AnalyticsEvents.TRACK_UNMUTED;
-
- /**
- * Creates an operational event which indicates that we have received a
- * "bridge down" event from jicofo.
- */
- export const createBridgeDownEvent = () => ( {
- action: 'bridge.down',
- actionSubject: 'bridge.down',
- type: TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an event which indicates that the XMPP connection failed
- * @param errorType TODO
- * @param errorMessage TODO
- * @param detail connection failed details.
- */
- export const createConnectionFailedEvent = ( errorType: unknown, errorMessage: unknown, details: object ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'connection.failed',
- attributes: {
- 'error_type': errorType,
- 'error_message': errorMessage,
- ...details
- }
- } );
-
- /**
- * Creates a conference event.
- *
- * @param action - The action of the event.
- * @param attributes - The attributes to be added to the event.
- */
- export const createConferenceEvent = ( action: string, attributes: object ) => ( {
- action,
- attributes,
- source: 'conference',
- type: AnalyticsEvents.TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an operational event which indicates that a particular connection
- * stage was reached (i.e. the XMPP connection transitioned to the "connected"
- * state).
- *
- * @param stage the stage which was reached
- * @param attributes additional attributes for the event. This should be an
- * object with a "value" property indicating a timestamp in milliseconds
- * relative to the beginning of the document's lifetime.
- *
- */
- export const createConnectionStageReachedEvent = ( stage: unknown, attributes: object ) => ( {
- action: 'connection.stage.reached',
- actionSubject: stage,
- attributes,
- source: 'connection.stage.reached',
- type: AnalyticsEvents.TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an operational event for the end-to-end round trip time to a
- * specific remote participant.
- * @param participantId the ID of the remote participant.
- * @param region the region of the remote participant
- * @param rtt the rtt
- */
- export const createE2eRttEvent = ( participantId: unknown, region: unknown, rtt: unknown ) => ( {
- attributes: {
- 'participant_id': participantId,
- region,
- rtt
- },
- name: 'e2e_rtt',
- type: AnalyticsEvents.TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an event which indicates that the focus has left the MUC.
- */
- export const createFocusLeftEvent = () => ( {
- action: 'focus.left',
- actionSubject: 'focus.left',
- type: AnalyticsEvents.TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an event related to a getUserMedia call.
- *
- * @param action the type of the result that the event represents: 'error',
- * 'success', 'warning', etc.
- * @param attributes the attributes to attach to the event.
- */
- export const createGetUserMediaEvent = ( action: 'error' | 'success' | 'warning' | string, attributes: object = {} ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- source: 'get.user.media',
- action,
- attributes
- } );
-
- /**
- * Creates an event related to remote participant connection status changes.
- *
- * @param attributes the attributes to attach to the event.
- */
- export const createParticipantConnectionStatusEvent = ( attributes: object = {} ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- source: 'peer.conn.status',
- action: 'duration',
- attributes
- } );
-
- /**
- * Creates an event related to remote track streaming status changes.
- *
- * @param attributes the attributes to attach to the event.
- */
- export const createTrackStreamingStatusEvent = ( attributes: object = {} ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- source: 'track.streaming.status',
- action: 'duration',
- attributes
- } );
-
- /**
- * Creates an event for a Jingle-related event.
- * @param action the action of the event
- * @param attributes attributes to add to the event.
- */
- export const createJingleEvent = ( action: unknown, attributes: object = {} ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action,
- source: 'jingle',
- attributes
- } );
-
- /**
- * Creates an event which indicates that a local track was not able to read
- * data from its source (a camera or a microphone).
- *
- * @param mediaType the media type of the local track ('audio' or
- * 'video').
- */
- export const createNoDataFromSourceEvent = ( mediaType: 'audio' | 'video' | string, value: unknown ) => ( {
- attributes: {
- 'media_type': mediaType,
- value
- },
- action: 'track.no.data.from.source',
- type: AnalyticsEvents.TYPE_OPERATIONAL
- } );
-
- /**
- * Creates an event for a p2p-related event.
- * @param action the action of the event
- * @param attributes attributes to add to the event.
- */
- export const createP2PEvent = ( action: unknown, attributes: object = {} ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action,
- source: 'p2p',
- attributes
- } )
-
- /**
- * Indicates that we received a remote command to mute.
- */
- export const createRemotelyMutedEvent = ( mediaType: unknown ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'remotely.muted',
- mediaType
- } );
-
- /**
- * Creates an event which contains RTP statistics such as RTT and packet loss.
- *
- * All average RTP stats are currently reported under 1 event name, but with
- * different properties that allows to distinguish between a P2P call, a
- * call relayed through TURN or the JVB, and multiparty vs 1:1.
- *
- * The structure of the event is:
- *
- * {
- * p2p: true,
- * conferenceSize: 2,
- * localCandidateType: "relay",
- * remoteCandidateType: "relay",
- * transportType: "udp",
- *
- * // Average RTT of 200ms
- * "rtt.avg": 200,
- * "rtt.samples": "[100, 200, 300]",
- *
- * // Average packet loss of 10%
- * "packet.loss.avg": 10,
- * "packet.loss.samples": '[5, 10, 15]'
- *
- * // Difference in milliseconds in the end-to-end RTT between p2p and jvb.
- * // The e2e RTT through jvb is 15ms shorter:
- * "rtt.diff": 15,
- *
- * // End-to-end RTT through JVB is ms.
- * "end2end.rtt.avg" = 100
- * }
- *
- * Note that the value of the "samples" properties are (JSON encoded) strings,
- * and not JSON arrays, as events' attributes can not be nested. The samples are
- * currently included for debug purposes only and can be removed anytime soon
- * from the structure.
- *
- * Also note that not all of values are present in each event, as values are
- * obtained and calculated as part of different process/event pipe. For example
- * {@link ConnectionAvgStats} instances are doing the reports for each
- * {@link TraceablePeerConnection} and work independently from the main stats
- * pipe.
- */
- export const createRtpStatsEvent = ( attributes: object ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'rtp.stats',
- attributes
- } );
-
- /**
- * Creates an event which contains the round trip time (RTT) to a set of
- * regions.
- *
- * @param attributes
- */
- export const createRttByRegionEvent = ( attributes: object ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'rtt.by.region',
- attributes
- } );
-
- /**
- * Creates an event which contains the local and remote ICE candidate types
- * for the transport that is currently selected.
- *
- * @param attributes
- */
- export const createTransportStatsEvent = ( attributes: object ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'transport.stats',
- attributes
- } );
-
- /**
- * Creates an event which contains information about the audio output problem (the user id of the affected participant,
- * the local audio levels and the remote audio levels that triggered the event).
- *
- * @param userID - The user id of the affected participant.
- * @param localAudioLevels - The local audio levels.
- * @param remoteAudioLevels - The audio levels received from the participant.
- */
- export const createAudioOutputProblemEvent = ( userID: string, localAudioLevels: unknown, remoteAudioLevels: unknown ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'audio.output.problem',
- attributes: {
- userID,
- localAudioLevels,
- remoteAudioLevels
- }
- } );
-
- /**
- * Creates an event which contains an information related to the bridge channel close event.
- *
- * @param code - A code from {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
- * @param reason - A string which describes the reason for closing the bridge channel.
- */
- export const createBridgeChannelClosedEvent = ( code: string, reason: string ) => ( {
- type: AnalyticsEvents.TYPE_OPERATIONAL,
- action: 'bridge-channel.error',
- attributes: {
- code,
- reason
- }
- } );
-
- /**
- * Creates an event which indicates the Time To First Media (TTFM).
- * It is measured in milliseconds relative to the beginning of the document's
- * lifetime (i.e. the origin used by window.performance.now()), and it excludes
- * the following:
- * 1. The delay due to getUserMedia()
- * 2. The period between the MUC being joined and the reception of the Jingle
- * session-initiate from jicofo. This is because jicofo will not start a Jingle
- * session until there are at least 2 participants in the room.
- *
- * @param attributes the attributes to add to the event. Currently used fields:
- * mediaType: the media type of the local track ('audio' or 'video').
- * muted: whether the track has ever been muted (?)
- * value: the TTMF in milliseconds.
- */
- export const createTtfmEvent = ( attributes: object ) => createConnectionStageReachedEvent( 'ttfm', attributes );
|