From 9af0fc744ff28c824f97229381c3fe5ca9d6ed43 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Mon, 4 Mar 2024 21:57:38 -0800 Subject: [PATCH] selecting webrtc device --- net/web/src/constants/Strings.js | 8 +++ net/web/src/context/useRingContext.hook.js | 24 +++++++ .../src/context/useSettingsContext.hook.js | 46 +++++++++++++ .../src/session/account/profile/Profile.jsx | 8 +-- .../session/account/profile/Profile.styled.js | 10 ++- .../profile/accountAccess/AccountAccess.jsx | 64 +++++++++++++------ .../accountAccess/AccountAccess.styled.js | 1 + .../accountAccess/useAccountAccess.hook.js | 27 +++++++- .../selectItem/SelectItem.styled.js | 2 +- todo | 8 +++ 10 files changed, 167 insertions(+), 31 deletions(-) diff --git a/net/web/src/constants/Strings.js b/net/web/src/constants/Strings.js index 4ce586e2..20eef60e 100644 --- a/net/web/src/constants/Strings.js +++ b/net/web/src/constants/Strings.js @@ -176,6 +176,10 @@ export const en = { editMembership: 'Edit Membership', deleteTopic: 'Delete Topic', leaveTopic: 'Leave Topic', + + integrated: 'Integrated', + microphone: 'Microphone', + camera: 'Camera' }; export const fr = { @@ -356,5 +360,9 @@ export const fr = { editMembership: 'Modifier Membres du Suject', deleteTopic: 'Supprimer le Sujet', leaveTopic: 'Quitter le Suject', + + integrated: 'Intégré', + microphone: 'Microphone', + camera: 'Caméra' }; diff --git a/net/web/src/context/useRingContext.hook.js b/net/web/src/context/useRingContext.hook.js index 74ec1290..bb3430e6 100644 --- a/net/web/src/context/useRingContext.hook.js +++ b/net/web/src/context/useRingContext.hook.js @@ -164,6 +164,9 @@ export function useRingContext() { }; try { + const devices = await navigator.mediaDevices.enumerateDevices(); + console.log('>> ', devices); + const stream = await navigator.mediaDevices.getUserMedia({ video: false, audio: true, @@ -417,6 +420,9 @@ export function useRingContext() { }, enableVideo: async () => { if (!accessVideo.current) { + const devices = await navigator.mediaDevices.enumerateDevices(); + console.log('>> ', devices); + const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true, @@ -457,6 +463,24 @@ export function useRingContext() { updateState({ localAudio: false }); } }, + getDevices: async (type) => { + const filtered = new Map(); + const devices = await navigator.mediaDevices.enumerateDevices(); + devices.filter(item => item.kind === type + 'input').forEach(item => { + if (item && item.label) { + const entry = filtered.get(item.groupId); + if (entry) { + if (item.label && item.label.length < entry.label.length) { + filtered.set(item.groupId, item); + } + } + else { + filtered.set(item.groupId, item); + } + } + }); + return Array.from(filtered.values()); + }, } return { state, actions } diff --git a/net/web/src/context/useSettingsContext.hook.js b/net/web/src/context/useSettingsContext.hook.js index 5e0b9f41..0ffa9521 100644 --- a/net/web/src/context/useSettingsContext.hook.js +++ b/net/web/src/context/useSettingsContext.hook.js @@ -18,6 +18,10 @@ export function useSettingsContext() { strings: en, dateFormat: 'mm/dd', timeFormat: '12h', + audioInput: null, + audioInputs: [], + videoInput: null, + videoInputs: [], }); const SMALL_MEDIUM = 650; @@ -43,6 +47,36 @@ export function useSettingsContext() { } }; + const getDevices = async (type) => { + const filtered = new Map(); + const devices = await navigator.mediaDevices.enumerateDevices(); + + devices.filter(item => item.kind === type + 'input').forEach(item => { + if (item) { + const label = item.label ? item.label : state.strings.integrated; + const entry = filtered.get(item.groupId); + if (entry) { + if (item.label && label.length < entry.label.length) { + filtered.set(item.groupId, { value: item.deviceId, label }); + } + } + else { + filtered.set(item.groupId, { value: item.deviceId, label }); + } + } + }); + return Array.from(filtered.values()); + } + + useEffect(() => { + getDevices('audio').then(audio => { + updateState({ audioInputs: audio }); + }); + getDevices('video').then(video => { + updateState({ videoInputs: video }); + }); + }, [state.strings]); + useEffect(() => { for (let i = 0; i < 10; i++) { setTimeout(handleResize, 100 * i); //cludge for my mobile browser @@ -100,6 +134,10 @@ export function useSettingsContext() { } } + const audioInput = localStorage.getItem('audio_input'); + const videoInput = localStorage.getItem('video_input'); + updateState({ audioInput, videoInput }); + return () => { window.removeEventListener('resize', handleResize); window.removeEventListener('orientationchange', handleResize); @@ -155,6 +193,14 @@ export function useSettingsContext() { localStorage.setItem('time_format', timeFormat); updateState({ timeFormat }); }, + setAudioInput: (audioInput) => { + localStorage.setItem('audio_input', audioInput); + updateState({ audioInput }); + }, + setVideoInput: (videoInput) => { + localStorage.setItem('video_input', videoInput); + updateState({ videoInput }); + }, } return { state, actions } diff --git a/net/web/src/session/account/profile/Profile.jsx b/net/web/src/session/account/profile/Profile.jsx index d4bcedfb..6343aae7 100644 --- a/net/web/src/session/account/profile/Profile.jsx +++ b/net/web/src/session/account/profile/Profile.jsx @@ -135,13 +135,13 @@ export function Profile({ closeProfile }) { { state.display !== 'xlarge' && state.displaySet && (
- { state.display === 'small' && ( -
- -
{ state.strings.logout }
+
+ +
{ state.strings.logout }
)} +
)} diff --git a/net/web/src/session/account/profile/Profile.styled.js b/net/web/src/session/account/profile/Profile.styled.js index b6452939..a48c2fcc 100644 --- a/net/web/src/session/account/profile/Profile.styled.js +++ b/net/web/src/session/account/profile/Profile.styled.js @@ -205,14 +205,18 @@ export const ProfileWrapper = styled.div` display: flex; flex-direction: row; align-items: center; - cursor: pointer; - color: ${props => props.theme.mainText}; - background-color: ${props => props.theme.modalArea}; + background-color: ${props => props.theme.selectedArea}; padding: 8px; border-radius: 4px; justify-content: center; + .icon { + color: ${props => props.theme.alertText}; + cursor: pointer; + } + .label { + cursor: pointer; padding-left: 8px; } } diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx index 426f168c..9ffa2a0d 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.jsx @@ -55,6 +55,29 @@ export function AccountAccess() { return ( { modalContext } +
+
{state.strings.account}
+
+
+
+ saveSearchable(enable)} /> +
+
{state.strings.registry}
+
+
+
+ +
+
{state.strings.sealedTopics}
+
+
+
+ +
+
{state.strings.changeLogin}
+
+
+
{state.strings.application}
@@ -94,28 +117,27 @@ export function AccountAccess() { options={state.languages} />
-
-
-
-
{state.strings.account}
-
-
-
- saveSearchable(enable)} /> -
-
{state.strings.registry}
+
+
{state.strings.microphone}
+
diff --git a/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js b/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js index 3720d0d7..5677ada2 100644 --- a/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js +++ b/net/web/src/session/account/profile/accountAccess/AccountAccess.styled.js @@ -35,6 +35,7 @@ export const AccountAccessWrapper = styled.div` display: flex; padding-top: 8px; align-items: center; + width: 100%; .label { padding-right: 16px; diff --git a/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js b/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js index f82fde6b..f18d8ea6 100644 --- a/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js +++ b/net/web/src/session/account/profile/accountAccess/useAccountAccess.hook.js @@ -2,6 +2,7 @@ import { useRef, useState, useEffect, useContext } from 'react'; import { AccountContext } from 'context/AccountContext'; import { ProfileContext } from 'context/ProfileContext'; import { SettingsContext } from 'context/SettingsContext'; +import { RingContext } from 'context/RingContext'; import { generateSeal, unlockSeal, updateSeal } from 'context/sealUtil'; import { getUsername } from 'api/getUsername'; export function useAccountAccess() { @@ -34,6 +35,10 @@ export function useAccountAccess() { themes: [], language: null, languages: [], + audioInput: null, + audioInputs: [], + videoInput: null, + videoInputs: [], seal: null, sealKey: null, @@ -42,6 +47,7 @@ export function useAccountAccess() { const profile = useContext(ProfileContext); const account = useContext(AccountContext); const settings = useContext(SettingsContext); + const ring = useContext(RingContext); const debounce = useRef(null); const updateState = (value) => { @@ -59,10 +65,21 @@ export function useAccountAccess() { }, [account.state]); useEffect(() => { - const { strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages } = settings.state; - updateState({ strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages }); + const { audioInput, audioInputs, videoInput, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages } = settings.state; + updateState({ audioInput, audioInputs, videoInput, videoInputs, strings, menuStyle, timeFormat, dateFormat, theme, themes, language, languages }); }, [settings.state]); + const showDevices = async () => { + const audio = await ring.actions.getDevices('audio'); + const video = await ring.actions.getDevices('video'); + + console.log('devices', audio, video); + }; + + useEffect(() => { + showDevices(); + }, []); + const sealUnlock = async () => { const unlocked = unlockSeal(state.seal, state.sealUnlock); await account.actions.unlockSeal(unlocked); @@ -113,6 +130,12 @@ export function useAccountAccess() { setLanguage: (language) => { settings.actions.setLanguage(language); }, + setAudio: (device) => { + settings.actions.setAudioInput(device); + }, + setVideo: (device) => { + settings.actions.setVideoInput(device); + }, setEditSeal: () => { let sealMode; let sealEnabled = isEnabled(); diff --git a/net/web/src/session/cardSelect/selectItem/SelectItem.styled.js b/net/web/src/session/cardSelect/selectItem/SelectItem.styled.js index 308ad22f..4cde7aaa 100644 --- a/net/web/src/session/cardSelect/selectItem/SelectItem.styled.js +++ b/net/web/src/session/cardSelect/selectItem/SelectItem.styled.js @@ -9,7 +9,7 @@ export const SelectItemWrapper = styled.div` height: 48px; width: 100%; padding-left: 8px; - padding-right: 8px; + padding-right: 16px; display: flex; align-items: center; diff --git a/todo b/todo index 1960b49d..a0d27aa0 100644 --- a/todo +++ b/todo @@ -5,3 +5,11 @@ calling: - fullscreen - device selection +add languages: +spanish +portugues +german +russian + +trim docker image +