Show voice room participants when not connected (#8136)

* Add utility for getting connected voice participants

* Allow voice room members to send connected device state

* Update connected devices when connecting/disconnecting voice

* Show voice room participants in room tile when not connected

* Update voice room tests

* Add null types and guards
This commit is contained in:
Robin 2022-03-28 09:12:09 -04:00 committed by GitHub
parent 0a16989d26
commit 8baf06c3ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 378 additions and 143 deletions

View file

@ -15,11 +15,17 @@ limitations under the License.
*/
import { EventEmitter } from "events";
import { logger } from "matrix-js-sdk/src/logger";
import { ClientWidgetApi, IWidgetApiRequest } from "matrix-widget-api";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { ElementWidgetActions } from "./widgets/ElementWidgetActions";
import { WidgetMessagingStore } from "./widgets/WidgetMessagingStore";
import { getVoiceChannel } from "../utils/VoiceChannelUtils";
import {
VOICE_CHANNEL_MEMBER,
IVoiceChannelMemberContent,
getVoiceChannel,
} from "../utils/VoiceChannelUtils";
import { timeout } from "../utils/promise";
import WidgetUtils from "../utils/WidgetUtils";
@ -54,6 +60,7 @@ export default class VoiceChannelStore extends EventEmitter {
return VoiceChannelStore._instance;
}
private readonly cli = MatrixClientPeg.get();
private activeChannel: ClientWidgetApi;
private _roomId: string;
private _participants: IJitsiParticipant[];
@ -118,6 +125,9 @@ export default class VoiceChannelStore extends EventEmitter {
messaging.once(`action:${ElementWidgetActions.HangupCall}`, this.onHangup);
this.emit(VoiceChannelEvent.Connect);
// Tell others that we're connected, by adding our device to room state
await this.updateDevices(devices => Array.from(new Set(devices).add(this.cli.getDeviceId())));
};
public disconnect = async () => {
@ -169,8 +179,8 @@ export default class VoiceChannelStore extends EventEmitter {
private waitForAction = async (action: ElementWidgetActions) => {
const wait = new Promise<void>(resolve =>
this.activeChannel.once(`action:${action}`, (ev: CustomEvent<IWidgetApiRequest>) => {
resolve();
this.ack(ev);
resolve();
}),
);
if (await timeout(wait, false, VoiceChannelStore.TIMEOUT) === false) {
@ -182,22 +192,47 @@ export default class VoiceChannelStore extends EventEmitter {
this.activeChannel.transport.reply(ev.detail, {});
};
private onHangup = (ev: CustomEvent<IWidgetApiRequest>) => {
private updateDevices = async (fn: (devices: string[]) => string[]) => {
if (!this.roomId) {
logger.error("Tried to update devices while disconnected");
return;
}
const devices = this.cli.getRoom(this.roomId)
.currentState.getStateEvents(VOICE_CHANNEL_MEMBER, this.cli.getUserId())
?.getContent<IVoiceChannelMemberContent>()?.devices ?? [];
await this.cli.sendStateEvent(
this.roomId, VOICE_CHANNEL_MEMBER, { devices: fn(devices) }, this.cli.getUserId(),
);
};
private onHangup = async (ev: CustomEvent<IWidgetApiRequest>) => {
this.ack(ev);
this.activeChannel.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
this.activeChannel.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
this.activeChannel.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
this.activeChannel.off(`action:${ElementWidgetActions.MuteVideo}`, this.onMuteVideo);
this.activeChannel.off(`action:${ElementWidgetActions.UnmuteVideo}`, this.onUnmuteVideo);
this._roomId = null;
this.activeChannel = null;
this._participants = null;
this._audioMuted = null;
this._videoMuted = null;
this.emit(VoiceChannelEvent.Disconnect);
this.ack(ev);
// Save this for last, since ack needs activeChannel to exist
this.activeChannel = null;
try {
// Tell others that we're disconnected, by removing our device from room state
await this.updateDevices(devices => {
const devicesSet = new Set(devices);
devicesSet.delete(this.cli.getDeviceId());
return Array.from(devicesSet);
});
} finally {
// Save this for last, since updateDevices needs the room ID
this._roomId = null;
this.emit(VoiceChannelEvent.Disconnect);
}
};
private onParticipants = (ev: CustomEvent<IWidgetApiRequest>) => {