Skip to content

Commit

Permalink
Voice: Added Deafen
Browse files Browse the repository at this point in the history
  • Loading branch information
SupertigerDev committed Dec 19, 2024
1 parent f0c65ed commit 05f3a01
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 33 deletions.
59 changes: 58 additions & 1 deletion src/chat-api/store/useVoiceUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ type VoiceUsersMap = Record<string, ChannelUsersMap>;

// voiceUsers[channelId][userId] = VoiceUser
const [voiceUsers, setVoiceUsers] = createStore<VoiceUsersMap>({});
const [deafened, setDeafened] = createStore({
enabled: false,
wasMicEnabled: false,
});

interface CurrentVoiceUser {
channelId: string;
Expand All @@ -92,6 +96,34 @@ createEffect(
})
);

function toggleDeafen() {
const newDeafenEnabled = !deafened.enabled;
const currentUser = currentVoiceUser();
if (!currentUser) return;

const isMicEnabled = !!currentUser.audioStream;

const voiceUsers = getVoiceUsersByChannelId(currentUser.channelId);
voiceUsers.forEach((voiceUser) => {
if (voiceUser.audio) {
voiceUser.audio.muted = newDeafenEnabled;
}
});

if (!newDeafenEnabled && deafened.wasMicEnabled) {
enableMic();
}

if (newDeafenEnabled && isMicEnabled) {
disableMic();
}

batch(() => {
setDeafened("enabled", newDeafenEnabled);
setDeafened("wasMicEnabled", isMicEnabled);
});
}

