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:
Michael Telatynski 2024-07-08 13:44:54 +01:00 committed by GitHub
parent 466f37a83d
commit 8679ace2b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 20 additions and 14 deletions

View file

@ -457,6 +457,15 @@ export default class LegacyCallHandler extends EventEmitter {
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 {
// 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

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
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 { Button, Tooltip } from "@vector-im/compound-web";
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 { ActionPayload } from "../dispatcher/payloads";
import { Call } from "../models/Call";
import { AudioID } from "../LegacyCallHandler";
import LegacyCallHandler, { AudioID } from "../LegacyCallHandler";
import { useEventEmitter } from "../hooks/useEventEmitter";
import { CallStore, CallStoreEvent } from "../stores/CallStore";
@ -78,7 +78,6 @@ export function IncomingCallToast({ notifyEvent }: Props): JSX.Element {
const roomId = notifyEvent.getRoomId()!;
const room = MatrixClientPeg.safeGet().getRoom(roomId) ?? undefined;
const call = useCall(roomId);
const audio = useMemo(() => document.getElementById(AudioID.Ring) as HTMLMediaElement, []);
const [connectedCalls, setConnectedCalls] = useState<Call[]>(Array.from(CallStore.instance.connectedCalls));
useEventEmitter(CallStore.instance, CallStoreEvent.ConnectedCalls, () => {
setConnectedCalls(Array.from(CallStore.instance.connectedCalls));
@ -87,18 +86,18 @@ export function IncomingCallToast({ notifyEvent }: Props): JSX.Element {
// Start ringing if not already.
useEffect(() => {
const isRingToast = (notifyEvent.getContent() as unknown as { notify_type: string })["notify_type"] == "ring";
if (isRingToast && audio.paused) {
audio.play();
if (isRingToast && !LegacyCallHandler.instance.isPlaying(AudioID.Ring)) {
LegacyCallHandler.instance.play(AudioID.Ring);
}
}, [audio, notifyEvent]);
}, [notifyEvent]);
// Stop ringing on dismiss.
const dismissToast = useCallback((): void => {
ToastStore.sharedInstance().dismissToast(
getIncomingCallToastKey(notifyEvent.getContent().call_id ?? "", roomId),
);
audio.pause();
}, [audio, notifyEvent, roomId]);
LegacyCallHandler.instance.pause(AudioID.Ring);
}, [notifyEvent, roomId]);
// Dismiss if session got ended remotely.
const onCall = useCallback(

View file

@ -18,6 +18,7 @@ export const mocks = {
AudioBufferSourceNode: {
connect: jest.fn(),
start: jest.fn(),
stop: jest.fn(),
} as unknown as AudioBufferSourceNode,
AudioContext: {
close: jest.fn(),

View file

@ -39,11 +39,10 @@ import { WidgetMessagingStore } from "../../src/stores/widgets/WidgetMessagingSt
import DMRoomMap from "../../src/utils/DMRoomMap";
import ToastStore from "../../src/stores/ToastStore";
import { getIncomingCallToastKey, IncomingCallToast } from "../../src/toasts/IncomingCallToast";
import { AudioID } from "../../src/LegacyCallHandler";
import LegacyCallHandler, { AudioID } from "../../src/LegacyCallHandler";
describe("IncomingCallEvent", () => {
describe("IncomingCallToast", () => {
useMockedCalls();
jest.spyOn(HTMLMediaElement.prototype, "play").mockImplementation(async () => {});
let client: Mocked<MatrixClient>;
let room: Room;
@ -133,10 +132,8 @@ describe("IncomingCallEvent", () => {
...notifyContent,
notify_type: "ring",
}) 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} />);
expect(playMock).toHaveBeenCalled();
});