diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js index 8fe29a734e..9a2a52a657 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -35,6 +35,9 @@ var TransformOperation; TransformOperation["Encrypt"] = "encrypt"; TransformOperation["Decrypt"] = "decrypt"; })(TransformOperation || (TransformOperation = {})); +function localMedia(call) { + return call.localMediaSources.camera || call.localMediaSources.screen ? CallMediaType.Video : CallMediaType.Audio; +} let activeCall; let answerTimeout = 30000; var useWorker = false; @@ -143,7 +146,11 @@ const processCommand = (function () { const call = { connection: pc, iceCandidates, - localMedia: mediaType, + localMediaSources: { + mic: true, + camera: mediaType == CallMediaType.Video && !isDesktop, + screen: false, + }, localCamera, localStream, remoteStream, @@ -153,8 +160,6 @@ const processCommand = (function () { screen: false, }, aesKey, - screenShareEnabled: false, - cameraEnabled: !isDesktop, }; await setupMediaStreams(call); let connectionTimeout = setTimeout(connectionHandler, answerTimeout); @@ -339,7 +344,7 @@ const processCommand = (function () { if (!activeCall) { resp = { type: "error", message: "media: call not started" }; } - else if (activeCall.localMedia == CallMediaType.Audio && command.media == CallMediaType.Video && command.enable) { + else if (localMedia(activeCall) == CallMediaType.Audio && command.media == CallMediaType.Video && command.enable) { await startSendingVideo(activeCall, activeCall.localCamera); resp = { type: "ok" }; } @@ -566,8 +571,7 @@ const processCommand = (function () { //pc.addTrack(t, call.localStream) console.log("LALAL ADDED VIDEO TRACK " + t); } - call.localMedia = CallMediaType.Video; - call.cameraEnabled = true; + call.localMediaSources.camera = true; } catch (e) { return; @@ -590,15 +594,17 @@ const processCommand = (function () { const audioWasEnabled = oldAudioTracks.some((elem) => elem.enabled); let localStream; try { - localStream = call.screenShareEnabled ? await getLocalScreenCaptureStream() : await getLocalMediaStream(call.localMedia, camera); + localStream = call.localMediaSources.screen + ? await getLocalScreenCaptureStream() + : await getLocalMediaStream(localMedia(call), camera); } catch (e) { - if (call.screenShareEnabled) { - call.screenShareEnabled = false; + if (call.localMediaSources.screen) { + call.localMediaSources.screen = false; } return; } - if (!call.screenShareEnabled) { + if (!call.localMediaSources.screen) { for (const t of call.localStream.getTracks()) t.stop(); } @@ -620,7 +626,7 @@ const processCommand = (function () { if (!audioWasEnabled && oldAudioTracks.length > 0) { audioTracks.forEach((elem) => (elem.enabled = false)); } - if (!call.cameraEnabled && !call.screenShareEnabled) { + if (!call.localMediaSources.camera && !call.localMediaSources.screen) { videoTracks.forEach((elem) => (elem.enabled = false)); } replaceTracks(pc, audioTracks); @@ -793,14 +799,14 @@ const processCommand = (function () { for (const t of tracks) t.enabled = enable; if (media == CallMediaType.Video && activeCall) { - activeCall.cameraEnabled = enable; + activeCall.localMediaSources.camera = enable; } } toggleScreenShare = async function () { const call = activeCall; if (!call) return; - call.screenShareEnabled = !call.screenShareEnabled; + call.localMediaSources.screen = !call.localMediaSources.screen; await replaceMedia(call, call.localCamera); }; return processCommand; @@ -817,7 +823,7 @@ function toggleMedia(s, media) { res = t.enabled; } if (media == CallMediaType.Video && activeCall) { - activeCall.cameraEnabled = res; + activeCall.localMediaSources.camera = res; } return res; } diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/desktop/ui.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/desktop/ui.js index f448d99373..d5b1838172 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/desktop/ui.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/desktop/ui.js @@ -29,7 +29,7 @@ function endCallManually() { sendMessageToNative({ resp: { type: "end" } }); } function toggleAudioManually() { - if (activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMedia) { + if (activeCall && localMedia(activeCall)) { document.getElementById("toggle-audio").innerHTML = toggleMedia(activeCall.localStream, CallMediaType.Audio) ? '' : ''; @@ -43,27 +43,29 @@ function toggleSpeakerManually() { } } function toggleVideoManually() { - if (activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMedia) { - if (activeCall === null || activeCall === void 0 ? void 0 : activeCall.screenShareEnabled) { - activeCall.cameraEnabled = !activeCall.cameraEnabled; - enableVideoIcon(activeCall.cameraEnabled); + if (activeCall) { + if (activeCall.localMediaSources.screen) { + activeCall.localMediaSources.camera = !activeCall.localMediaSources.camera; + enableVideoIcon(activeCall.localMediaSources.camera); // } else if (activeCall.localMedia == CallMediaType.Video) { // enableVideoIcon(toggleMedia(activeCall.localStream, CallMediaType.Video)) } else { - const apiCall = { command: { type: "media", media: CallMediaType.Video, enable: activeCall.cameraEnabled != true } }; + const apiCall = { command: { type: "media", media: CallMediaType.Video, enable: activeCall.localMediaSources.camera != true } }; reactOnMessageFromServer(apiCall); processCommand(apiCall).then(() => { - enableVideoIcon((activeCall === null || activeCall === void 0 ? void 0 : activeCall.cameraEnabled) == true); + var _a; + enableVideoIcon(((_a = activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMediaSources) === null || _a === void 0 ? void 0 : _a.camera) == true); }); } } } async function toggleScreenManually() { - const was = activeCall === null || activeCall === void 0 ? void 0 : activeCall.screenShareEnabled; + var _a; + const was = activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMediaSources.screen; await toggleScreenShare(); - if (was != (activeCall === null || activeCall === void 0 ? void 0 : activeCall.screenShareEnabled)) { - document.getElementById("toggle-screen").innerHTML = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.screenShareEnabled) + if (was != (activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMediaSources.screen)) { + document.getElementById("toggle-screen").innerHTML = ((_a = activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMediaSources) === null || _a === void 0 ? void 0 : _a.screen) ? '' : ''; } @@ -108,9 +110,11 @@ function reactOnMessageFromServer(msg) { } function reactOnMessageToServer(msg) { var _a; + if (!activeCall) + return; switch ((_a = msg.resp) === null || _a === void 0 ? void 0 : _a.type) { case "peerMedia": - const className = (activeCall === null || activeCall === void 0 ? void 0 : activeCall.localMedia) == CallMediaType.Video || (activeCall === null || activeCall === void 0 ? void 0 : activeCall.peerMediaSources.camera) || (activeCall === null || activeCall === void 0 ? void 0 : activeCall.peerMediaSources.screen) + const className = localMedia(activeCall) == CallMediaType.Video || activeCall.peerMediaSources.camera || activeCall.peerMediaSources.screen ? "video" : "audio"; document.getElementById("info-block").className = className; diff --git a/packages/simplex-chat-webrtc/src/call.ts b/packages/simplex-chat-webrtc/src/call.ts index ad6bfbdd2e..5c899c92b0 100644 --- a/packages/simplex-chat-webrtc/src/call.ts +++ b/packages/simplex-chat-webrtc/src/call.ts @@ -234,18 +234,20 @@ interface WVAPICall { interface Call { connection: RTCPeerConnection iceCandidates: Promise // JSON strings for RTCIceCandidate - localMedia: CallMediaType + localMediaSources: CallMediaSources localCamera: VideoCamera localStream: MediaStream remoteStream: MediaStream peerMediaSources: CallMediaSources - screenShareEnabled: boolean - cameraEnabled: boolean aesKey?: string worker?: Worker key?: CryptoKey } +function localMedia(call: Call): CallMediaType { + return call.localMediaSources.camera || call.localMediaSources.screen ? CallMediaType.Video : CallMediaType.Audio +} + let activeCall: Call | undefined let answerTimeout = 30_000 var useWorker = false @@ -379,7 +381,11 @@ const processCommand = (function () { const call: Call = { connection: pc, iceCandidates, - localMedia: mediaType, + localMediaSources: { + mic: true, + camera: mediaType == CallMediaType.Video && !isDesktop, + screen: false, + }, localCamera, localStream, remoteStream, @@ -389,8 +395,6 @@ const processCommand = (function () { screen: false, }, aesKey, - screenShareEnabled: false, - cameraEnabled: !isDesktop, } await setupMediaStreams(call) let connectionTimeout: number | undefined = setTimeout(connectionHandler, answerTimeout) @@ -571,7 +575,7 @@ const processCommand = (function () { case "media": if (!activeCall) { resp = {type: "error", message: "media: call not started"} - } else if (activeCall.localMedia == CallMediaType.Audio && command.media == CallMediaType.Video && command.enable) { + } else if (localMedia(activeCall) == CallMediaType.Audio && command.media == CallMediaType.Video && command.enable) { await startSendingVideo(activeCall, activeCall.localCamera) resp = {type: "ok"} } else { @@ -813,8 +817,7 @@ const processCommand = (function () { //pc.addTrack(t, call.localStream) console.log("LALAL ADDED VIDEO TRACK " + t) } - call.localMedia = CallMediaType.Video - call.cameraEnabled = true + call.localMediaSources.camera = true } catch (e: any) { return } @@ -846,14 +849,16 @@ const processCommand = (function () { const audioWasEnabled = oldAudioTracks.some((elem) => elem.enabled) let localStream: MediaStream try { - localStream = call.screenShareEnabled ? await getLocalScreenCaptureStream() : await getLocalMediaStream(call.localMedia, camera) + localStream = call.localMediaSources.screen + ? await getLocalScreenCaptureStream() + : await getLocalMediaStream(localMedia(call), camera) } catch (e: any) { - if (call.screenShareEnabled) { - call.screenShareEnabled = false + if (call.localMediaSources.screen) { + call.localMediaSources.screen = false } return } - if (!call.screenShareEnabled) { + if (!call.localMediaSources.screen) { for (const t of call.localStream.getTracks()) t.stop() } else { // Don't stop audio track if switching to screenshare @@ -872,7 +877,7 @@ const processCommand = (function () { if (!audioWasEnabled && oldAudioTracks.length > 0) { audioTracks.forEach((elem) => (elem.enabled = false)) } - if (!call.cameraEnabled && !call.screenShareEnabled) { + if (!call.localMediaSources.camera && !call.localMediaSources.screen) { videoTracks.forEach((elem) => (elem.enabled = false)) } @@ -1063,14 +1068,14 @@ const processCommand = (function () { const tracks = media == CallMediaType.Video ? s.getVideoTracks() : s.getAudioTracks() for (const t of tracks) t.enabled = enable if (media == CallMediaType.Video && activeCall) { - activeCall.cameraEnabled = enable + activeCall.localMediaSources.camera = enable } } toggleScreenShare = async function () { const call = activeCall if (!call) return - call.screenShareEnabled = !call.screenShareEnabled + call.localMediaSources.screen = !call.localMediaSources.screen await replaceMedia(call, call.localCamera) } @@ -1090,7 +1095,7 @@ function toggleMedia(s: MediaStream, media: CallMediaType): boolean { res = t.enabled } if (media == CallMediaType.Video && activeCall) { - activeCall.cameraEnabled = res + activeCall.localMediaSources.camera = res } return res } diff --git a/packages/simplex-chat-webrtc/src/desktop/ui.ts b/packages/simplex-chat-webrtc/src/desktop/ui.ts index deb50ff808..9602a034c4 100644 --- a/packages/simplex-chat-webrtc/src/desktop/ui.ts +++ b/packages/simplex-chat-webrtc/src/desktop/ui.ts @@ -34,7 +34,7 @@ function endCallManually() { } function toggleAudioManually() { - if (activeCall?.localMedia) { + if (activeCall && localMedia(activeCall)) { document.getElementById("toggle-audio")!!.innerHTML = toggleMedia(activeCall.localStream, CallMediaType.Audio) ? '' : '' @@ -50,27 +50,27 @@ function toggleSpeakerManually() { } function toggleVideoManually() { - if (activeCall?.localMedia) { - if (activeCall?.screenShareEnabled) { - activeCall.cameraEnabled = !activeCall.cameraEnabled - enableVideoIcon(activeCall.cameraEnabled) + if (activeCall) { + if (activeCall.localMediaSources.screen) { + activeCall.localMediaSources.camera = !activeCall.localMediaSources.camera + enableVideoIcon(activeCall.localMediaSources.camera) // } else if (activeCall.localMedia == CallMediaType.Video) { // enableVideoIcon(toggleMedia(activeCall.localStream, CallMediaType.Video)) } else { - const apiCall: WVAPICall = {command: {type: "media", media: CallMediaType.Video, enable: activeCall.cameraEnabled != true}} + const apiCall: WVAPICall = {command: {type: "media", media: CallMediaType.Video, enable: activeCall.localMediaSources.camera != true}} reactOnMessageFromServer(apiCall as any) processCommand(apiCall).then(() => { - enableVideoIcon(activeCall?.cameraEnabled == true) + enableVideoIcon(activeCall?.localMediaSources?.camera == true) }) } } } async function toggleScreenManually() { - const was = activeCall?.screenShareEnabled + const was = activeCall?.localMediaSources.screen await toggleScreenShare() - if (was != activeCall?.screenShareEnabled) { - document.getElementById("toggle-screen")!!.innerHTML = activeCall?.screenShareEnabled + if (was != activeCall?.localMediaSources.screen) { + document.getElementById("toggle-screen")!!.innerHTML = activeCall?.localMediaSources?.screen ? '' : '' } @@ -117,10 +117,12 @@ function reactOnMessageFromServer(msg: WVApiMessage) { } function reactOnMessageToServer(msg: WVApiMessage) { + if (!activeCall) return + switch (msg.resp?.type) { case "peerMedia": const className = - activeCall?.localMedia == CallMediaType.Video || activeCall?.peerMediaSources.camera || activeCall?.peerMediaSources.screen + localMedia(activeCall) == CallMediaType.Video || activeCall.peerMediaSources.camera || activeCall.peerMediaSources.screen ? "video" : "audio" document.getElementById("info-block")!!.className = className