@@ -20,7 +20,7 @@ import {
2020 useState
2121} from "@vencord/types/webpack/common" ;
2222import type { Dispatch , SetStateAction } from "react" ;
23- import { patchAudioWithDevice } from "renderer/patches/screenShareAudio " ;
23+ import { patchDisplayMedia } from "renderer/patches/screenSharePatch " ;
2424import { addPatch } from "renderer/patches/shared" ;
2525import { isLinux , isWindows } from "renderer/utils" ;
2626
@@ -43,6 +43,7 @@ interface StreamSettings {
4343
4444export interface StreamPick extends StreamSettings {
4545 id : string ;
46+ cameraId ?: string ;
4647}
4748
4849interface Source {
@@ -51,6 +52,11 @@ interface Source {
5152 url : string ;
5253}
5354
55+ interface Camera {
56+ id : string ;
57+ name : string ;
58+ }
59+
5460let currentSettings : StreamSettings | null = null ;
5561
5662addPatch ( {
@@ -100,6 +106,7 @@ if (isLinux) {
100106
101107export function openScreenSharePicker ( screens : Source [ ] , skipPicker : boolean ) {
102108 let didSubmit = false ;
109+
103110 return new Promise < StreamPick > ( ( resolve , reject ) => {
104111 const key = openModal (
105112 props => (
@@ -109,16 +116,24 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
109116 submit = { async v => {
110117 didSubmit = true ;
111118 if ( v . audioSource && v . audioSource !== "None" ) {
112- if ( v . audioSource === "Entire System" ) {
113- await VesktopNative . virtmic . startSystem ( v . workaround ) ;
114- } else {
115- await VesktopNative . virtmic . start ( [ v . audioSource ] , v . workaround ) ;
119+ patchDisplayMedia ( {
120+ audioId : v . audioDevice ,
121+ venmic : ! ! v . audioSource && v . audioSource !== "None" ,
122+ videoId : v . cameraId
123+ } ) ;
124+
125+ if ( ! v . audioDevice && v . audioSource && v . audioSource !== "None" ) {
126+ if ( v . audioSource === "Entire System" ) {
127+ await VesktopNative . virtmic . startSystem ( v . workaround ) ;
128+ } else {
129+ await VesktopNative . virtmic . start ( [ v . audioSource ] , v . workaround ) ;
130+ }
116131 }
117- }
118132
119- patchAudioWithDevice ( v . audioDevice ) ;
133+ patchAudioWithDevice ( v . audioDevice ) ;
120134
121- resolve ( v ) ;
135+ resolve ( v ) ;
136+ }
122137 } }
123138 close = { ( ) => {
124139 props . onClose ( ) ;
@@ -137,12 +152,26 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
137152 } ) ;
138153}
139154
140- function ScreenPicker ( { screens, chooseScreen } : { screens : Source [ ] ; chooseScreen : ( id : string ) => void } ) {
155+ function ScreenPicker ( {
156+ screens,
157+ chooseScreen,
158+ isDisabled = false
159+ } : {
160+ screens : Source [ ] ;
161+ chooseScreen : ( id : string ) => void ;
162+ isDisabled ?: boolean ;
163+ } ) {
141164 return (
142165 < div className = "vcd-screen-picker-grid" >
143166 { screens . map ( ( { id, name, url } ) => (
144167 < label key = { id } >
145- < input type = "radio" name = "screen" value = { id } onChange = { ( ) => chooseScreen ( id ) } />
168+ < input
169+ type = "radio"
170+ name = "screen"
171+ value = { id }
172+ onChange = { ( ) => chooseScreen ( id ) }
173+ disabled = { isDisabled }
174+ />
146175
147176 < img src = { url } alt = "" />
148177 < Text variant = "text-sm/normal" > { name } </ Text >
@@ -152,6 +181,37 @@ function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScre
152181 ) ;
153182}
154183
184+ function CameraPicker ( {
185+ camera,
186+ chooseCamera
187+ } : {
188+ camera : string | undefined ;
189+ chooseCamera : ( id : string | undefined ) => void ;
190+ } ) {
191+ const [ cameras ] = useAwaiter (
192+ ( ) =>
193+ navigator . mediaDevices
194+ . enumerateDevices ( )
195+ . then ( res =>
196+ res
197+ . filter ( d => d . kind === "videoinput" )
198+ . map ( d => ( { id : d . deviceId , name : d . label } ) satisfies Camera )
199+ ) ,
200+ { fallbackValue : [ ] }
201+ ) ;
202+
203+ return (
204+ < Select
205+ clearable = { true }
206+ options = { cameras . map ( s => ( { label : s . name , value : s . id } ) ) }
207+ isSelected = { s => s === camera }
208+ select = { s => chooseCamera ( s ) }
209+ clear = { ( ) => chooseCamera ( undefined ) }
210+ serialize = { String }
211+ />
212+ ) ;
213+ }
214+
155215function StreamSettings ( {
156216 source,
157217 settings,
@@ -174,6 +234,7 @@ function StreamSettings({
174234 return (
175235 < div >
176236 < Forms . FormTitle > What you're streaming</ Forms . FormTitle >
237+
177238 < Card className = "vcd-screen-picker-card vcd-screen-picker-preview" >
178239 < img src = { thumb } alt = "" />
179240 < Text variant = "text-sm/normal" > { source . name } </ Text >
@@ -256,7 +317,7 @@ function AudioSourceAnyDevice({
256317 audioDevice ?: string ;
257318 setAudioDevice ( s : string ) : void ;
258319} ) {
259- const [ sources , _ , loading ] = useAwaiter (
320+ const [ sources ] = useAwaiter (
260321 ( ) =>
261322 navigator . mediaDevices
262323 . enumerateDevices ( )
@@ -358,11 +419,8 @@ function ModalComponent({
358419 skipPicker : boolean ;
359420} ) {
360421 const [ selected , setSelected ] = useState < string | undefined > ( skipPicker ? screens [ 0 ] . id : void 0 ) ;
361- const [ settings , setSettings ] = useState < StreamSettings > ( {
362- resolution : "1080" ,
363- fps : "60" ,
364- audio : true
365- } ) ;
422+ const [ camera , setCamera ] = useState < string | undefined > ( undefined ) ;
423+ const [ settings , setSettings ] = useState < StreamSettings > ( { resolution : "1080" , fps : "60" , audio : true } ) ;
366424
367425 return (
368426 < Modals . ModalRoot { ...modalProps } >
@@ -373,7 +431,10 @@ function ModalComponent({
373431
374432 < Modals . ModalContent className = "vcd-screen-picker-modal" >
375433 { ! selected ? (
376- < ScreenPicker screens = { screens } chooseScreen = { setSelected } />
434+ < >
435+ < ScreenPicker screens = { screens } chooseScreen = { setSelected } isDisabled = { ! ! camera } />
436+ < CameraPicker camera = { camera } chooseCamera = { setCamera } />
437+ </ >
377438 ) : (
378439 < StreamSettings
379440 source = { screens . find ( s => s . id === selected ) ! }
@@ -386,7 +447,7 @@ function ModalComponent({
386447
387448 < Modals . ModalFooter className = "vcd-screen-picker-footer" >
388449 < Button
389- disabled = { ! selected }
450+ disabled = { ! selected && ! camera }
390451 onClick = { ( ) => {
391452 currentSettings = settings ;
392453
@@ -410,6 +471,7 @@ function ModalComponent({
410471
411472 submit ( {
412473 id : selected ! ,
474+ cameraId : camera ,
413475 ...settings
414476 } ) ;
415477
0 commit comments