const micTrack = createMemo(() => {
const current = currentVoiceUser();
return current?.audioStream?.getAudioTracks()[0];
Expand Down Expand Up @@ -141,6 +173,7 @@ const setCurrentChannelId = (channelId: string | null) => {
}
if (!channelId) {
setCurrentVoiceUser(undefined);
setDeafened("wasMicEnabled", false);
return;
}
setCurrentVoiceUser({
Expand Down Expand Up @@ -331,6 +364,7 @@ const createPeer = (voiceUser: VoiceUser, signal?: SimplePeer.SignalData) => {
if (!streams) return;

const audio = newVoiceUser.audio || new Audio();
audio.muted = deafened();
const deviceId = getStorageString(StorageKeys.outputDeviceId, undefined);
if (deviceId) {
audio.setSinkId(JSON.parse(deviceId));
Expand Down Expand Up @@ -441,7 +475,8 @@ const pushVoiceUserTrack = (
tracks: [track],
});
};
const toggleMic = async () => {

const disableMic = () => {
const userId = useAccount().user()?.id!;
const current = currentVoiceUser();
if (!current) return;
Expand All @@ -460,6 +495,15 @@ const toggleMic = async () => {

return;
}
};

const enableMic = async () => {
const current = currentVoiceUser();
if (!current) return;

if (current.audioStream) {
return;
}
const deviceId = getStorageString(StorageKeys.inputDeviceId, undefined);
const stream = await navigator.mediaDevices.getUserMedia({
audio: !deviceId ? true : { deviceId: JSON.parse(deviceId) },
Expand Down Expand Up @@ -497,6 +541,17 @@ const toggleMic = async () => {
});
};

const toggleMic = async () => {
const current = currentVoiceUser();
if (!current) return;

if (current.audioStream) {
disableMic();
return;
}
enableMic();
};

const setVideoStream = (stream: MediaStream | null) => {
const current = currentVoiceUser();
if (!current) return;
Expand Down Expand Up @@ -599,5 +654,7 @@ export default function useVoiceUsers() {
isLocalMicMuted: () => !currentVoiceUser()?.audioStream,

micEnabled,
toggleDeafen,
deafened,
};
}
96 changes: 66 additions & 30 deletions src/components/InVoiceActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { CustomLink } from "./ui/CustomLink";
import { timeElapsed } from "@/common/date";
import Button from "./ui/Button";

const InVoiceActionsContainer = styled(FlexRow)`
const InVoiceActionsContainer = styled(FlexColumn)`
background-color: rgb(15, 15, 15);
margin: 5px;
margin-bottom: 0;
border-radius: 8px;
height: 50px;
flex-shrink: 0;
align-items: center;
padding-top: 6px;
position: sticky;
bottom: 5px;
Expand All @@ -25,6 +24,7 @@ const InVoiceActionsContainer = styled(FlexRow)`
const DetailsContainer = styled(FlexColumn)`
overflow: hidden;
gap: 2px;
margin-right: 5px;
`;

export default function InVoiceActions(props: { style?: JSX.CSSProperties }) {
Expand All @@ -48,29 +48,31 @@ export default function InVoiceActions(props: { style?: JSX.CSSProperties }) {
return (
<Show when={channelId()}>
<InVoiceActionsContainer style={props?.style}>
<Icon
name="call"
color="var(--success-color)"
size={18}
style={{ padding: "10px", "padding-right": "5px" }}
/>
<DetailsContainer>
<Text size={12}>
Connected for <CallTime channelId={channelId()!} />
</Text>
<CustomLink
href={href()}
decoration
style={{
"font-size": "12px",
"white-space": "nowrap",
overflow: "hidden",
"text-overflow": "ellipsis",
}}
>
{name()}
</CustomLink>
</DetailsContainer>
<FlexRow>
<Icon
name="call"
color="var(--success-color)"
size={18}
style={{ padding: "10px", "padding-right": "5px" }}
/>
<DetailsContainer>
<Text size={12}>
Connected for <CallTime channelId={channelId()!} />
</Text>
<CustomLink
href={href()}
decoration
style={{
"font-size": "12px",
"white-space": "nowrap",
overflow: "hidden",
"text-overflow": "ellipsis",
}}
>
{name()}
</CustomLink>
</DetailsContainer>
</FlexRow>
<ActionButtons channelId={channelId()!} />
</InVoiceActionsContainer>
</Show>
Expand All @@ -79,15 +81,19 @@ export default function InVoiceActions(props: { style?: JSX.CSSProperties }) {

const ActionButtonsContainer = styled(FlexRow)`
gap: 5px;
margin-left: auto;
margin-right: 10px;
padding: 5px;
padding-top: 0;
button {
flex: 1;
}
`;

function ActionButtons(props: { channelId: string }) {
const { channels } = useStore();
const channel = () => channels.get(props.channelId);
return (
<ActionButtonsContainer>
<VoiceDeafenButton channelId={props.channelId} />
<VoiceMicButton channelId={props.channelId} />
<Button
margin={0}
Expand All @@ -102,11 +108,13 @@ function ActionButtons(props: { channelId: string }) {

function VoiceMicButton(props: { channelId: string }) {
const {
voiceUsers: { isLocalMicMuted, toggleMic },
voiceUsers: { isLocalMicMuted, toggleMic, deafened },
} = useStore();

const isDeafened = () => deafened.enabled;

return (
<>
<Show when={!isDeafened()}>
<Show when={isLocalMicMuted()}>
<Button
margin={0}
Expand All @@ -125,6 +133,34 @@ function VoiceMicButton(props: { channelId: string }) {
onClick={toggleMic}
/>
</Show>
</Show>
);
}
function VoiceDeafenButton(props: { channelId: string }) {
const { voiceUsers } = useStore();

const isDeafened = () => voiceUsers.deafened.enabled;

return (
<>
<Show when={isDeafened()}>
<Button
margin={0}
iconName="headset_off"
iconSize={16}
color="var(--alert-color)"
onClick={voiceUsers.toggleDeafen}
/>
</Show>
<Show when={!isDeafened()}>
<Button
margin={0}
iconName="headset_mic"
iconSize={16}
color="var(--primary-color)"
onClick={voiceUsers.toggleDeafen}
/>
</Show>
</>
);
}
Expand Down
30 changes: 28 additions & 2 deletions src/components/main-pane-header/MainPaneHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ function VoiceActions(props: { channelId: string }) {
color="var(--alert-color)"
/>
</Show>
<VoiceDeafenActions channelId={props.channelId} />
<VoiceMicActions channelId={props.channelId} />
<Button
iconName="call_end"
Expand All @@ -598,11 +599,11 @@ function VoiceActions(props: { channelId: string }) {

function VoiceMicActions(props: { channelId: string }) {
const {
voiceUsers: { isLocalMicMuted, toggleMic },
voiceUsers: { isLocalMicMuted, toggleMic, deafened },
} = useStore();

return (
<>
<Show when={!deafened.enabled}>
<Show when={isLocalMicMuted()}>
<Button
iconName="mic_off"
Expand All @@ -618,6 +619,31 @@ function VoiceMicActions(props: { channelId: string }) {
onClick={toggleMic}
/>
</Show>
</Show>
);
}
function VoiceDeafenActions(props: { channelId: string }) {
const { voiceUsers } = useStore();

const isDeafened = () => voiceUsers.deafened.enabled;

return (
<>
<Show when={isDeafened()}>
<Button
iconName="headset_off"
color="var(--alert-color)"
label="Deafened"
onClick={voiceUsers.toggleDeafen}
/>
</Show>
<Show when={!isDeafened()}>
<Button
iconName="headset_mic"
color="var(--primary-color)"
onClick={voiceUsers.toggleDeafen}
/>
</Show>
</>
);
}

0 comments on commit 05f3a01

Please sign in to comment.