From 1bd7de5a183d4ec370025799dbef596e173782ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0imon=20Brandner?= Date: Sun, 29 Aug 2021 09:38:44 +0200 Subject: [PATCH] Use MediaHandler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Šimon Brandner --- src/client.ts | 9 ++++ src/matrix.ts | 2 - src/webrtc/call.ts | 132 ++++++++------------------------------------- 3 files changed, 30 insertions(+), 113 deletions(-) diff --git a/src/client.ts b/src/client.ts index 894c5a09d..baeb51735 100644 --- a/src/client.ts +++ b/src/client.ts @@ -144,6 +144,7 @@ import { IHierarchyRoom, ISpaceSummaryEvent, ISpaceSummaryRoom } from "./@types/ import { IPusher, IPusherRequest, IPushRules, PushRuleAction, PushRuleKind, RuleId } from "./@types/PushRules"; import { IThreepid } from "./@types/threepids"; import { CryptoStore } from "./crypto/store/base"; +import { MediaHandler } from "./webrtc/mediaHandler"; export type Store = IStore; export type SessionStore = WebStorageSessionStore; @@ -733,6 +734,7 @@ export class MatrixClient extends EventEmitter { protected checkTurnServersIntervalID: number; protected exportedOlmDeviceToImport: IOlmDevice; protected txnCtr = 0; + protected mediaHandler = new MediaHandler(); constructor(opts: IMatrixClientCreateOpts) { super(); @@ -1240,6 +1242,13 @@ export class MatrixClient extends EventEmitter { return this.canSupportVoip; } + /** + * @returns {MediaHandler} + */ + public getMediaHandler(): MediaHandler { + return this.mediaHandler; + } + /** * Set whether VoIP calls are forced to use only TURN * candidates. This is the same as the forceTURN option diff --git a/src/matrix.ts b/src/matrix.ts index 97709e314..bb6492412 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -49,8 +49,6 @@ export * from "./content-repo"; export * as ContentHelpers from "./content-helpers"; export { createNewMatrixCall, - setAudioInput as setMatrixCallAudioInput, - setVideoInput as setMatrixCallVideoInput, } from "./webrtc/call"; // expose the underlying request object so different environments can use diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index 1cd3d8243..f15300c87 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -212,11 +212,6 @@ export enum CallErrorCode { Transfered = 'transferred', } -enum ConstraintsType { - Audio = "audio", - Video = "video", -} - /** * The version field that we set in m.call.* events */ @@ -337,11 +332,7 @@ export class MatrixCall extends EventEmitter { * @throws If you have not specified a listener for 'error' events. */ public async placeVoiceCall(): Promise { - logger.debug("placeVoiceCall"); - this.checkForErrorListener(); - const constraints = getUserMediaContraints(ConstraintsType.Audio); - this.type = CallType.Voice; - await this.placeCallWithConstraints(constraints); + await this.placeCall(true, false); } /** @@ -349,11 +340,7 @@ export class MatrixCall extends EventEmitter { * @throws If you have not specified a listener for 'error' events. */ public async placeVideoCall(): Promise { - logger.debug("placeVideoCall"); - this.checkForErrorListener(); - const constraints = getUserMediaContraints(ConstraintsType.Video); - this.type = CallType.Video; - await this.placeCallWithConstraints(constraints); + await this.placeCall(true, true); } public getOpponentMember(): RoomMember { @@ -672,17 +659,14 @@ export class MatrixCall extends EventEmitter { logger.debug(`Answering call ${this.callId} of type ${this.type}`); if (!this.localUsermediaStream && !this.waitForLocalAVStream) { - const constraints = getUserMediaContraints( - this.type == CallType.Video ? - ConstraintsType.Video: - ConstraintsType.Audio, - ); - logger.log("Getting user media with constraints", constraints); this.setState(CallState.WaitLocalMedia); this.waitForLocalAVStream = true; try { - const mediaStream = await navigator.mediaDevices.getUserMedia(constraints); + const mediaStream = await this.client.getMediaHandler().getUserMediaStream( + true, + this.type === CallType.Video, + ); this.waitForLocalAVStream = false; this.gotUserMediaForAnswer(mediaStream); } catch (e) { @@ -797,7 +781,7 @@ export class MatrixCall extends EventEmitter { logger.debug(`Set screensharing enabled? ${enabled}`); if (enabled) { try { - const stream = await getScreensharingStream(desktopCapturerSourceId); + const stream = await this.client.getMediaHandler().getScreensharingStream(desktopCapturerSourceId); if (!stream) return false; this.pushLocalFeed(stream, SDPStreamMetadataPurpose.Screenshare); return true; @@ -832,7 +816,7 @@ export class MatrixCall extends EventEmitter { logger.debug(`Set screensharing enabled? ${enabled} using replaceTrack()`); if (enabled) { try { - const stream = await getScreensharingStream(desktopCapturerSourceId); + const stream = await this.client.getMediaHandler().getScreensharingStream(desktopCapturerSourceId); if (!stream) return false; const track = stream.getTracks().find((track) => { @@ -1809,8 +1793,18 @@ export class MatrixCall extends EventEmitter { } } - private async placeCallWithConstraints(constraints: MediaStreamConstraints): Promise { - logger.log("Getting user media with constraints", constraints); + /** + * Place a call to this room. + * @throws if you have not specified a listener for 'error' events. + * @throws if have passed audio=false. + */ + public async placeCall(audio: boolean, video: boolean): Promise { + logger.debug(`placeCall audio=${audio} video=${video}`); + if (!audio) { + throw new Error("You CANNOT start a call without audio"); + } + this.type = video ? CallType.Video : CallType.Voice; + this.checkForErrorListener(); // XXX Find a better way to do this this.client.callEventHandler.calls.set(this.callId, this); this.setState(CallState.WaitLocalMedia); @@ -1828,7 +1822,7 @@ export class MatrixCall extends EventEmitter { this.peerConn = this.createPeerConnection(); try { - const mediaStream = await navigator.mediaDevices.getUserMedia(constraints); + const mediaStream = await this.client.getMediaHandler().getUserMediaStream(audio, video); this.gotUserMediaForInvite(mediaStream); } catch (e) { this.getUserMediaFailed(e); @@ -1922,96 +1916,12 @@ export class MatrixCall extends EventEmitter { } } -async function getScreensharingStream(desktopCapturerSourceId: string): Promise { - const screenshareConstraints = getScreenshareContraints(desktopCapturerSourceId); - if (!screenshareConstraints) return null; - - if (desktopCapturerSourceId) { - // We are using Electron - logger.debug("Getting screen stream using getUserMedia()..."); - return await navigator.mediaDevices.getUserMedia(screenshareConstraints); - } else { - // We are not using Electron - logger.debug("Getting screen stream using getDisplayMedia()..."); - return await navigator.mediaDevices.getDisplayMedia(screenshareConstraints); - } -} - function setTracksEnabled(tracks: Array, enabled: boolean): void { for (let i = 0; i < tracks.length; i++) { tracks[i].enabled = enabled; } } -function getUserMediaContraints(type: ConstraintsType): MediaStreamConstraints { - const isWebkit = !!navigator.webkitGetUserMedia; - - switch (type) { - case ConstraintsType.Audio: { - return { - audio: { - deviceId: audioInput ? { ideal: audioInput } : undefined, - }, - video: false, - }; - } - case ConstraintsType.Video: { - return { - audio: { - deviceId: audioInput ? { ideal: audioInput } : undefined, - }, video: { - deviceId: videoInput ? { ideal: videoInput } : undefined, - /* We want 640x360. Chrome will give it only if we ask exactly, - FF refuses entirely if we ask exactly, so have to ask for ideal - instead - XXX: Is this still true? - */ - width: isWebkit ? { exact: 640 } : { ideal: 640 }, - height: isWebkit ? { exact: 360 } : { ideal: 360 }, - }, - }; - } - } -} - -function getScreenshareContraints(desktopCapturerSourceId?: string): DesktopCapturerConstraints { - if (desktopCapturerSourceId) { - logger.debug("Using desktop capturer source", desktopCapturerSourceId); - return { - audio: false, - video: { - mandatory: { - chromeMediaSource: "desktop", - chromeMediaSourceId: desktopCapturerSourceId, - }, - }, - }; - } else { - logger.debug("Not using desktop capturer source"); - return { - audio: false, - video: true, - }; - } -} - -let audioInput: string; -let videoInput: string; -/** - * Set an audio input device to use for MatrixCalls - * @function - * @param {string=} deviceId the identifier for the device - * undefined treated as unset - */ -export function setAudioInput(deviceId: string): void { audioInput = deviceId; } -/** - * Set a video input device to use for MatrixCalls - * @function - * @param {string=} deviceId the identifier for the device - * undefined treated as unset - */ -export function setVideoInput(deviceId: string): void { videoInput = deviceId; } - /** * DEPRECATED * Use client.createCall()