Fix incoming call toast crash due to audio refactor (#12737)
* Fix incoming call toast crash due to audio refactor Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Fix tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Iterate Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
466f37a83d
commit
8679ace2b2
4 changed files with 20 additions and 14 deletions
|
@ -457,6 +457,15 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
logger.debug(`${logPrefix} paused audio`);
|
logger.debug(`${logPrefix} paused audio`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given audio is currently playing
|
||||||
|
* Only supported for looping audio tracks
|
||||||
|
* @param audioId the ID of the audio to query for playing state
|
||||||
|
*/
|
||||||
|
public isPlaying(audioId: AudioID.Ring | AudioID.Ringback): boolean {
|
||||||
|
return !!this.playingSources[audioId];
|
||||||
|
}
|
||||||
|
|
||||||
private matchesCallForThisRoom(call: MatrixCall): boolean {
|
private matchesCallForThisRoom(call: MatrixCall): boolean {
|
||||||
// We don't allow placing more than one call per room, but that doesn't mean there
|
// We don't allow placing more than one call per room, but that doesn't mean there
|
||||||
// can't be more than one, eg. in a glare situation. This checks that the given call
|
// can't be more than one, eg. in a glare situation. This checks that the given call
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
import { Button, Tooltip } from "@vector-im/compound-web";
|
import { Button, Tooltip } from "@vector-im/compound-web";
|
||||||
import { Icon as VideoCallIcon } from "@vector-im/compound-design-tokens/icons/video-call-solid.svg";
|
import { Icon as VideoCallIcon } from "@vector-im/compound-design-tokens/icons/video-call-solid.svg";
|
||||||
|
@ -36,7 +36,7 @@ import AccessibleButton, { ButtonEvent } from "../components/views/elements/Acce
|
||||||
import { useDispatcher } from "../hooks/useDispatcher";
|
import { useDispatcher } from "../hooks/useDispatcher";
|
||||||
import { ActionPayload } from "../dispatcher/payloads";
|
import { ActionPayload } from "../dispatcher/payloads";
|
||||||
import { Call } from "../models/Call";
|
import { Call } from "../models/Call";
|
||||||
import { AudioID } from "../LegacyCallHandler";
|
import LegacyCallHandler, { AudioID } from "../LegacyCallHandler";
|
||||||
import { useEventEmitter } from "../hooks/useEventEmitter";
|
import { useEventEmitter } from "../hooks/useEventEmitter";
|
||||||
import { CallStore, CallStoreEvent } from "../stores/CallStore";
|
import { CallStore, CallStoreEvent } from "../stores/CallStore";
|
||||||
|
|
||||||
|
@ -78,7 +78,6 @@ export function IncomingCallToast({ notifyEvent }: Props): JSX.Element {
|
||||||
const roomId = notifyEvent.getRoomId()!;
|
const roomId = notifyEvent.getRoomId()!;
|
||||||
const room = MatrixClientPeg.safeGet().getRoom(roomId) ?? undefined;
|
const room = MatrixClientPeg.safeGet().getRoom(roomId) ?? undefined;
|
||||||
const call = useCall(roomId);
|
const call = useCall(roomId);
|
||||||
const audio = useMemo(() => document.getElementById(AudioID.Ring) as HTMLMediaElement, []);
|
|
||||||
const [connectedCalls, setConnectedCalls] = useState<Call[]>(Array.from(CallStore.instance.connectedCalls));
|
const [connectedCalls, setConnectedCalls] = useState<Call[]>(Array.from(CallStore.instance.connectedCalls));
|
||||||
useEventEmitter(CallStore.instance, CallStoreEvent.ConnectedCalls, () => {
|
useEventEmitter(CallStore.instance, CallStoreEvent.ConnectedCalls, () => {
|
||||||
setConnectedCalls(Array.from(CallStore.instance.connectedCalls));
|
setConnectedCalls(Array.from(CallStore.instance.connectedCalls));
|
||||||
|
@ -87,18 +86,18 @@ export function IncomingCallToast({ notifyEvent }: Props): JSX.Element {
|
||||||
// Start ringing if not already.
|
// Start ringing if not already.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isRingToast = (notifyEvent.getContent() as unknown as { notify_type: string })["notify_type"] == "ring";
|
const isRingToast = (notifyEvent.getContent() as unknown as { notify_type: string })["notify_type"] == "ring";
|
||||||
if (isRingToast && audio.paused) {
|
if (isRingToast && !LegacyCallHandler.instance.isPlaying(AudioID.Ring)) {
|
||||||
audio.play();
|
LegacyCallHandler.instance.play(AudioID.Ring);
|
||||||
}
|
}
|
||||||
}, [audio, notifyEvent]);
|
}, [notifyEvent]);
|
||||||
|
|
||||||
// Stop ringing on dismiss.
|
// Stop ringing on dismiss.
|
||||||
const dismissToast = useCallback((): void => {
|
const dismissToast = useCallback((): void => {
|
||||||
ToastStore.sharedInstance().dismissToast(
|
ToastStore.sharedInstance().dismissToast(
|
||||||
getIncomingCallToastKey(notifyEvent.getContent().call_id ?? "", roomId),
|
getIncomingCallToastKey(notifyEvent.getContent().call_id ?? "", roomId),
|
||||||
);
|
);
|
||||||
audio.pause();
|
LegacyCallHandler.instance.pause(AudioID.Ring);
|
||||||
}, [audio, notifyEvent, roomId]);
|
}, [notifyEvent, roomId]);
|
||||||
|
|
||||||
// Dismiss if session got ended remotely.
|
// Dismiss if session got ended remotely.
|
||||||
const onCall = useCallback(
|
const onCall = useCallback(
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const mocks = {
|
||||||
AudioBufferSourceNode: {
|
AudioBufferSourceNode: {
|
||||||
connect: jest.fn(),
|
connect: jest.fn(),
|
||||||
start: jest.fn(),
|
start: jest.fn(),
|
||||||
|
stop: jest.fn(),
|
||||||
} as unknown as AudioBufferSourceNode,
|
} as unknown as AudioBufferSourceNode,
|
||||||
AudioContext: {
|
AudioContext: {
|
||||||
close: jest.fn(),
|
close: jest.fn(),
|
||||||
|
|
|
@ -39,11 +39,10 @@ import { WidgetMessagingStore } from "../../src/stores/widgets/WidgetMessagingSt
|
||||||
import DMRoomMap from "../../src/utils/DMRoomMap";
|
import DMRoomMap from "../../src/utils/DMRoomMap";
|
||||||
import ToastStore from "../../src/stores/ToastStore";
|
import ToastStore from "../../src/stores/ToastStore";
|
||||||
import { getIncomingCallToastKey, IncomingCallToast } from "../../src/toasts/IncomingCallToast";
|
import { getIncomingCallToastKey, IncomingCallToast } from "../../src/toasts/IncomingCallToast";
|
||||||
import { AudioID } from "../../src/LegacyCallHandler";
|
import LegacyCallHandler, { AudioID } from "../../src/LegacyCallHandler";
|
||||||
|
|
||||||
describe("IncomingCallEvent", () => {
|
describe("IncomingCallToast", () => {
|
||||||
useMockedCalls();
|
useMockedCalls();
|
||||||
jest.spyOn(HTMLMediaElement.prototype, "play").mockImplementation(async () => {});
|
|
||||||
|
|
||||||
let client: Mocked<MatrixClient>;
|
let client: Mocked<MatrixClient>;
|
||||||
let room: Room;
|
let room: Room;
|
||||||
|
@ -133,10 +132,8 @@ describe("IncomingCallEvent", () => {
|
||||||
...notifyContent,
|
...notifyContent,
|
||||||
notify_type: "ring",
|
notify_type: "ring",
|
||||||
}) as any;
|
}) as any;
|
||||||
const playMock = jest.fn();
|
|
||||||
const audio = { play: playMock, paused: true };
|
|
||||||
|
|
||||||
jest.spyOn(document, "getElementById").mockReturnValue(audio as any);
|
const playMock = jest.spyOn(LegacyCallHandler.instance, "play");
|
||||||
render(<IncomingCallToast notifyEvent={call.event} />);
|
render(<IncomingCallToast notifyEvent={call.event} />);
|
||||||
expect(playMock).toHaveBeenCalled();
|
expect(playMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue