diff --git a/src/livekit/useLiveKit.ts b/src/livekit/useLiveKit.ts index d6d8394b..bf12669c 100644 --- a/src/livekit/useLiveKit.ts +++ b/src/livekit/useLiveKit.ts @@ -20,6 +20,7 @@ import { ExternalE2EEKeyProvider, Room, RoomOptions, + Track, } from "livekit-client"; import { useLiveKitRoom } from "@livekit/components-react"; import { useEffect, useMemo, useRef, useState } from "react"; @@ -158,12 +159,54 @@ export function useLiveKit( if (room !== undefined && connectionState === ConnectionState.Connected) { const syncDevice = (kind: MediaDeviceKind, device: MediaDevice) => { const id = device.selectedId; - if (id !== undefined && room.getActiveDevice(kind) !== id) { - room - .switchActiveDevice(kind, id) - .catch((e) => - logger.error(`Failed to sync ${kind} device with LiveKit`, e) - ); + + // Detect if we're trying to use chrome's default device, in which case + // we need to to see if the default device has changed to a different device + // by comparing the group ID of the device we're using against the group ID + // of what the default device is *now*. + // This is special-cased for only audio inputs because we need to dig around + // in the LocalParticipant object for the track object and there's not a nice + // way to do that generically. There is usually no OS-level default video capture + // device anyway, and audio outputs work differently. + if ( + id === "default" && + kind === "audioinput" && + room.options.audioCaptureDefaults?.deviceId === "default" + ) { + const activeMicTrack = Array.from( + room.localParticipant.audioTracks.values() + ).find((d) => d.source === Track.Source.Microphone)?.track; + + const defaultDevice = device.available.find( + (d) => d.deviceId === "default" + ); + if ( + defaultDevice && + activeMicTrack && + // only restart if the stream is still running: LiveKit will detect + // when a track stops & restart appropriately, so this is not our job. + // Plus, we need to avoid restarting again if the track is already in + // the process of being restarted. + activeMicTrack.mediaStreamTrack.readyState !== "ended" && + defaultDevice.groupId !== + activeMicTrack.mediaStreamTrack.getSettings().groupId + ) { + // It's different, so restart the track, ie. cause Livekit to do another + // getUserMedia() call with deviceId: default to get the *new* default device. + // Note that room.switchActiveDevice() won't work: Livekit will ignore it because + // the deviceId hasn't changed (was & still is default). + room.localParticipant + .getTrack(Track.Source.Microphone) + ?.audioTrack?.restartTrack(); + } + } else { + if (id !== undefined && room.getActiveDevice(kind) !== id) { + room + .switchActiveDevice(kind, id) + .catch((e) => + logger.error(`Failed to sync ${kind} device with LiveKit`, e) + ); + } } }; diff --git a/yarn.lock b/yarn.lock index 2df68cf6..57dfaf92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1951,16 +1951,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/sourcemap-codec@^1.4.13": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": version "0.3.19" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" @@ -2903,16 +2898,6 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@sentry-internal/tracing@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.69.0.tgz#8d8eb740b72967b6ba3fdc0a5173aa55331b7d35" - integrity sha512-4BgeWZUj9MO6IgfO93C9ocP3+AdngqujF/+zB2rFdUe+y9S6koDyUC7jr9Knds/0Ta72N/0D6PwhgSCpHK8s0Q== - dependencies: - "@sentry/core" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - tslib "^2.4.1 || ^1.9.3" - "@sentry-internal/tracing@7.73.0": version "7.73.0" resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.73.0.tgz#4838f31e41d23a6041ef4520519b80f788bf1cac" @@ -2935,12 +2920,12 @@ "@sentry/utils" "7.73.0" tslib "^2.4.1 || ^1.9.3" -"@sentry/bundler-plugin-core@2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.7.1.tgz#60ca41f79393263911ae6bc5530f387cb1e48e47" - integrity sha512-ZC/B/7FzzgGpux2t54B2ioXudlq60MHMVPaUeuFzWwxmxiArrV4uBXcp18RMW5ns4biik5WBAD72vbsoloBfIQ== +"@sentry/bundler-plugin-core@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.8.0.tgz#e01df24d7f909277f453844132b856ed997c182b" + integrity sha512-DsTUgeKPqck3DkGzKjRduhPpEn0pez+/THF3gpwQBEfbPnKGr0EYugDvfungZwBFenckIvQBDTOZw0STvbgChA== dependencies: - "@sentry/cli" "^2.20.1" + "@sentry/cli" "^2.21.2" "@sentry/node" "^7.60.0" "@sentry/utils" "^7.60.0" dotenv "^16.3.1" @@ -2949,10 +2934,10 @@ magic-string "0.27.0" unplugin "1.0.1" -"@sentry/cli@^2.20.1": - version "2.20.7" - resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.20.7.tgz#8f7f3f632c330cac6bd2278d820948163f3128a6" - integrity sha512-YaHKEUdsFt59nD8yLvuEGCOZ3/ArirL8GZ/66RkZ8wcD2wbpzOFbzo08Kz4te/Eo3OD5/RdW+1dPaOBgGbrXlA== +"@sentry/cli@^2.21.2": + version "2.21.2" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.21.2.tgz#89e5633ff48a83d078c76c6997fffd4b68b2da1c" + integrity sha512-X1nye89zl+QV3FSuQDGItfM51tW9PQ7ce0TtV/12DgGgTVEgnVp5uvO3wX5XauHvulQzRPzwUL3ZK+yS5bAwCw== dependencies: https-proxy-agent "^5.0.0" node-fetch "^2.6.7" @@ -2960,15 +2945,6 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d" - integrity sha512-V6jvK2lS8bhqZDMFUtvwe2XvNstFQf5A+2LMKCNBOV/NN6eSAAd6THwEpginabjet9dHsNRmMk7WNKvrUfQhZw== - dependencies: - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - tslib "^2.4.1 || ^1.9.3" - "@sentry/core@7.73.0": version "7.73.0" resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.73.0.tgz#1caeeec44f42c4d58c06cc05dec39e5497b65aa3" @@ -2979,15 +2955,15 @@ tslib "^2.4.1 || ^1.9.3" "@sentry/node@^7.60.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.69.0.tgz#938200095a17f41a2445fec168df293db7c24836" - integrity sha512-T0NgPcmDQvEuz5hy6aEhXghTHHTWsiP3IWoeEAakDBHAXmtpT6lYFQZgb5AiEOt9F5KO/G/1yH3YYdpDAnKhPw== + version "7.73.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.73.0.tgz#7eecf06689cd8f9d21587ca5cbfdc74543cc8c09" + integrity sha512-i50bRfmgkRRx0XXUbg9jGD/RuznDJxJXc4rBILhoJuhl+BjRIaoXA3ayplfJn8JLZxsNh75uJaCq4IUK70SORw== dependencies: - "@sentry-internal/tracing" "7.69.0" - "@sentry/core" "7.69.0" - "@sentry/types" "7.69.0" - "@sentry/utils" "7.69.0" - cookie "^0.4.1" + "@sentry-internal/tracing" "7.73.0" + "@sentry/core" "7.73.0" + "@sentry/types" "7.73.0" + "@sentry/utils" "7.73.0" + cookie "^0.5.0" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^2.4.1 || ^1.9.3" @@ -3019,25 +2995,12 @@ dependencies: "@sentry-internal/tracing" "7.73.0" -"@sentry/types@7.69.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292" - integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw== - "@sentry/types@7.73.0": version "7.73.0" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.73.0.tgz#6d811bbe413d319df0a592a672d6d72a94a8e716" integrity sha512-/v8++bly8jW7r4cP2wswYiiVpn7eLLcqwnfPUMeCQze4zj3F3nTRIKc9BGHzU0V+fhHa3RwRC2ksqTGq1oJMDg== -"@sentry/utils@7.69.0", "@sentry/utils@^7.60.0": - version "7.69.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.69.0.tgz#b7594e4eb2a88b9b25298770b841dd3f81bd2aa4" - integrity sha512-4eBixe5Y+0EGVU95R4NxH3jkkjtkE4/CmSZD4In8SCkWGSauogePtq6hyiLsZuP1QHdpPb9Kt0+zYiBb2LouBA== - dependencies: - "@sentry/types" "7.69.0" - tslib "^2.4.1 || ^1.9.3" - -"@sentry/utils@7.73.0": +"@sentry/utils@7.73.0", "@sentry/utils@^7.60.0": version "7.73.0" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.73.0.tgz#530cf023f7c395aa7708cd3824e5a45948449c10" integrity sha512-h3ZK/qpf4k76FhJV9uiSbvMz3V/0Ovy94C+5/9UgPMVCJXFmVsdw8n/dwANJ7LupVPfYP23xFGgebDMFlK1/2w== @@ -3046,11 +3009,11 @@ tslib "^2.4.1 || ^1.9.3" "@sentry/vite-plugin@^2.0.0": - version "2.7.1" - resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.7.1.tgz#23fa4c95079c3f2ba10b851dce7452c16adc82c8" - integrity sha512-bZrM06Z+QP/TvPyTYFxpQVugT5rzaFW1jzTnHzUHICz5tgyarY8bhhmYXnI37f6mngkVwDZNAftczbVF2IuFWQ== + version "2.8.0" + resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.8.0.tgz#d19d2ebf07fcbf09bb585033d803b9967717e5a6" + integrity sha512-17++vXjfn0xEfE7W4FWdwoXdNNqGjXnuTvIgSLlhJvDCTcqWONDpA/TGXGLjbhQEmQ58wL4wQqmlyxoqMPlokQ== dependencies: - "@sentry/bundler-plugin-core" "2.7.1" + "@sentry/bundler-plugin-core" "2.8.0" unplugin "1.0.1" "@sinclair/typebox@^0.27.8": @@ -4623,10 +4586,10 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== copy-to-clipboard@^3.3.1: version "3.3.3" @@ -7420,9 +7383,9 @@ minipass@^4.2.4: integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.3.tgz#05ea638da44e475037ed94d1c7efcc76a25e1974" - integrity sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg== + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== mkdirp@^1.0.4: version "1.0.4"