mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 12:45:11 +08:00
Add audible notifcation on broadcast error (#10654)
* Add audible notifcation on broadcast error * Add error audio file * Add error ogg * Catch play broadcast error * Await play error sound * Add promise error handling * Add comment about audio elements
This commit is contained in:
parent
9aade5a4d5
commit
0a6fe83a8c
BIN
res/media/error.mp3
Normal file
BIN
res/media/error.mp3
Normal file
Binary file not shown.
BIN
res/media/error.ogg
Normal file
BIN
res/media/error.ogg
Normal file
Binary file not shown.
@ -46,6 +46,7 @@ import { ActionPayload } from "../../dispatcher/payloads";
|
|||||||
import { VoiceBroadcastChunkEvents } from "../utils/VoiceBroadcastChunkEvents";
|
import { VoiceBroadcastChunkEvents } from "../utils/VoiceBroadcastChunkEvents";
|
||||||
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
|
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
|
||||||
import { createReconnectedListener } from "../../utils/connection";
|
import { createReconnectedListener } from "../../utils/connection";
|
||||||
|
import { localNotificationsAreSilenced } from "../../utils/notifications";
|
||||||
|
|
||||||
export enum VoiceBroadcastRecordingEvent {
|
export enum VoiceBroadcastRecordingEvent {
|
||||||
StateChanged = "liveness_changed",
|
StateChanged = "liveness_changed",
|
||||||
@ -333,10 +334,29 @@ export class VoiceBroadcastRecording
|
|||||||
* It sets the connection error state and stops the recorder.
|
* It sets the connection error state and stops the recorder.
|
||||||
*/
|
*/
|
||||||
private async onConnectionError(): Promise<void> {
|
private async onConnectionError(): Promise<void> {
|
||||||
|
this.playConnectionErrorAudioNotification().catch(() => {
|
||||||
|
// Error logged in playConnectionErrorAudioNotification().
|
||||||
|
});
|
||||||
await this.stopRecorder(false);
|
await this.stopRecorder(false);
|
||||||
this.setState("connection_error");
|
this.setState("connection_error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async playConnectionErrorAudioNotification(): Promise<void> {
|
||||||
|
if (localNotificationsAreSilenced(this.client)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio files are added to the document in Element Web.
|
||||||
|
// See <audio> elements in https://github.com/vector-im/element-web/blob/develop/src/vector/index.html
|
||||||
|
const audioElement = document.querySelector<HTMLAudioElement>("audio#errorAudio");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await audioElement?.play();
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn("error playing 'errorAudio'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async uploadFile(chunk: ChunkRecordedPayload): ReturnType<typeof uploadFile> {
|
private async uploadFile(chunk: ChunkRecordedPayload): ReturnType<typeof uploadFile> {
|
||||||
return uploadFile(
|
return uploadFile(
|
||||||
this.client,
|
this.client,
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
ClientEvent,
|
ClientEvent,
|
||||||
EventTimelineSet,
|
EventTimelineSet,
|
||||||
EventType,
|
EventType,
|
||||||
|
LOCAL_NOTIFICATION_SETTINGS_PREFIX,
|
||||||
MatrixClient,
|
MatrixClient,
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
MatrixEventEvent,
|
MatrixEventEvent,
|
||||||
@ -89,6 +90,7 @@ describe("VoiceBroadcastRecording", () => {
|
|||||||
let voiceBroadcastRecording: VoiceBroadcastRecording;
|
let voiceBroadcastRecording: VoiceBroadcastRecording;
|
||||||
let onStateChanged: (state: VoiceBroadcastRecordingState) => void;
|
let onStateChanged: (state: VoiceBroadcastRecordingState) => void;
|
||||||
let voiceBroadcastRecorder: VoiceBroadcastRecorder;
|
let voiceBroadcastRecorder: VoiceBroadcastRecorder;
|
||||||
|
let audioElement: HTMLAudioElement;
|
||||||
|
|
||||||
const mkVoiceBroadcastInfoEvent = (content: VoiceBroadcastInfoEventContent) => {
|
const mkVoiceBroadcastInfoEvent = (content: VoiceBroadcastInfoEventContent) => {
|
||||||
return mkEvent({
|
return mkEvent({
|
||||||
@ -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(() => {
|
afterEach(() => {
|
||||||
@ -501,6 +515,19 @@ 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", () => {
|
describe("and a chunk has been recorded and sending the voice message fails", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(client.sendMessage).mockRejectedValue("Error");
|
mocked(client.sendMessage).mockRejectedValue("Error");
|
||||||
@ -509,6 +536,24 @@ describe("VoiceBroadcastRecording", () => {
|
|||||||
|
|
||||||
itShouldBeInState("connection_error");
|
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");
|
||||||
|
emitFirsChunkRecorded();
|
||||||
|
});
|
||||||
|
|
||||||
|
itShouldBeInState("connection_error");
|
||||||
|
|
||||||
|
it("should play a notification", () => {
|
||||||
|
expect(audioElement.play).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
describe("and the connection is back", () => {
|
describe("and the connection is back", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(client.sendMessage).mockClear();
|
mocked(client.sendMessage).mockClear();
|
||||||
|
Loading…
Reference in New Issue
Block a user