Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add audible notifcation on broadcast error #10654

Merged
merged 10 commits into from
May 11, 2023
Binary file added res/media/error.mp3
Binary file not shown.
Binary file added res/media/error.ogg
Binary file not shown.
18 changes: 18 additions & 0 deletions src/voice-broadcast/models/VoiceBroadcastRecording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { ActionPayload } from "../../dispatcher/payloads";
import { VoiceBroadcastChunkEvents } from "../utils/VoiceBroadcastChunkEvents";
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
import { createReconnectedListener } from "../../utils/connection";
import { localNotificationsAreSilenced } from "../../utils/notifications";

export enum VoiceBroadcastRecordingEvent {
StateChanged = "liveness_changed",
Expand Down Expand Up @@ -333,10 +334,27 @@ export class VoiceBroadcastRecording
* It sets the connection error state and stops the recorder.
*/
private async onConnectionError(): Promise<void> {
this.playConnectionErrorAudioNotification().catch(() => {
// Error logged in playConnectionErrorAudioNotification().
});
await this.stopRecorder(false);
this.setState("connection_error");
}

private async playConnectionErrorAudioNotification(): Promise<void> {
if (localNotificationsAreSilenced(this.client)) {
return;
}

const audioElement = document.querySelector<HTMLAudioElement>("audio#errorAudio");
weeman1337 marked this conversation as resolved.
Show resolved Hide resolved

try {
await audioElement?.play();
} catch (e) {
logger.warn("error playing 'errorAudio'", e);
}
}

private async uploadFile(chunk: ChunkRecordedPayload): ReturnType<typeof uploadFile> {
return uploadFile(
this.client,
Expand Down
45 changes: 45 additions & 0 deletions test/voice-broadcast/models/VoiceBroadcastRecording-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
ClientEvent,
EventTimelineSet,
EventType,
LOCAL_NOTIFICATION_SETTINGS_PREFIX,
MatrixClient,
MatrixEvent,
MatrixEventEvent,
Expand Down Expand Up @@ -89,6 +90,7 @@ describe("VoiceBroadcastRecording", () => {
let voiceBroadcastRecording: VoiceBroadcastRecording;
let onStateChanged: (state: VoiceBroadcastRecordingState) => void;
let voiceBroadcastRecorder: VoiceBroadcastRecorder;
let audioElement: HTMLAudioElement;

const mkVoiceBroadcastInfoEvent = (content: VoiceBroadcastInfoEventContent) => {
return mkEvent({
Expand Down Expand Up @@ -251,6 +253,18 @@ describe("VoiceBroadcastRecording", () => {
};
},
);

audioElement = {
play: jest.fn(),
} as any as HTMLAudioElement;

jest.spyOn(document, "querySelector").mockImplementation((selector: string) => {
if (selector === "audio#errorAudio") {
return audioElement;
}

return null;
});
});

afterEach(() => {
Expand Down Expand Up @@ -501,6 +515,33 @@ describe("VoiceBroadcastRecording", () => {
});
});

describe("and audible notifications are disabled", () => {
beforeEach(() => {
const notificationSettings = mkEvent({
event: true,
type: `${LOCAL_NOTIFICATION_SETTINGS_PREFIX.name}.${client.getDeviceId()}`,
user: client.getSafeUserId(),
content: {
is_silenced: true,
},
});
mocked(client.getAccountData).mockReturnValue(notificationSettings);
});

describe("and a chunk has been recorded and sending the voice message fails", () => {
beforeEach(() => {
mocked(client.sendMessage).mockRejectedValue("Error");
emitFirsChunkRecorded();
});

itShouldBeInState("connection_error");

it("should not play a notification", () => {
expect(audioElement.play).not.toHaveBeenCalled();
});
});
});

describe("and a chunk has been recorded and sending the voice message fails", () => {
beforeEach(() => {
mocked(client.sendMessage).mockRejectedValue("Error");
Expand All @@ -509,6 +550,10 @@ describe("VoiceBroadcastRecording", () => {

itShouldBeInState("connection_error");

it("should play a notification", () => {
expect(audioElement.play).toHaveBeenCalled();
});

describe("and the connection is back", () => {
beforeEach(() => {
mocked(client.sendMessage).mockClear();
Expand Down
Loading