Stop voice broadcast recording on redaction (#9455)
parent
d5a4718d46
commit
07a1e9a009
|
@ -20,7 +20,6 @@ import {
|
||||||
VoiceBroadcastInfoState,
|
VoiceBroadcastInfoState,
|
||||||
VoiceBroadcastRecording,
|
VoiceBroadcastRecording,
|
||||||
VoiceBroadcastRecordingEvent,
|
VoiceBroadcastRecordingEvent,
|
||||||
VoiceBroadcastRecordingsStore,
|
|
||||||
} from "..";
|
} from "..";
|
||||||
import QuestionDialog from "../../components/views/dialogs/QuestionDialog";
|
import QuestionDialog from "../../components/views/dialogs/QuestionDialog";
|
||||||
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
import { useTypedEventEmitter } from "../../hooks/useEventEmitter";
|
||||||
|
@ -54,7 +53,6 @@ export const useVoiceBroadcastRecording = (recording: VoiceBroadcastRecording) =
|
||||||
|
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
recording.stop();
|
recording.stop();
|
||||||
VoiceBroadcastRecordingsStore.instance().clearCurrent();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixClient, MatrixEvent, RelationType } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent, MatrixEventEvent, RelationType } from "matrix-js-sdk/src/matrix";
|
||||||
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -67,6 +67,7 @@ export class VoiceBroadcastRecording
|
||||||
}) ? VoiceBroadcastInfoState.Started : VoiceBroadcastInfoState.Stopped;
|
}) ? VoiceBroadcastInfoState.Started : VoiceBroadcastInfoState.Stopped;
|
||||||
// TODO Michael W: add listening for updates
|
// TODO Michael W: add listening for updates
|
||||||
|
|
||||||
|
this.infoEvent.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,10 +100,19 @@ export class VoiceBroadcastRecording
|
||||||
this.recorder.stop();
|
this.recorder.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.infoEvent.off(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
|
||||||
this.removeAllListeners();
|
this.removeAllListeners();
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onBeforeRedaction = () => {
|
||||||
|
if (this.getState() !== VoiceBroadcastInfoState.Stopped) {
|
||||||
|
this.setState(VoiceBroadcastInfoState.Stopped);
|
||||||
|
// destroy cleans up everything
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private onAction = (payload: ActionPayload) => {
|
private onAction = (payload: ActionPayload) => {
|
||||||
if (payload.action !== "call_state") return;
|
if (payload.action !== "call_state") return;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter";
|
||||||
|
|
||||||
import { VoiceBroadcastRecording } from "..";
|
import { VoiceBroadcastInfoState, VoiceBroadcastRecording, VoiceBroadcastRecordingEvent } from "..";
|
||||||
|
|
||||||
export enum VoiceBroadcastRecordingsStoreEvent {
|
export enum VoiceBroadcastRecordingsStoreEvent {
|
||||||
CurrentChanged = "current_changed",
|
CurrentChanged = "current_changed",
|
||||||
|
@ -41,7 +41,12 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
|
||||||
public setCurrent(current: VoiceBroadcastRecording): void {
|
public setCurrent(current: VoiceBroadcastRecording): void {
|
||||||
if (this.current === current) return;
|
if (this.current === current) return;
|
||||||
|
|
||||||
|
if (this.current) {
|
||||||
|
this.current.off(VoiceBroadcastRecordingEvent.StateChanged, this.onCurrentStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
this.current = current;
|
this.current = current;
|
||||||
|
this.current.on(VoiceBroadcastRecordingEvent.StateChanged, this.onCurrentStateChanged);
|
||||||
this.recordings.set(current.infoEvent.getId(), current);
|
this.recordings.set(current.infoEvent.getId(), current);
|
||||||
this.emit(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, current);
|
this.emit(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, current);
|
||||||
}
|
}
|
||||||
|
@ -51,8 +56,9 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearCurrent(): void {
|
public clearCurrent(): void {
|
||||||
if (this.current === null) return;
|
if (!this.current) return;
|
||||||
|
|
||||||
|
this.current.off(VoiceBroadcastRecordingEvent.StateChanged, this.onCurrentStateChanged);
|
||||||
this.current = null;
|
this.current = null;
|
||||||
this.emit(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, null);
|
this.emit(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, null);
|
||||||
}
|
}
|
||||||
|
@ -67,6 +73,12 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
|
||||||
return this.recordings.get(infoEventId);
|
return this.recordings.get(infoEventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onCurrentStateChanged = (state: VoiceBroadcastInfoState) => {
|
||||||
|
if (state === VoiceBroadcastInfoState.Stopped) {
|
||||||
|
this.clearCurrent();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private static readonly cachedInstance = new VoiceBroadcastRecordingsStore();
|
private static readonly cachedInstance = new VoiceBroadcastRecordingsStore();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
EventType,
|
EventType,
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
|
MatrixEventEvent,
|
||||||
MsgType,
|
MsgType,
|
||||||
RelationType,
|
RelationType,
|
||||||
Room,
|
Room,
|
||||||
|
@ -81,6 +82,7 @@ describe("VoiceBroadcastRecording", () => {
|
||||||
const setUpVoiceBroadcastRecording = () => {
|
const setUpVoiceBroadcastRecording = () => {
|
||||||
voiceBroadcastRecording = new VoiceBroadcastRecording(infoEvent, client);
|
voiceBroadcastRecording = new VoiceBroadcastRecording(infoEvent, client);
|
||||||
voiceBroadcastRecording.on(VoiceBroadcastRecordingEvent.StateChanged, onStateChanged);
|
voiceBroadcastRecording.on(VoiceBroadcastRecordingEvent.StateChanged, onStateChanged);
|
||||||
|
jest.spyOn(voiceBroadcastRecording, "destroy");
|
||||||
jest.spyOn(voiceBroadcastRecording, "removeAllListeners");
|
jest.spyOn(voiceBroadcastRecording, "removeAllListeners");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,6 +216,18 @@ describe("VoiceBroadcastRecording", () => {
|
||||||
expect(voiceBroadcastRecorder.start).toHaveBeenCalled();
|
expect(voiceBroadcastRecorder.start).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("and the info event is redacted", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
infoEvent.emit(MatrixEventEvent.BeforeRedaction, null, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
itShouldBeInState(VoiceBroadcastInfoState.Stopped);
|
||||||
|
|
||||||
|
it("should destroy the recording", () => {
|
||||||
|
expect(voiceBroadcastRecording.destroy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("and receiving a call action", () => {
|
describe("and receiving a call action", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
|
|
|
@ -18,28 +18,22 @@ import { mocked } from "jest-mock";
|
||||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
VoiceBroadcastInfoEventType,
|
|
||||||
VoiceBroadcastRecordingsStore,
|
VoiceBroadcastRecordingsStore,
|
||||||
VoiceBroadcastRecordingsStoreEvent,
|
VoiceBroadcastRecordingsStoreEvent,
|
||||||
VoiceBroadcastRecording,
|
VoiceBroadcastRecording,
|
||||||
|
VoiceBroadcastInfoState,
|
||||||
} from "../../../src/voice-broadcast";
|
} from "../../../src/voice-broadcast";
|
||||||
import { mkEvent, mkStubRoom, stubClient } from "../../test-utils";
|
import { mkStubRoom, stubClient } from "../../test-utils";
|
||||||
|
import { mkVoiceBroadcastInfoStateEvent } from "../utils/test-utils";
|
||||||
jest.mock("../../../src/voice-broadcast/models/VoiceBroadcastRecording.ts", () => ({
|
|
||||||
VoiceBroadcastRecording: jest.fn().mockImplementation(
|
|
||||||
(
|
|
||||||
infoEvent: MatrixEvent,
|
|
||||||
client: MatrixClient,
|
|
||||||
) => ({ infoEvent, client }),
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe("VoiceBroadcastRecordingsStore", () => {
|
describe("VoiceBroadcastRecordingsStore", () => {
|
||||||
const roomId = "!room:example.com";
|
const roomId = "!room:example.com";
|
||||||
let client: MatrixClient;
|
let client: MatrixClient;
|
||||||
let room: Room;
|
let room: Room;
|
||||||
let infoEvent: MatrixEvent;
|
let infoEvent: MatrixEvent;
|
||||||
|
let otherInfoEvent: MatrixEvent;
|
||||||
let recording: VoiceBroadcastRecording;
|
let recording: VoiceBroadcastRecording;
|
||||||
|
let otherRecording: VoiceBroadcastRecording;
|
||||||
let recordings: VoiceBroadcastRecordingsStore;
|
let recordings: VoiceBroadcastRecordingsStore;
|
||||||
let onCurrentChanged: (recording: VoiceBroadcastRecording) => void;
|
let onCurrentChanged: (recording: VoiceBroadcastRecording) => void;
|
||||||
|
|
||||||
|
@ -51,22 +45,17 @@ describe("VoiceBroadcastRecordingsStore", () => {
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
infoEvent = mkEvent({
|
infoEvent = mkVoiceBroadcastInfoStateEvent(roomId, VoiceBroadcastInfoState.Started, client.getUserId());
|
||||||
event: true,
|
otherInfoEvent = mkVoiceBroadcastInfoStateEvent(roomId, VoiceBroadcastInfoState.Started, client.getUserId());
|
||||||
type: VoiceBroadcastInfoEventType,
|
recording = new VoiceBroadcastRecording(infoEvent, client);
|
||||||
user: client.getUserId(),
|
otherRecording = new VoiceBroadcastRecording(otherInfoEvent, client);
|
||||||
room: roomId,
|
|
||||||
content: {},
|
|
||||||
});
|
|
||||||
recording = {
|
|
||||||
infoEvent,
|
|
||||||
} as unknown as VoiceBroadcastRecording;
|
|
||||||
recordings = new VoiceBroadcastRecordingsStore();
|
recordings = new VoiceBroadcastRecordingsStore();
|
||||||
onCurrentChanged = jest.fn();
|
onCurrentChanged = jest.fn();
|
||||||
recordings.on(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, onCurrentChanged);
|
recordings.on(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, onCurrentChanged);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
recording.destroy();
|
||||||
recordings.off(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, onCurrentChanged);
|
recordings.off(VoiceBroadcastRecordingsStoreEvent.CurrentChanged, onCurrentChanged);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -110,6 +99,32 @@ describe("VoiceBroadcastRecordingsStore", () => {
|
||||||
it("should emit a current changed event", () => {
|
it("should emit a current changed event", () => {
|
||||||
expect(onCurrentChanged).toHaveBeenCalledWith(null);
|
expect(onCurrentChanged).toHaveBeenCalledWith(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("and calling it again should work", () => {
|
||||||
|
recordings.clearCurrent();
|
||||||
|
expect(recordings.getCurrent()).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and setting another recording and stopping the previous recording", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
recordings.setCurrent(otherRecording);
|
||||||
|
recording.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should keep the current recording", () => {
|
||||||
|
expect(recordings.getCurrent()).toBe(otherRecording);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("and the recording stops", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
recording.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should clear the current recording", () => {
|
||||||
|
expect(recordings.getCurrent()).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -133,10 +148,7 @@ describe("VoiceBroadcastRecordingsStore", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the recording", () => {
|
it("should return the recording", () => {
|
||||||
expect(returnedRecording).toEqual({
|
expect(returnedRecording.infoEvent).toBe(infoEvent);
|
||||||
infoEvent,
|
|
||||||
client,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue