CallEventHandlerMap: {
    asserted_identity_changed: (call: MatrixCall) => void;
    datachannel: (channel: RTCDataChannel, call: MatrixCall) => void;
    error: (error: CallError, call: MatrixCall) => void;
    feeds_changed: (feeds: CallFeed[], call: MatrixCall) => void;
    hangup: (call: MatrixCall) => void;
    hold_unhold: (onHold: boolean) => void;
    length_changed: (length: number, call: MatrixCall) => void;
    local_hold_unhold: (onHold: boolean, call: MatrixCall) => void;
    peer_connection_created: (
        peerConn: RTCPeerConnection,
        call: MatrixCall,
    ) => void;
    remote_hold_unhold: (onHold: boolean, call: MatrixCall) => void;
    replaced: (newCall: MatrixCall, oldCall: MatrixCall) => void;
    send_voip_event: (event: VoipEvent, call: MatrixCall) => void;
    state: (state: CallState, oldState: CallState, call: MatrixCall) => void;
}

These now all have the call object as an argument. Why? Well, to know which call a given event is about you have three options:

  1. Use a closure as the callback that remembers what call it's listening to. This can be a pain because you need to pass the listener function again when you remove the listener, which might be somewhere else.
  2. Use not-very-well-known fact that EventEmitter sets 'this' to the emitter object in the callback. This doesn't really play well with modern Typescript and eslint and doesn't work with our pattern of re-emitting events.
  3. Pass the object in question as an argument to the callback.

Now that we have group calls which have to deal with multiple call objects, this will become more important, and I think methods 1 and 2 are just going to cause issues.