Add new VideoConference module for muting mic/cam (#11798)
* add new VideoConference module for muting mic/cam Co-authored-by: PrzemyslawTusinski <61138537+PrzemyslawTusinski@users.noreply.github.com> Co-authored-by: Niels Laute <niels.laute@live.nl>
150
.github/actions/spell-check/expect.txt
vendored
@ -46,6 +46,7 @@ Aissue
|
||||
akamaihd
|
||||
ALarger
|
||||
alekhyareddy
|
||||
alignas
|
||||
ALIGNLEFT
|
||||
ALLAPPS
|
||||
Alloc
|
||||
@ -142,9 +143,11 @@ autoplay
|
||||
Autorun
|
||||
AUTOSIZECOLUMNS
|
||||
autoupdate
|
||||
awakeversion
|
||||
AValid
|
||||
avialable
|
||||
awakeversion
|
||||
AWAYMODE
|
||||
AYUV
|
||||
azurecr
|
||||
azurewebsites
|
||||
backend
|
||||
@ -185,6 +188,7 @@ bms
|
||||
BNumber
|
||||
Bokm
|
||||
BOKMAL
|
||||
boolalpha
|
||||
Bools
|
||||
bootstrapper
|
||||
Bopomofo
|
||||
@ -213,6 +217,7 @@ BValue
|
||||
bytearray
|
||||
callbackptr
|
||||
callhistory
|
||||
Camer
|
||||
Cangjie
|
||||
cangjieime
|
||||
CANRENAME
|
||||
@ -285,6 +290,7 @@ CMock
|
||||
CMONITORS
|
||||
cmyk
|
||||
cnt
|
||||
coc
|
||||
coclass
|
||||
codebase
|
||||
codecvt
|
||||
@ -293,9 +299,10 @@ codereview
|
||||
Codespaces
|
||||
COINIT
|
||||
colorconv
|
||||
colorfilter
|
||||
colorhistory
|
||||
colorhistorylimit
|
||||
colorfilter
|
||||
COLORKEY
|
||||
colorpicker
|
||||
COLORREF
|
||||
colorscheme
|
||||
@ -429,6 +436,7 @@ dcomp
|
||||
DComposition
|
||||
ddd
|
||||
ddee
|
||||
ddf
|
||||
Deact
|
||||
declspec
|
||||
decltype
|
||||
@ -472,11 +480,14 @@ devenum
|
||||
deviceencryption
|
||||
devicemanagenent
|
||||
DEVMON
|
||||
devpkey
|
||||
DEVSOURCE
|
||||
DFactory
|
||||
DHCP
|
||||
Dialpad
|
||||
diffing
|
||||
difftime
|
||||
DIIRFLAG
|
||||
dimm
|
||||
directaccess
|
||||
dirname
|
||||
@ -489,6 +500,7 @@ Displayandhidethedesktop
|
||||
DISPLAYCHANGE
|
||||
displayname
|
||||
divyan
|
||||
djsoref
|
||||
DLACTIVEXCTLS
|
||||
DLCONTROL
|
||||
dlg
|
||||
@ -501,9 +513,10 @@ dllexport
|
||||
dllhost
|
||||
dllmain
|
||||
DNLEN
|
||||
docsmsft
|
||||
Dns
|
||||
docsmsft
|
||||
doctype
|
||||
dogancelik
|
||||
domainlexicon
|
||||
DONTVALIDATEPATH
|
||||
dotnet
|
||||
@ -531,7 +544,11 @@ dupenv
|
||||
dutil
|
||||
DVASPECT
|
||||
DVASPECTINFO
|
||||
DVH
|
||||
DVHD
|
||||
DVR
|
||||
DVSD
|
||||
DVSL
|
||||
DVTARGETDEVICE
|
||||
DWindow
|
||||
DWINRT
|
||||
@ -550,6 +567,8 @@ dword
|
||||
dworigin
|
||||
dwrite
|
||||
dxgi
|
||||
dxgiformat
|
||||
dxguid
|
||||
dynamiclock
|
||||
EABF
|
||||
EAC
|
||||
@ -602,6 +621,7 @@ efa
|
||||
efgh
|
||||
EFile
|
||||
egistry
|
||||
elif
|
||||
elseif
|
||||
emailandaccounts
|
||||
Emoji
|
||||
@ -610,6 +630,7 @@ ENABLEDPOPUP
|
||||
endforeach
|
||||
endif
|
||||
endl
|
||||
endpointvolume
|
||||
endregion
|
||||
Enque
|
||||
ENTERSIZEMOVE
|
||||
@ -662,7 +683,7 @@ exlist
|
||||
EXPCMDFLAGS
|
||||
EXPCMDSTATE
|
||||
explr
|
||||
Expr
|
||||
expr
|
||||
exsb
|
||||
EXSEL
|
||||
exstyle
|
||||
@ -679,6 +700,7 @@ FANCYZONESDRAWLAYOUTTEST
|
||||
FANCYZONESEDITOR
|
||||
Farbraum
|
||||
FARPROC
|
||||
fdw
|
||||
feimage
|
||||
ffcd
|
||||
FFDDDDDD
|
||||
@ -690,13 +712,16 @@ FILEFLAGS
|
||||
FILEFLAGSMASK
|
||||
FILEOP
|
||||
FILEOS
|
||||
filepath
|
||||
FILESUBTYPE
|
||||
FILESYSPATH
|
||||
filesystem
|
||||
FILETIME
|
||||
FILETYPE
|
||||
FILEVERSION
|
||||
Filtergraph
|
||||
Filterkeyboard
|
||||
Filterx
|
||||
finalizer
|
||||
findfast
|
||||
findmydevice
|
||||
@ -705,6 +730,7 @@ FIXEDFILEINFO
|
||||
FLASHZONES
|
||||
FLASHZONESONQUICKSWITCH
|
||||
Fle
|
||||
flt
|
||||
fluentui
|
||||
flyout
|
||||
fmtlib
|
||||
@ -726,6 +752,7 @@ FTYPE
|
||||
FULLNAME
|
||||
fullscreen
|
||||
func
|
||||
Functiondiscoverykeys
|
||||
fwlink
|
||||
fwrite
|
||||
fxcop
|
||||
@ -736,6 +763,7 @@ Gamebar
|
||||
gamedvr
|
||||
gamemode
|
||||
GBs
|
||||
GCLP
|
||||
gcnew
|
||||
gdi
|
||||
gdiplus
|
||||
@ -778,8 +806,10 @@ Hashset
|
||||
hbitmap
|
||||
hbmp
|
||||
hbr
|
||||
HBRBACKGROUND
|
||||
HBRUSH
|
||||
hcblack
|
||||
HCERTSTORE
|
||||
hcwhite
|
||||
hdc
|
||||
HDF
|
||||
@ -791,6 +821,8 @@ hdrop
|
||||
HDS
|
||||
HEB
|
||||
helptext
|
||||
HEVC
|
||||
hfile
|
||||
HGLOBAL
|
||||
hhk
|
||||
HHmmss
|
||||
@ -865,11 +897,13 @@ IApp
|
||||
IApplication
|
||||
IAppx
|
||||
IAsync
|
||||
IAudio
|
||||
IAuto
|
||||
IBackground
|
||||
IBase
|
||||
IBeam
|
||||
IBind
|
||||
ICapture
|
||||
icase
|
||||
iccex
|
||||
ICEBLUE
|
||||
@ -922,9 +956,11 @@ IFancy
|
||||
ifdef
|
||||
IFeatures
|
||||
IFile
|
||||
IFilter
|
||||
ifndef
|
||||
IFolder
|
||||
ifstream
|
||||
IGraph
|
||||
iid
|
||||
IImage
|
||||
Iindex
|
||||
@ -944,8 +980,11 @@ imagingdevices
|
||||
IMain
|
||||
IMarkdown
|
||||
ime
|
||||
IMedia
|
||||
IMem
|
||||
imeutil
|
||||
img
|
||||
iminstall
|
||||
IMoniker
|
||||
IMonitor
|
||||
IMouse
|
||||
@ -1002,6 +1041,7 @@ IObject
|
||||
iobjectwithsitesetsite
|
||||
IOle
|
||||
iolewindowcontextsensitivehelp
|
||||
iomanip
|
||||
iostream
|
||||
IPackage
|
||||
IPath
|
||||
@ -1023,6 +1063,7 @@ IProperty
|
||||
IPublic
|
||||
IQuery
|
||||
IRead
|
||||
IReference
|
||||
IReflect
|
||||
IRegistered
|
||||
IRegistration
|
||||
@ -1055,6 +1096,7 @@ ith
|
||||
IThrottled
|
||||
IThumbnail
|
||||
ITrigger
|
||||
itsme
|
||||
IUI
|
||||
IUnknown
|
||||
IUri
|
||||
@ -1065,9 +1107,11 @@ IVector
|
||||
IView
|
||||
IVirtual
|
||||
IWeb
|
||||
IXml
|
||||
IWIC
|
||||
IWindows
|
||||
IXml
|
||||
ixx
|
||||
IYUV
|
||||
IZone
|
||||
IZoom
|
||||
JArray
|
||||
@ -1116,17 +1160,17 @@ Keytool
|
||||
keyup
|
||||
KILLFOCUS
|
||||
Knownfolders
|
||||
KSPROPERTY
|
||||
Kybd
|
||||
LAlt
|
||||
Lambson
|
||||
lamotile
|
||||
langword
|
||||
langword
|
||||
Lastdevice
|
||||
LASTEXITCODE
|
||||
Laute
|
||||
launchfaceenrollment
|
||||
launchfingerprintenrollment
|
||||
Laute
|
||||
laute
|
||||
laviusmotileng
|
||||
LAYOUTRTL
|
||||
@ -1140,9 +1184,11 @@ Lclean
|
||||
LCONTROL
|
||||
LCtrl
|
||||
Ldone
|
||||
ldx
|
||||
LEFTSCROLLBAR
|
||||
lego
|
||||
len
|
||||
LEQ
|
||||
LError
|
||||
Lessthan
|
||||
LEVELID
|
||||
@ -1166,6 +1212,7 @@ LINQTo
|
||||
Linux
|
||||
listbox
|
||||
listview
|
||||
lld
|
||||
llkhf
|
||||
Llvm
|
||||
lmcons
|
||||
@ -1246,6 +1293,7 @@ MAINICON
|
||||
Mainwindow
|
||||
majortype
|
||||
makeappx
|
||||
makecab
|
||||
MAKEINTRESOURCE
|
||||
MAKEINTRESOURCEW
|
||||
MAKELPARAM
|
||||
@ -1264,6 +1312,7 @@ MATCHMODE
|
||||
MAXIMIZEBOX
|
||||
MAXSHORTCUTSIZE
|
||||
maxversiontested
|
||||
MBs
|
||||
MBUTTON
|
||||
MBUTTONDBLCLK
|
||||
MBUTTONDOWN
|
||||
@ -1273,7 +1322,7 @@ MDICHILD
|
||||
MDL
|
||||
mdpreviewhandler
|
||||
MEDIASUBTYPE
|
||||
MEDIATYPE
|
||||
mediatype
|
||||
Melman
|
||||
memcpy
|
||||
memset
|
||||
@ -1285,8 +1334,17 @@ messageboxes
|
||||
METACHARSET
|
||||
metadata
|
||||
metafile
|
||||
mfapi
|
||||
mfc
|
||||
mfcribbon
|
||||
mfidl
|
||||
mfobjects
|
||||
mfplat
|
||||
mfreadwrite
|
||||
Mfsensorgroup
|
||||
mftransform
|
||||
mfuuid
|
||||
mic
|
||||
microsoft
|
||||
Midl
|
||||
mii
|
||||
@ -1299,10 +1357,12 @@ miniz
|
||||
minlevel
|
||||
MINMAXINFO
|
||||
Miracast
|
||||
mirophone
|
||||
MJPG
|
||||
mkdir
|
||||
Mlcfg
|
||||
MLogo
|
||||
mmdeviceapi
|
||||
MMI
|
||||
Mmsys
|
||||
mobilehotspot
|
||||
@ -1369,6 +1429,7 @@ mutex
|
||||
mutexes
|
||||
muxc
|
||||
mvvm
|
||||
myfile
|
||||
MYICON
|
||||
NAMECHANGE
|
||||
nameof
|
||||
@ -1412,6 +1473,7 @@ netsh
|
||||
netstandard
|
||||
Neue
|
||||
newcolor
|
||||
newdev
|
||||
newitem
|
||||
newpath
|
||||
newrow
|
||||
@ -1421,6 +1483,7 @@ niels
|
||||
nielslaute
|
||||
NIF
|
||||
nightlight
|
||||
nitroin
|
||||
NLD
|
||||
nlog
|
||||
NLSTEXT
|
||||
@ -1438,6 +1501,7 @@ nodoc
|
||||
noexcept
|
||||
NOFRAMES
|
||||
NOINHERITLAYOUT
|
||||
NOINTERFACE
|
||||
NOLINKINFO
|
||||
NOMINMAX
|
||||
NOMOVE
|
||||
@ -1521,6 +1585,7 @@ OPTIMIZEFORINVOKE
|
||||
optin
|
||||
optionalfeatures
|
||||
OPTIONSGROUP
|
||||
ORAW
|
||||
ORPHANEDDIALOGTITLE
|
||||
oss
|
||||
ostr
|
||||
@ -1532,6 +1597,7 @@ otheroptions
|
||||
otherusers
|
||||
OUTOFCONTEXT
|
||||
OUTOFMEMORY
|
||||
outpin
|
||||
Outptr
|
||||
outputtype
|
||||
outro
|
||||
@ -1553,6 +1619,7 @@ PARENTRELATIVEPARSING
|
||||
parray
|
||||
PARTIALCONFIRMATIONDIALOGTITLE
|
||||
pathcch
|
||||
PAUDIO
|
||||
pbc
|
||||
Pbgra
|
||||
pcb
|
||||
@ -1593,6 +1660,7 @@ Pipelinhttps
|
||||
pipename
|
||||
pitem
|
||||
PKBDLLHOOKSTRUCT
|
||||
PKEY
|
||||
placeholders
|
||||
plib
|
||||
PLK
|
||||
@ -1611,6 +1679,7 @@ popd
|
||||
popup
|
||||
POPUPWINDOW
|
||||
posix
|
||||
Postion
|
||||
powerappscds
|
||||
powercfg
|
||||
powerlauncher
|
||||
@ -1626,6 +1695,7 @@ powertoyswiki
|
||||
Powrprof
|
||||
ppenum
|
||||
ppidl
|
||||
ppmt
|
||||
pprm
|
||||
pproc
|
||||
ppsi
|
||||
@ -1643,11 +1713,13 @@ Prefixer
|
||||
Preinstalled
|
||||
preload
|
||||
PREMULTIPLIED
|
||||
preperty
|
||||
prevhost
|
||||
previewer
|
||||
PREVIEWGROUP
|
||||
PREVIEWHANDLERFRAMEINFO
|
||||
previewpane
|
||||
previouscamera
|
||||
PREVIOUSVERSIONSINSTALLED
|
||||
prevpane
|
||||
prgms
|
||||
@ -1664,6 +1736,7 @@ PROGRAMFILES
|
||||
progressbar
|
||||
Proj
|
||||
projectname
|
||||
PROPBAG
|
||||
propkey
|
||||
propvarutil
|
||||
prpui
|
||||
@ -1676,6 +1749,7 @@ psfgao
|
||||
Psr
|
||||
psrm
|
||||
psrree
|
||||
pstr
|
||||
pstream
|
||||
pstrm
|
||||
psz
|
||||
@ -1693,6 +1767,7 @@ PVOID
|
||||
pwa
|
||||
pwcs
|
||||
PWSTR
|
||||
pwsz
|
||||
pwtd
|
||||
qianlifeng
|
||||
qit
|
||||
@ -1738,20 +1813,27 @@ rectp
|
||||
rects
|
||||
recyclebin
|
||||
redirectedfrom
|
||||
reencode
|
||||
reencoded
|
||||
refactor
|
||||
refactoring
|
||||
REFCLSID
|
||||
refcount
|
||||
REFGUID
|
||||
REFIID
|
||||
REGCLS
|
||||
regedit
|
||||
regex
|
||||
REGFILTER
|
||||
REGFILTERPINS
|
||||
regionformatting
|
||||
regionlanguage
|
||||
REGISTERCLASSFAILED
|
||||
Registery
|
||||
registrypath
|
||||
regkey
|
||||
REGPINTYPES
|
||||
regsvr
|
||||
reimplementing
|
||||
reloadable
|
||||
Remapper
|
||||
@ -1803,13 +1885,14 @@ RKey
|
||||
RMENU
|
||||
RNumber
|
||||
roadmap
|
||||
robocopy
|
||||
Roboto
|
||||
roslyn
|
||||
royvou
|
||||
Rpc
|
||||
RRF
|
||||
rshift
|
||||
RSHIFT
|
||||
rshift
|
||||
Rsp
|
||||
rst
|
||||
Rstrtmgr
|
||||
@ -1859,6 +1942,7 @@ SEARCHFOR
|
||||
SEARCHREPLACEGROUP
|
||||
searchterm
|
||||
Secur
|
||||
seekg
|
||||
Segoe
|
||||
Sekan
|
||||
SENDCHANGE
|
||||
@ -1904,8 +1988,8 @@ Shl
|
||||
shldisp
|
||||
shlobj
|
||||
shlwapi
|
||||
shmem
|
||||
shobjidl
|
||||
shortsplit
|
||||
SHORTCUTATLEAST
|
||||
shortcutcontrol
|
||||
Shortcutguide
|
||||
@ -1917,6 +2001,7 @@ SHORTCUTSTARTWITHMODIFIER
|
||||
Shortcuttool
|
||||
shortdate
|
||||
SHORTPATH
|
||||
shortsplit
|
||||
showcolorname
|
||||
SHOWDEFAULT
|
||||
SHOWELEVATIONPROMPT
|
||||
@ -1945,6 +2030,7 @@ SIZENESW
|
||||
SIZENS
|
||||
SIZENWSE
|
||||
sizeof
|
||||
sizeread
|
||||
SIZEWE
|
||||
sketchapp
|
||||
SKIPOWNPROCESS
|
||||
@ -1974,6 +2060,7 @@ spesi
|
||||
splitwstring
|
||||
sppd
|
||||
sppre
|
||||
sprintf
|
||||
spsi
|
||||
spsia
|
||||
spsrif
|
||||
@ -2031,6 +2118,7 @@ storagesense
|
||||
stoul
|
||||
stoull
|
||||
strcmp
|
||||
streampos
|
||||
strftime
|
||||
Stringified
|
||||
Stringify
|
||||
@ -2057,8 +2145,8 @@ surfacehub
|
||||
sut
|
||||
SVE
|
||||
svg
|
||||
SVGIO
|
||||
SVGIn
|
||||
SVGIO
|
||||
svgpreviewhandler
|
||||
SWC
|
||||
SWFO
|
||||
@ -2068,6 +2156,7 @@ swprintf
|
||||
SWRESTORE
|
||||
SYMED
|
||||
SYMOPT
|
||||
SYNCMFT
|
||||
SYNCPAINT
|
||||
sys
|
||||
SYSCHAR
|
||||
@ -2083,9 +2172,9 @@ syslog
|
||||
SYSMENU
|
||||
systemd
|
||||
SYSTEMTIME
|
||||
Tadele
|
||||
sz
|
||||
tabletmode
|
||||
Tadele
|
||||
tadele
|
||||
Tahoma
|
||||
talenthrcore
|
||||
@ -2111,6 +2200,7 @@ tchar
|
||||
tcscpy
|
||||
TCustom
|
||||
TDevice
|
||||
tellg
|
||||
Templated
|
||||
templatenamespace
|
||||
Temporarilypeekatthedesktop
|
||||
@ -2132,8 +2222,8 @@ THISCOMPONENT
|
||||
thre
|
||||
tif
|
||||
TILEDWINDOW
|
||||
timediff
|
||||
timedate
|
||||
timediff
|
||||
Timeline
|
||||
TIMERID
|
||||
timeunion
|
||||
@ -2143,6 +2233,7 @@ TLayout
|
||||
tlb
|
||||
tlbimp
|
||||
tmp
|
||||
TMPVAR
|
||||
TNP
|
||||
todo
|
||||
toggleswitch
|
||||
@ -2161,12 +2252,15 @@ towlower
|
||||
towupper
|
||||
tracelogging
|
||||
traies
|
||||
transcoded
|
||||
transparrent
|
||||
TRAYMOUSEMESSAGE
|
||||
TRK
|
||||
trl
|
||||
trueplay
|
||||
truetype
|
||||
trunc
|
||||
tspan
|
||||
TStr
|
||||
tsx
|
||||
TYMED
|
||||
@ -2192,8 +2286,10 @@ UIPI
|
||||
UIs
|
||||
UITo
|
||||
ULARGE
|
||||
ulazy
|
||||
ULLONG
|
||||
ulong
|
||||
ULONGLONG
|
||||
umd
|
||||
unchecks
|
||||
uncomment
|
||||
@ -2222,6 +2318,7 @@ unknwn
|
||||
UNLEN
|
||||
unlicense
|
||||
Unmap
|
||||
unmute
|
||||
UNORM
|
||||
unregister
|
||||
unregistering
|
||||
@ -2256,16 +2353,20 @@ uuidof
|
||||
uwp
|
||||
UWPUI
|
||||
uxtheme
|
||||
UYVY
|
||||
validmodulename
|
||||
vcamp
|
||||
vccorlib
|
||||
vcdl
|
||||
VCINSTALLDIR
|
||||
vcm
|
||||
vcomp
|
||||
vcredist
|
||||
VCRT
|
||||
vcruntime
|
||||
vcvars
|
||||
vcxproj
|
||||
vdi
|
||||
VDId
|
||||
vec
|
||||
VERBSONLY
|
||||
@ -2275,10 +2376,14 @@ VERSIONINFO
|
||||
Versioning
|
||||
VFT
|
||||
vid
|
||||
VIDCAP
|
||||
videoconference
|
||||
videoconferencevirtualdriver
|
||||
VIDEOINFOHEADER
|
||||
videoplayback
|
||||
viewbox
|
||||
viewmodel
|
||||
vih
|
||||
virtualization
|
||||
visiblecolorformats
|
||||
Visibletrue
|
||||
@ -2298,6 +2403,7 @@ VSCBD
|
||||
vscode
|
||||
VSCROLL
|
||||
vse
|
||||
vsix
|
||||
vsonline
|
||||
vstemplate
|
||||
VSTHRD
|
||||
@ -2320,6 +2426,9 @@ wcscpy
|
||||
wcslen
|
||||
wcsncmp
|
||||
wcsnicmp
|
||||
WDK
|
||||
wdksetup
|
||||
wdkvsix
|
||||
wdp
|
||||
wdupenv
|
||||
We'd
|
||||
@ -2346,6 +2455,8 @@ wikipedia
|
||||
wil
|
||||
wildcards
|
||||
winapi
|
||||
wincodec
|
||||
Wincodecsdk
|
||||
wincolor
|
||||
windef
|
||||
windevbuildagents
|
||||
@ -2401,6 +2512,7 @@ WMKEYUP
|
||||
wmp
|
||||
WMSYSKEYDOWN
|
||||
WMSYSKEYUP
|
||||
WMV
|
||||
wnd
|
||||
WNDCLASS
|
||||
WNDCLASSEX
|
||||
@ -2431,9 +2543,11 @@ wstringstream
|
||||
wsz
|
||||
wtoi
|
||||
WTS
|
||||
wtsapi
|
||||
WTSAT
|
||||
wu
|
||||
wubi
|
||||
WVC
|
||||
Wwan
|
||||
www
|
||||
wxs
|
||||
@ -2448,6 +2562,7 @@ XBUTTON
|
||||
XBUTTONDBLCLK
|
||||
XBUTTONDOWN
|
||||
XBUTTONUP
|
||||
xcopy
|
||||
XDiff
|
||||
XDocument
|
||||
XElement
|
||||
@ -2479,7 +2594,10 @@ yourinfo
|
||||
YourUserName
|
||||
YStr
|
||||
YUY
|
||||
yuyoyuppe
|
||||
YUYV
|
||||
YVU
|
||||
YVYU
|
||||
ZEROINIT
|
||||
ZIndex
|
||||
zipfolder
|
||||
@ -2491,9 +2609,3 @@ ZONESETCHANGE
|
||||
Zoneszonabletester
|
||||
Zoomusingmagnifier
|
||||
zzz
|
||||
coc
|
||||
djsoref
|
||||
dogancelik
|
||||
itsme
|
||||
nitroin
|
||||
ulazy
|
||||
|
@ -7,3 +7,5 @@ set SolutionDir=%cd%
|
||||
popd
|
||||
SET IsPipeline=1
|
||||
call msbuild ../tools/BugReportTool/BugReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1
|
||||
call msbuild ../tools/WebcamReportTool/WebcamReportTool.sln /p:Configuration=Release /p:Platform=x64 /p:CIBuild=true || exit /b 1
|
||||
|
||||
|
@ -61,6 +61,11 @@ build:
|
||||
- 'x64/**/*.pdb'
|
||||
exclude:
|
||||
- 'x64/Release/obj/**/*.pdb'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- from: 'x86/Release'
|
||||
# to: 'Build_Output'
|
||||
# include:
|
||||
# - 'modules\VideoConference\VideoConferenceProxyFilter_x86.dll'
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
@ -159,6 +164,9 @@ build:
|
||||
- 'modules\PowerRename\PowerRenameExt.dll'
|
||||
- 'modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe'
|
||||
- 'modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.dll'
|
||||
# TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
#- 'modules\VideoConference\VideoConferenceModule.dll'
|
||||
#- 'modules\VideoConference\VideoConferenceProxyFilter_x64.dll'
|
||||
- 'Settings\ManagedTelemetry.dll'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.exe'
|
||||
- 'Settings\Microsoft.PowerToys.Settings.UI.Lib.dll'
|
||||
@ -177,6 +185,7 @@ build:
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'BugReportTool\BugReportTool.exe'
|
||||
- 'WebcamReportTool\WebcamReportTool.exe'
|
||||
signing_options:
|
||||
sign_inline: true # This does signing a soon as this command completes
|
||||
- !!buildcommand
|
||||
@ -237,4 +246,3 @@ static_analysis_options:
|
||||
files_to_scan:
|
||||
- exclude:
|
||||
- '**/*.lcl'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../tools/BugReportTool/BugReportTool.sln || exit /b 1
|
||||
nuget restore ../tools/WebcamReportTool/WebcamReportTool.sln || exit /b 1
|
||||
|
@ -1,3 +1,12 @@
|
||||
cd /D "%~dp0"
|
||||
|
||||
nuget restore ../PowerToys.sln || exit /b 1
|
||||
|
||||
powershell.exe -Command "Invoke-WebRequest -OutFile %tmp%\wdksetup.exe https://go.microsoft.com/fwlink/p/?linkid=2085767"
|
||||
%tmp%\wdksetup.exe /q
|
||||
|
||||
copy "C:\Program Files (x86)\Windows Kits\10\Vsix\VS2019\WDK.vsix" %tmp%\wdkvsix.zip
|
||||
powershell Expand-Archive %tmp%\wdkvsix.zip -DestinationPath %tmp%\wdkvsix -Force
|
||||
|
||||
robocopy /e %tmp%\wdkvsix\$MSBuild\Microsoft\VC\v160 "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
robocopy /e %tmp%\wdkvsix\$VCTargets "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCTargets" || IF %ERRORLEVEL% LEQ 7 EXIT 0
|
||||
|
@ -75,7 +75,7 @@
|
||||
|
||||
<!-- Props that are constant for both Debug and Release configurations -->
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(OverridePlatformToolset)'!='True'">v142</PlatformToolset>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
|
258
PowerToys.sln
@ -333,7 +333,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.UnitConverter.UnitTest", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest\Community.PowerToys.Run.Plugin.UnitConverter.UnitTest.csproj", "{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}"
|
||||
EndProject
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shortcutguide", "shortcutguide", "{106CBECA-0701-4FC3-838C-9DF816A19AE2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterface", "src\modules\ShortcutGuide\ShortcutGuideModuleInterface\ShortcutGuideModuleInterface.vcxproj", "{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}"
|
||||
@ -342,376 +341,597 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\module
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZonesModuleInterface", "src\modules\fancyzones\FancyZonesModuleInterface\FancyZonesModuleInterface.vcxproj", "{48804216-2A0E-4168-A6D8-9CD068D14227}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{390AE700-B55F-4202-91EA-A822EB75B9BD}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FancyZones", "src\modules\fancyzones\FancyZones\FancyZones.vcxproj", "{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Update\PowerToys.Update.vcxproj", "{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "src\modules\videoconference\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceModule", "src\modules\videoconference\VideoConferenceModule\Video Conference.vcxproj", "{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "src\modules\videoconference\VideoConferenceProxyFilter\VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VideoConference", "VideoConference", "{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x64.Build.0 = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.ActiveCfg = Release|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x64.Build.0 = Release|x64
|
||||
{9412D5C6-2CF2-4FC2-A601-B55508EA9B27}.Release|x86.ActiveCfg = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x64.Build.0 = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.ActiveCfg = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x64.Build.0 = Release|x64
|
||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}.Release|x86.ActiveCfg = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x64.Build.0 = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.ActiveCfg = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x64.Build.0 = Release|x64
|
||||
{9C6A7905-72D4-4BF5-B256-ABFDAEF68AE9}.Release|x86.ActiveCfg = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x64.Build.0 = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.ActiveCfg = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x64.Build.0 = Release|x64
|
||||
{1A066C63-64B3-45F8-92FE-664E1CCE8077}.Release|x86.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x86.ActiveCfg = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x64.Build.0 = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.ActiveCfg = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x64.Build.0 = Release|x64
|
||||
{B25AC7A5-FB9F-4789-B392-D5C85E948670}.Release|x86.ActiveCfg = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x64.Build.0 = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.ActiveCfg = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x64.Build.0 = Release|x64
|
||||
{51920F1F-C28C-4ADF-8660-4238766796C2}.Release|x86.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x64.Build.0 = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.ActiveCfg = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x64.Build.0 = Release|x64
|
||||
{0E072714-D127-460B-AFAD-B4C40B412798}.Release|x86.ActiveCfg = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x64.Build.0 = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.ActiveCfg = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x64.Build.0 = Release|x64
|
||||
{A3935CF4-46C5-4A88-84D3-6B12E16E6BA2}.Release|x86.ActiveCfg = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x64.Build.0 = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.ActiveCfg = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x64.Build.0 = Release|x64
|
||||
{2151F984-E006-4A9F-92EF-C6DDE3DC8413}.Release|x86.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x64.Build.0 = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.ActiveCfg = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x64.Build.0 = Release|x64
|
||||
{64A80062-4D8B-4229-8A38-DFA1D7497749}.Release|x86.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x64.Build.0 = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.ActiveCfg = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x64.Build.0 = Release|x64
|
||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387}.Release|x86.ActiveCfg = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x64.Build.0 = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.ActiveCfg = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x64.Build.0 = Release|x64
|
||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9}.Release|x86.ActiveCfg = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x64.Build.0 = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.ActiveCfg = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x64.Build.0 = Release|x64
|
||||
{2BE46397-4DFA-414C-9BD4-41E4BBF8CB34}.Release|x86.ActiveCfg = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x64.Build.0 = Release|x64
|
||||
{0B43679E-EDFA-4DA0-AD30-F4628B308B1B}.Release|x86.ActiveCfg = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x64.Build.0 = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.ActiveCfg = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x64.Build.0 = Release|x64
|
||||
{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}.Release|x86.ActiveCfg = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x64.Build.0 = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.ActiveCfg = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x64.Build.0 = Release|x64
|
||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}.Release|x86.ActiveCfg = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x86.ActiveCfg = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x64.Build.0 = Release|x64
|
||||
{8AFFA899-0B73-49EC-8C50-0FADDA57B2FC}.Release|x86.ActiveCfg = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.Build.0 = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.ActiveCfg = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|x64
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.ActiveCfg = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x64.Build.0 = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.ActiveCfg = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.Build.0 = Release|x64
|
||||
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.ActiveCfg = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x64.Build.0 = Release|x64
|
||||
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Release|x86.ActiveCfg = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x64.Build.0 = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.ActiveCfg = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|x64
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x64.Build.0 = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.ActiveCfg = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x64.Build.0 = Release|x64
|
||||
{4D971245-7A70-41D5-BAA0-DDB5684CAF51}.Release|x86.ActiveCfg = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x64.Build.0 = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.ActiveCfg = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x64.Build.0 = Release|x64
|
||||
{74F1B9ED-F59C-4FE7-B473-7B453E30837E}.Release|x86.ActiveCfg = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x64.Build.0 = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.ActiveCfg = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x64.Build.0 = Release|x64
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4}.Release|x86.ActiveCfg = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.Build.0 = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.ActiveCfg = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x64.Build.0 = Release|x64
|
||||
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Release|x86.ActiveCfg = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x64.Build.0 = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.ActiveCfg = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x64.Build.0 = Release|x64
|
||||
{F8B870EB-D5F5-45BA-9CF7-A5C459818820}.Release|x86.ActiveCfg = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x64.Build.0 = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.ActiveCfg = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x64.Build.0 = Release|x64
|
||||
{E364F67B-BB12-4E91-B639-355866EBCD8B}.Release|x86.ActiveCfg = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x64.Build.0 = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.ActiveCfg = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x64.Build.0 = Release|x64
|
||||
{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}.Release|x86.ActiveCfg = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x64.Build.0 = Release|x64
|
||||
{AF2349B8-E5B6-4004-9502-687C1C7730B1}.Release|x86.ActiveCfg = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x64.Build.0 = Release|x64
|
||||
{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}.Release|x86.ActiveCfg = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x64.Build.0 = Release|x64
|
||||
{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}.Release|x86.ActiveCfg = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x64.Build.0 = Release|x64
|
||||
{DA425894-6E13-404F-8DCB-78584EC0557A}.Release|x86.ActiveCfg = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x64.Build.0 = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.ActiveCfg = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x64.Build.0 = Release|x64
|
||||
{060D75DA-2D1C-48E6-A4A1-6F0718B64661}.Release|x86.ActiveCfg = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x64.Build.0 = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.ActiveCfg = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x64.Build.0 = Release|x64
|
||||
{748417CA-F17E-487F-9411-CAFB6D3F4877}.Release|x86.ActiveCfg = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x64.Build.0 = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.ActiveCfg = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x64.Build.0 = Release|x64
|
||||
{217DF501-135C-4E38-BFC8-99D4821032EA}.Release|x86.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x64.Build.0 = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.ActiveCfg = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x64.Build.0 = Release|x64
|
||||
{47310AB4-9034-4BD1-8D8B-E88AD21A171B}.Release|x86.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x64.Build.0 = Debug|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.ActiveCfg = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x64.Build.0 = Release|x64
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Build.0 = Release|Win32
|
||||
{A7D5099E-F0FD-4BF3-8522-5A682759F915}.Release|x86.Deploy.0 = Release|Win32
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x64.Build.0 = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.ActiveCfg = Release|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x64.Build.0 = Release|x64
|
||||
{B1BCC8C6-46B5-4BFA-8F22-20F32D99EC6A}.Release|x86.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x64.Build.0 = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.ActiveCfg = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x64.Build.0 = Release|x64
|
||||
{787B8AA6-CA93-4C84-96FE-DF31110AD1C4}.Release|x86.ActiveCfg = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x64.Build.0 = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.ActiveCfg = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x64.Build.0 = Release|x64
|
||||
{08C8C05F-0362-41BC-818C-724572DF8B06}.Release|x86.ActiveCfg = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x64.Build.0 = Release|x64
|
||||
{5D00D290-4016-4CFE-9E41-1E7C724509BA}.Release|x86.ActiveCfg = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64
|
||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x86.ActiveCfg = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.Build.0 = Release|x64
|
||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x86.ActiveCfg = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x64.Build.0 = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.ActiveCfg = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x64.Build.0 = Release|x64
|
||||
{1EF1EEF0-10F0-4F2E-8550-39B6D8044D3E}.Release|x86.ActiveCfg = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x64.Build.0 = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.ActiveCfg = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x64.Build.0 = Release|x64
|
||||
{8FFE09DA-FA4F-4EE1-B3A2-AD5497FBD1AD}.Release|x86.ActiveCfg = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.Build.0 = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.ActiveCfg = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.Build.0 = Release|x64
|
||||
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x86.ActiveCfg = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
|
||||
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x86.ActiveCfg = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x64.Build.0 = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.ActiveCfg = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x64.Build.0 = Release|x64
|
||||
{03276A39-D4E9-417C-8FFD-200B0EE5E871}.Release|x86.ActiveCfg = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x64.Build.0 = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.ActiveCfg = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x64.Build.0 = Release|x64
|
||||
{B81FB7B6-D30E-428F-908A-41422EFC1172}.Release|x86.ActiveCfg = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x64.Build.0 = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.ActiveCfg = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x64.Build.0 = Release|x64
|
||||
{0F85E674-34AE-443D-954C-8321EB8B93B1}.Release|x86.ActiveCfg = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x64.Build.0 = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.ActiveCfg = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x64.Build.0 = Release|x64
|
||||
{632BBE62-5421-49EA-835A-7FFA4F499BD6}.Release|x86.ActiveCfg = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x64.Build.0 = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.ActiveCfg = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x64.Build.0 = Release|x64
|
||||
{4FA206A5-F69F-4193-BF8F-F6EEB496734C}.Release|x86.ActiveCfg = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x64.Build.0 = Release|x64
|
||||
{090CD7B7-3B0C-4D1D-BC98-83EB5D799BC1}.Release|x86.ActiveCfg = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x64.Build.0 = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.ActiveCfg = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x64.Build.0 = Release|x64
|
||||
{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}.Release|x86.ActiveCfg = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x64.Build.0 = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.ActiveCfg = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x64.Build.0 = Release|x64
|
||||
{FD8EB419-FF9C-4D88-BB6F-BF6CED37747B}.Release|x86.ActiveCfg = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x64.Build.0 = Release|x64
|
||||
{DA5A6FE9-0040-40CC-83CC-764AE5306590}.Release|x86.ActiveCfg = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x64.Build.0 = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.ActiveCfg = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x64.Build.0 = Release|x64
|
||||
{0351ADA4-0C32-4652-9BA0-41F7B602372B}.Release|x86.ActiveCfg = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x64.Build.0 = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.ActiveCfg = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x64.Build.0 = Release|x64
|
||||
{D9B8FC84-322A-4F9F-BBB9-20915C47DDFD}.Release|x86.ActiveCfg = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.Build.0 = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.ActiveCfg = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.Build.0 = Release|x64
|
||||
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x86.ActiveCfg = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x64.Build.0 = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.ActiveCfg = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x64.Build.0 = Release|x64
|
||||
{58736667-1027-4AD7-BFDF-7A3A6474103A}.Release|x86.ActiveCfg = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.Build.0 = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.ActiveCfg = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.Build.0 = Release|x64
|
||||
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x86.ActiveCfg = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x64.Build.0 = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.ActiveCfg = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x64.Build.0 = Release|x64
|
||||
{031AC72E-FA28-4AB7-B690-6F7B9C28AA73}.Release|x86.ActiveCfg = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x64.Build.0 = Release|x64
|
||||
{0B593A6C-4143-4337-860E-DB5710FB87DB}.Release|x86.ActiveCfg = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64
|
||||
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x86.ActiveCfg = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.Build.0 = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.ActiveCfg = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.Build.0 = Release|x64
|
||||
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x86.ActiveCfg = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x64.Build.0 = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.ActiveCfg = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x64.Build.0 = Release|x64
|
||||
{CABA8DFB-823B-4BF2-93AC-3F31984150D9}.Release|x86.ActiveCfg = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x64.Build.0 = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.ActiveCfg = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x64.Build.0 = Release|x64
|
||||
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB}.Release|x86.ActiveCfg = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x64.Build.0 = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x64.Build.0 = Release|x64
|
||||
{C3A17DCA-217B-462C-BB0C-BE086AF80081}.Release|x86.ActiveCfg = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x64.Build.0 = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.ActiveCfg = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x64.Build.0 = Release|x64
|
||||
{4BABF3FE-3451-42FD-873F-3C332E18DCEF}.Release|x86.ActiveCfg = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x64.Build.0 = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.ActiveCfg = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x64.Build.0 = Release|x64
|
||||
{0648DF05-5DDA-4BE1-B5F2-584926EBDB65}.Release|x86.ActiveCfg = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x64.Build.0 = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.ActiveCfg = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x64.Build.0 = Release|x64
|
||||
{6ED2F4FC-E122-4CEE-90F1-97E4CCC8BC7A}.Release|x86.ActiveCfg = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.ActiveCfg = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x64.Build.0 = Release|x64
|
||||
{BA661F5B-1D5A-4FFC-9BF1-FC39DF280BDD}.Release|x86.ActiveCfg = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x64.Build.0 = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.ActiveCfg = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x64.Build.0 = Release|x64
|
||||
{E496B7FC-1E99-4BAB-849B-0E8367040B02}.Release|x86.ActiveCfg = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x64.Build.0 = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.ActiveCfg = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x64.Build.0 = Release|x64
|
||||
{7F4B3A60-BC27-45A7-8000-68B0B6EA7466}.Release|x86.ActiveCfg = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x64.Build.0 = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.ActiveCfg = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x64.Build.0 = Release|x64
|
||||
{8DF78B53-200E-451F-9328-01EB907193AE}.Release|x86.ActiveCfg = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x64.Build.0 = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.ActiveCfg = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x64.Build.0 = Release|x64
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49}.Release|x86.ActiveCfg = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x86.ActiveCfg = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x86.ActiveCfg = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x86.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x86.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x86.ActiveCfg = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.Build.0 = Release|x64
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x86.ActiveCfg = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x86.ActiveCfg = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x64.Build.0 = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.ActiveCfg = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x64.Build.0 = Release|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Debug|x64.Build.0 = Debug|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.ActiveCfg = Release|x64
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD}.Release|x64.Build.0 = Release|x64
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227}.Release|x86.ActiveCfg = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x64.Build.0 = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.ActiveCfg = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x64.Build.0 = Release|x64
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700}.Release|x86.ActiveCfg = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.Build.0 = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.ActiveCfg = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.Build.0 = Release|x64
|
||||
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x86.ActiveCfg = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|x64
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.Build.0 = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x86.Build.0 = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.ActiveCfg = Release|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x86.Build.0 = Release|Win32
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x64.Build.0 = Release|x64
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}.Release|x86.ActiveCfg = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x86.Build.0 = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.ActiveCfg = Release|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -809,16 +1029,20 @@ Global
|
||||
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
|
||||
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
|
||||
{2EDB3EB4-FA92-4BFF-B2D8-566584837231} = {106CBECA-0701-4FC3-838C-9DF816A19AE2}
|
||||
{48804216-2A0E-4168-A6D8-9CD068D14227} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{390AE700-B55F-4202-91EA-A822EB75B9BD} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{FF1D7936-842A-4BBB-8BEA-E9FE796DE700} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042} = {470FBAF9-E1F8-4F3E-8786-198A1C81C8A8}
|
||||
{470FBAF9-E1F8-4F3E-8786-198A1C81C8A8} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -66,7 +66,12 @@ Various tools used by PowerToys. Includes the Visual Studio 2019 project templat
|
||||
2. Visual Studio Community/Professional/Enterprise 2019
|
||||
3. Once you've cloned and started the `PowerToys.sln`, in the solution explorer, if you see a dialog that says `install extra components`, click `install`
|
||||
|
||||
### Compile source code
|
||||
**Optional step:**<br/>
|
||||
4. to build the Video Conference module, install the [WDK version 1903](https://docs.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads) ([direct download link](https://go.microsoft.com/fwlink/?linkid=2085767))<br />
|
||||
During the installation, make sure that, when prompted, the `Install Windows Driver Kit Visual Studio extension` option is checked.
|
||||
|
||||
|
||||
### Compiling Source Code
|
||||
|
||||
- Open `PowerToys.sln` in Visual Studio, in the `Solutions Configuration` drop-down menu select `Release` or `Debug`, from the `Build` menu choose `Build Solution`.
|
||||
- The PowerToys binaries will be in your repo under `x64\Release\`.
|
||||
|
@ -3,7 +3,7 @@
|
||||
<Import Project="..\packages\WiX.3.11.2\build\wix.props" Condition="Exists('..\packages\WiX.3.11.2\build\wix.props')" />
|
||||
<Import Project="..\..\src\Version.props" />
|
||||
<PropertyGroup>
|
||||
<DefineConstants>Version=$(Version);</DefineConstants>
|
||||
<DefineConstants>Version=$(Version)</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
@ -74,7 +74,6 @@
|
||||
</Target>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>IF NOT DEFINED IsPipeline (
|
||||
|
||||
call "$([MSBuild]::GetVsInstallRoot())\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 -winsdk=10.0.18362.0
|
||||
SET PTRoot=..\..\..\..
|
||||
call "..\..\publish.cmd"
|
||||
|
@ -8,9 +8,11 @@
|
||||
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
||||
<?define PowerRenameProjectName="PowerRename"?>
|
||||
<?define ColorPickerProjectName="ColorPicker"?>
|
||||
<?define VideoConferenceProjectName="VideoConference"?>
|
||||
<?define AwakeProjectName="Awake"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?define BinX32Dir="$(var.RepoDir)x86\$(var.Configuration)\" ?>
|
||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||
<?define ShortcutGuideExecutable=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuide?>
|
||||
<?define ShortcutGuideModuleInterface=$(var.BinX64Dir)\modules\ShortcutGuide\ShortcutGuideModuleInterface?>
|
||||
@ -218,6 +220,10 @@
|
||||
</Directory>
|
||||
<Directory Id="ShortcutGuideModuleInterfaceInstallFolder" Name="ShortcutGuideModuleInterface"/>
|
||||
</Directory>
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <Directory Id="VideoConferenceInstallFolder" Name="$(var.VideoConferenceProjectName)">
|
||||
<Directory Id="VideoConferenceIconsFolder" Name="Icons" />
|
||||
</Directory> -->
|
||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||
<Directory Id="AwakeInstallFolder" Name="$(var.AwakeProjectName)">
|
||||
@ -442,6 +448,9 @@
|
||||
<Component Id="BugReportTool_exe" Guid="0F8E3E9F-2E86-4660-A3BF-AE4DD431B93C" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)BugReportTool\BugReportTool.exe" Id="BugReportTool.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="WebcamReportTool_exe" Guid="B6005DAC-8C26-4865-91B3-99F098422C13" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)WebcamReportTool\WebcamReportTool.exe" Id="WebcamReportTool.exe" Checksum="yes" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ModulesInstallFolder" FileSource="$(var.BinX64Dir)modules\">
|
||||
@ -637,6 +646,37 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <DirectoryRef Id="VideoConferenceInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\">
|
||||
<Component Id="Module_VideoConference" Guid="5996527a-40fc-432e-b3ac-abc0b4bd3887" Win64="yes">
|
||||
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
|
||||
<File SelfRegCost="1" Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x64.dll" KeyPath="yes">
|
||||
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
|
||||
</File>
|
||||
<File SelfRegCost="1" Source="$(var.BinX32Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceProxyFilter_x86.dll">
|
||||
<Class Id="{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}" Context="InprocServer32" ThreadingModel="apartment" Description="PowerToys VideoConference Mute" />
|
||||
</File>
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\VideoConferenceModule.dll" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="VideoConferenceIconsFolder" FileSource="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons">
|
||||
<Component Id="Module_VideoConferenceIcons" Guid="5996527a-40fc-432e-b34c-abc0b4bd3887" Win64="yes">
|
||||
<Condition>WINDOWSBUILDNUMBER >= 18362</Condition>
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-NotInUse Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-Off Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\Off-On Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-NotInUse Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Light.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-Off Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Dark.png" />
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.VideoConferenceProjectName)\Icons\On-On Light.png" />
|
||||
</Component>
|
||||
</DirectoryRef> -->
|
||||
|
||||
<DirectoryRef Id="ShortcutGuideExecutableInstallFolder" FileSource="$(var.ShortcutGuideExecutable)">
|
||||
<Component Id="Module_ShortcutGuideExecutable" Guid="DA6E5710-F1DF-44EB-A316-300FA39544E9" Win64="yes">
|
||||
<File Source="$(var.ShortcutGuideExecutable)\PowerToys.ShortcutGuide.exe" KeyPath="yes" />
|
||||
@ -751,7 +791,7 @@
|
||||
<File Source="$(var.BinX64Dir)Settings\PowerToys.Settings.exe"/>
|
||||
<File Source="$(var.BinX64Dir)Settings\Microsoft.PowerToys.Settings.UI.exe"/>
|
||||
<!-- dll -->
|
||||
<?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToys.Settings.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;ManagedTelemetry.dll;ManagedCommon.dll;ColorCode.Core.dll;ColorCode.UWP.dll;Microsoft.Graphics.Canvas.winmd;Microsoft.Toolkit.Parsers.dll;Microsoft.Toolkit.Uwp.UI.Animations.dll;Microsoft.Toolkit.Uwp.UI.Controls.dll?>
|
||||
<?foreach File in concrt140_app.dll;Microsoft.Bcl.AsyncInterfaces.dll;System.IO.Abstractions.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToys.Settings.dll;Microsoft.Toolkit.dll;Microsoft.Toolkit.Uwp.dll;Microsoft.Toolkit.Uwp.UI.dll;Microsoft.Toolkit.Win32.UI.XamlHost.dll;Microsoft.Toolkit.Win32.UI.XamlHost.Managed.dll;Microsoft.Toolkit.Wpf.UI.Controls.dll;Microsoft.Toolkit.Wpf.UI.XamlHost.dll;Microsoft.UI.Xaml.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;msvcp140_1_app.dll;msvcp140_2_app.dll;msvcp140_app.dll;Newtonsoft.Json.dll;PowerToysInterop.dll;System.Runtime.CompilerServices.Unsafe.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;vcamp140_app.dll;vccorlib140_app.dll;vcomp140_app.dll;vcruntime140_1_app.dll;vcruntime140_app.dll;ManagedTelemetry.dll;ManagedCommon.dll;ColorCode.Core.dll;ColorCode.UWP.dll;Microsoft.Graphics.Canvas.winmd;Microsoft.Toolkit.Parsers.dll;Microsoft.Toolkit.Uwp.UI.Animations.dll;Microsoft.Toolkit.Uwp.UI.Controls.dll;System.Deployment.dll;System.Windows.Forms.dll;System.Runtime.Serialization.Formatters.Soap.dll?>
|
||||
<File Id="SettingsV2_$(var.File)" Source="$(var.BinX64Dir)Settings\$(var.File)" />
|
||||
<?endforeach?>
|
||||
<!-- json -->
|
||||
@ -791,7 +831,7 @@
|
||||
</DirectoryRef>
|
||||
<DirectoryRef Id="SettingsV2AssetsModulesInstallFolder" FileSource="$(var.BinX64Dir)Settings\Assets\Modules">
|
||||
<Component Id="SettingsV2AssetsModules" Guid="A0B961A9-77D0-4223-88A9-E3B41BD9C329" Win64="yes">
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png?>
|
||||
<?foreach File in ColorPicker.png;FancyZones.png;Awake.png;ImageResizer.png;KBM.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<File Id="SettingsV2AssetsModules_$(var.File)" Source="$(var.BinX64Dir)Settings\Assets\Modules\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
@ -882,6 +922,9 @@
|
||||
<ComponentRef Id="ShortcutGuideSvgs" />
|
||||
<ComponentRef Id="Module_ShortcutGuideModuleInterface" />
|
||||
<ComponentRef Id="Module_ShortcutGuideExecutable" />
|
||||
<!-- TODO(yuyoyuppe): uncomment when VCM should be enabled -->
|
||||
<!-- <ComponentRef Id="Module_VideoConference" />
|
||||
<ComponentRef Id="Module_VideoConferenceIcons" /> -->
|
||||
<ComponentRef Id="Module_FancyZones" />
|
||||
<ComponentRef Id="DesktopShortcut" />
|
||||
<ComponentRef Id="Module_PowerRename" />
|
||||
@ -911,6 +954,7 @@
|
||||
</ComponentGroup>
|
||||
<ComponentGroup Id="ToolComponents" Directory="ToolsFolder">
|
||||
<ComponentRef Id="BugReportTool_exe" />
|
||||
<ComponentRef Id="WebcamReportTool_exe" />
|
||||
</ComponentGroup>
|
||||
</Fragment>
|
||||
|
||||
|
@ -18,6 +18,7 @@ TRACELOGGING_DEFINE_PROVIDER(
|
||||
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
|
||||
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
||||
|
||||
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
|
||||
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
|
||||
|
||||
// Creates a Scheduled Task to run at logon for the current user.
|
||||
@ -596,6 +597,165 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
#ifdef CIBuild // On pipeline we are using microsoft certification
|
||||
WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
|
||||
return WcaFinalize(ERROR_SUCCESS);
|
||||
#else
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR certificatePath = nullptr;
|
||||
HCERTSTORE hCertStore = nullptr;
|
||||
HANDLE hfile = nullptr;
|
||||
DWORD size = INVALID_FILE_SIZE;
|
||||
char * pFileContent = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "CertifyVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize", hr);
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &certificatePath);
|
||||
ExitOnFailure(hr, "Failed to get install preperty", hr);
|
||||
|
||||
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"AuthRoot");
|
||||
if (!hCertStore)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Cannot put principal run level: %x", hr);
|
||||
}
|
||||
|
||||
hfile = CreateFile(certificatePath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hfile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file open failed", hr);
|
||||
}
|
||||
|
||||
size = GetFileSize(hfile, nullptr);
|
||||
if (size == INVALID_FILE_SIZE)
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file size not valid", hr);
|
||||
}
|
||||
|
||||
pFileContent = (char*)malloc(size);
|
||||
|
||||
DWORD sizeread;
|
||||
if (!ReadFile(hfile, pFileContent, size, &sizeread, nullptr))
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Certificate file read failed", hr);
|
||||
}
|
||||
|
||||
if (!CertAddEncodedCertificateToStore(hCertStore,
|
||||
X509_ASN_ENCODING,
|
||||
(const BYTE*)pFileContent,
|
||||
size,
|
||||
CERT_STORE_ADD_ALWAYS,
|
||||
nullptr))
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Adding certificate failed", hr);
|
||||
}
|
||||
|
||||
free(pFileContent);
|
||||
|
||||
LExit:
|
||||
ReleaseStr(certificatePath);
|
||||
if (hCertStore)
|
||||
{
|
||||
CertCloseStore(hCertStore, 0);
|
||||
}
|
||||
if (hfile)
|
||||
{
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to add certificate to store"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UINT __stdcall InstallVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR driverPath = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "InstallVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &driverPath);
|
||||
ExitOnFailure(hr, "Failed to get install preperty");
|
||||
|
||||
BOOL requiresReboot;
|
||||
DiInstallDriverW(GetConsoleWindow(), driverPath, DIIRFLAG_FORCE_INF, &requiresReboot);
|
||||
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Failed to install driver");
|
||||
|
||||
LExit:
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Failed to install virtual camera driver"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall UninstallVirtualCameraDriverCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
LPWSTR driverPath = nullptr;
|
||||
|
||||
hr = WcaInitialize(hInstall, "UninstallVirtualCameraDriverCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
hr = WcaGetProperty(L"CustomActionData", &driverPath);
|
||||
ExitOnFailure(hr, "Failed to get uninstall preperty");
|
||||
|
||||
BOOL requiresReboot;
|
||||
DiUninstallDriverW(GetConsoleWindow(), driverPath, 0, &requiresReboot);
|
||||
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_INVALID_FLAGS:
|
||||
case ERROR_IN_WOW64:
|
||||
{
|
||||
hr = GetLastError();
|
||||
ExitOnFailure(hr, "Failed to uninstall driver");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LExit:
|
||||
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
PMSIHANDLE hRecord = MsiCreateRecord(0);
|
||||
MsiRecordSetString(hRecord, 0, TEXT("Filed to iminstall virtual camera driver"));
|
||||
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_WARNING + MB_OK), hRecord);
|
||||
}
|
||||
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
{
|
||||
|
@ -12,4 +12,8 @@ EXPORTS
|
||||
TelemetryLogUninstallFailCA
|
||||
TelemetryLogRepairCancelCA
|
||||
TelemetryLogRepairFailCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
TerminateProcessesCA
|
||||
CertifyVirtualCameraDriverCA
|
||||
InstallVirtualCameraDriverCA
|
||||
UninstallVirtualCameraDriverCA
|
||||
|
@ -56,7 +56,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Newdev.lib;Crypt32.lib;msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -124,4 +124,4 @@
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\WiX.3.11.2\build\wix.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\WiX.3.11.2\build\wix.props'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -4,6 +4,7 @@
|
||||
#define DPSAPI_VERSION 1
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <newdev.h>
|
||||
#include <strsafe.h>
|
||||
#include <msiquery.h>
|
||||
#include <Msi.h>
|
||||
|
@ -1,6 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
|
||||
#include <thread>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class FileWatcher
|
||||
{
|
@ -28,10 +28,12 @@
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="settings_helpers.h" />
|
||||
<ClInclude Include="settings_objects.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="settings_helpers.cpp" />
|
||||
<ClCompile Include="settings_objects.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -8,6 +8,7 @@ namespace PTSettingsHelper
|
||||
{
|
||||
constexpr inline const wchar_t* log_settings_filename = L"log_settings.json";
|
||||
|
||||
std::wstring get_powertoys_general_save_file_location();
|
||||
std::wstring get_module_save_file_location(std::wstring_view powertoy_key);
|
||||
std::wstring get_module_save_folder_location(std::wstring_view powertoy_name);
|
||||
std::wstring get_root_save_folder_location();
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <TraceLoggingProvider.h>
|
||||
#include <TraceLoggingDefines.h>
|
||||
#include "TraceLoggingProvider.h"
|
||||
#include "TraceLoggingDefines.h"
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(g_hProvider);
|
||||
|
@ -47,6 +47,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>PowerToysInterop;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)src\common\interop;../../;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<OmitDefaultLibName>false</OmitDefaultLibName>
|
||||
@ -54,7 +55,7 @@
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Mf.lib;WindowsApp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@ -83,6 +84,8 @@
|
||||
<WriteLinesToFile File="Generated Files\AssemblyInfo.cpp" Lines="@(HeaderLines)" Overwrite="true" Encoding="Unicode" WriteOnlyWhenDifferent="true" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h" />
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h" />
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="KeyboardHook.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
@ -90,6 +93,12 @@
|
||||
<ClInclude Include="shared_constants.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
|
||||
<CompileAsManaged>false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
|
||||
<CompileAsManaged>false</CompileAsManaged>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Generated Files\AssemblyInfo.cpp" />
|
||||
<ClCompile Include="HotkeyManager.cpp" />
|
||||
<ClCompile Include="interop.cpp" />
|
||||
@ -109,6 +118,12 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200902.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
</ImportGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -27,7 +27,13 @@
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shared_constants.h">
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shared_constants.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@ -50,10 +56,16 @@
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\MicrophoneDevice.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\videoconference\VideoConferenceShared\VideoCaptureDeviceList.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="interop.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -13,12 +13,17 @@
|
||||
// Therefore the simplest way is to compile these functions as native using the pragmas below.
|
||||
#pragma managed(push, off)
|
||||
#include "../utils/os-detect.h"
|
||||
// TODO: move to a separate library in common
|
||||
#include "../../modules/videoconference/VideoConferenceShared/MicrophoneDevice.h"
|
||||
#include "../../modules/videoconference/VideoConferenceShared/VideoCaptureDeviceList.h"
|
||||
#pragma managed(pop)
|
||||
|
||||
#include <common/version/version.h>
|
||||
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using System::Collections::Generic::List;
|
||||
|
||||
// https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2019
|
||||
namespace interop
|
||||
@ -122,6 +127,32 @@ public
|
||||
static String ^ GetProductVersion() {
|
||||
return gcnew String(get_product_version().c_str());
|
||||
}
|
||||
|
||||
static List<String ^> ^ GetAllActiveMicrophoneDeviceNames() {
|
||||
auto names = gcnew List<String ^>();
|
||||
for (const auto& device : MicrophoneDevice::getAllActive())
|
||||
{
|
||||
names->Add(gcnew String(device.name().data()));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
static List<String ^> ^
|
||||
GetAllVideoCaptureDeviceNames() {
|
||||
auto names = gcnew List<String ^>();
|
||||
VideoCaptureDeviceList vcdl;
|
||||
vcdl.EnumerateDevices();
|
||||
|
||||
for (UINT32 i = 0; i < vcdl.Count(); ++i)
|
||||
{
|
||||
auto name = gcnew String(vcdl.GetDeviceName(i).data());
|
||||
if (name != L"PowerToys VideoConference Mute")
|
||||
{
|
||||
names->Add(name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
};
|
||||
|
||||
public
|
||||
|
4
src/common/interop/packages.config
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200902.2" targetFramework="native" />
|
||||
</packages>
|
@ -7,13 +7,13 @@
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/window.h>
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
|
||||
#include "FancyZones.h"
|
||||
#include "FancyZonesLib/Settings.h"
|
||||
#include "FancyZonesLib/ZoneWindow.h"
|
||||
#include "FancyZonesLib/FancyZonesData.h"
|
||||
#include "FancyZonesLib/ZoneSet.h"
|
||||
#include "FancyZonesLib/FileWatcher.h"
|
||||
#include "FancyZonesLib/WindowMoveHandler.h"
|
||||
#include "FancyZonesLib/FancyZonesWinHookEventIDs.h"
|
||||
#include "FancyZonesLib/util.h"
|
||||
|
@ -41,7 +41,6 @@
|
||||
<ClInclude Include="FancyZones.h" />
|
||||
<ClInclude Include="FancyZonesDataTypes.h" />
|
||||
<ClInclude Include="FancyZonesWinHookEventIDs.h" />
|
||||
<ClInclude Include="FileWatcher.h" />
|
||||
<ClInclude Include="GenericKeyHook.h" />
|
||||
<ClInclude Include="FancyZonesData.h" />
|
||||
<ClInclude Include="JsonHelpers.h" />
|
||||
@ -67,7 +66,6 @@
|
||||
<ClCompile Include="FancyZonesDataTypes.cpp" />
|
||||
<ClCompile Include="FancyZonesWinHookEventIDs.cpp" />
|
||||
<ClCompile Include="FancyZonesData.cpp" />
|
||||
<ClCompile Include="FileWatcher.cpp" />
|
||||
<ClCompile Include="JsonHelpers.cpp" />
|
||||
<ClCompile Include="MonitorWorkAreaHandler.cpp" />
|
||||
<ClCompile Include="OnThreadExecutor.cpp" />
|
||||
|
@ -78,9 +78,6 @@
|
||||
<ClInclude Include="ZoneWindowDrawing.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileWatcher.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CallTracer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -140,9 +137,6 @@
|
||||
<ClCompile Include="OnThreadExecutor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileWatcher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CallTracer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-Disabled">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-Disabled" clip-path="url(#clip-Off-Disabled)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#585858" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
|
||||
<path id="Camera_disabled_icon" data-name="Camera disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#585858"/>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-Disabled_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-Disabled_Light" data-name="Off-Disabled Light" clip-path="url(#clip-Off-Disabled_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#c1c1c1" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
|
||||
<path id="Camera_disabled_icon" data-name="Camera disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#c1c1c1"/>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-Off_Dark">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-Off_Dark" data-name="Off-Off Dark" clip-path="url(#clip-Off-Off_Dark)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
|
||||
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)" fill="#fff"/>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-Off_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-Off_Light" data-name="Off-Off Light" clip-path="url(#clip-Off-Off_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
|
||||
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)"/>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 3.4 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-On_Dark">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-On_Dark" data-name="Off-On Dark" clip-path="url(#clip-Off-On_Dark)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)" fill="#fff"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-Off-On_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="Off-On_Light" data-name="Off-On Light" clip-path="url(#clip-Off-On_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
|
||||
<path id="Mic_off_icon" data-name="Mic off icon" d="M23.943,2.531l-1.019-1V1.5a1.448,1.448,0,0,1,.119-.586A1.5,1.5,0,0,1,23.37.437,1.538,1.538,0,0,1,24.453,0h4.076a1.538,1.538,0,0,1,1.083.437,1.5,1.5,0,0,1,.326.477,1.448,1.448,0,0,1,.119.586V8.531l-1.019-1V1.5a.472.472,0,0,0-.143-.352A.529.529,0,0,0,28.528,1H24.453a.491.491,0,0,0-.358.141.509.509,0,0,0-.151.359ZM32.095,8v2.523l-1.019-.992V8ZM35,15.148l-.716.7-3-2.945a3.218,3.218,0,0,1-1.106.8A3.388,3.388,0,0,1,28.831,14H27v1h2.038v1H23.943V15h2.038V14H24.15a3.206,3.206,0,0,1-1.266-.25,3.307,3.307,0,0,1-1.035-.687,3.239,3.239,0,0,1-.7-1.016,3.16,3.16,0,0,1-.263-1.25V8h1.019v2.8a2.093,2.093,0,0,0,.175.852,2.238,2.238,0,0,0,.486.7,2.2,2.2,0,0,0,.708.469,2.493,2.493,0,0,0,.876.18h4.681a2.187,2.187,0,0,0,.947-.211,2.427,2.427,0,0,0,.78-.586l-.812-.8a1.486,1.486,0,0,1-.533.438,1.613,1.613,0,0,1-.685.164H24.453a1.538,1.538,0,0,1-1.083-.437,1.5,1.5,0,0,1-.326-.477,1.448,1.448,0,0,1-.119-.586V4.711L19,.852l.716-.7ZM28.528,11a.5.5,0,0,0,.287-.086.526.526,0,0,0,.191-.234L23.943,5.711V10.5a.472.472,0,0,0,.143.352.529.529,0,0,0,.366.148Z" transform="translate(-9 14)"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone off</tspan></text>
|
||||
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-Disabled">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-Disabled" clip-path="url(#clip-On-Disabled)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#1f1f1f"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#585858" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
|
||||
<path id="Camer_disabled_icon" data-name="Camer disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#585858"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-Disabled_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-Disabled_Light" data-name="On-Disabled Light" clip-path="url(#clip-On-Disabled_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#c1c1c1" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera not in use</tspan></text>
|
||||
<path id="Camer_disabled_icon" data-name="Camer disabled icon" d="M12.5,509.031a3.408,3.408,0,0,1,1.359.272,3.634,3.634,0,0,1,1.117.745,3.348,3.348,0,0,1,.75,1.1A3.555,3.555,0,0,1,16,512.508a3.35,3.35,0,0,1-.273,1.351,3.608,3.608,0,0,1-.75,1.11,3.371,3.371,0,0,1-1.109.745,3.617,3.617,0,0,1-1.367.272,3.407,3.407,0,0,1-1.359-.272,3.634,3.634,0,0,1-1.117-.745,3.347,3.347,0,0,1-.75-1.1A3.555,3.555,0,0,1,9,512.508a3.351,3.351,0,0,1,.273-1.351,3.608,3.608,0,0,1,.75-1.11,3.371,3.371,0,0,1,1.109-.745A3.616,3.616,0,0,1,12.5,509.031ZM10,512.508a2.393,2.393,0,0,0,.2.963,2.585,2.585,0,0,0,.531.792,2.423,2.423,0,0,0,.8.536,2.491,2.491,0,0,0,.977.194,2.591,2.591,0,0,0,.719-.1,2.241,2.241,0,0,0,.656-.31l-3.461-3.439a2.334,2.334,0,0,0-.3.652A2.76,2.76,0,0,0,10,512.508Zm4.586,1.366a2.333,2.333,0,0,0,.3-.652,2.759,2.759,0,0,0,.109-.714,2.393,2.393,0,0,0-.2-.963,2.428,2.428,0,0,0-.539-.784,2.725,2.725,0,0,0-.8-.536,2.353,2.353,0,0,0-.969-.2,2.593,2.593,0,0,0-.719.1,2.245,2.245,0,0,0-.656.311ZM16,504v5.326a4.453,4.453,0,0,0-1-.823v-2.9l-3,1.5v.714a4.157,4.157,0,0,0-.508.078,4.1,4.1,0,0,0-.492.14v-2.981H1v5.962H8a4.038,4.038,0,0,0-.219.994H0v-7.95H12v1.925Z" transform="translate(171 -486)" fill="#c1c1c1"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-Off_Dark">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-Off_Dark" data-name="On-Off Dark" clip-path="url(#clip-On-Off_Dark)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
|
||||
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)" fill="#fff"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-Off_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-Off_Light" data-name="On-Off Light" clip-path="url(#clip-On-Off_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera off</tspan></text>
|
||||
<path id="Camera_off_icon" data-name="Camera off icon" d="M12,24.9l4-2.038v8.279l-1.953-1q-.141-.072-.258-.119t-.242-.1a1.825,1.825,0,0,1-.227-.119l-.25-.159a1.726,1.726,0,0,1-.2-.159,1.556,1.556,0,0,1-.156-.167q-.07-.088-.148-.175l-.18-.2L11,27.533v-3.59H7.477l-1-1.019H12Zm3,4.593V24.508l-3,1.536v1.91ZM.148,19.716.852,19l15,15.284-.7.716-3.859-3.924H0V22.924H3.289ZM1,30.057h9.289l-6-6.113H1Z" transform="translate(171 -5)"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-On_Dark">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-On_Dark" data-name="On-On Dark" clip-path="url(#clip-On-On_Dark)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#1f1f1f">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#313131"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#313131"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
|
||||
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)" fill="#fff"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" fill="#fff" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 3.2 KiB |
@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="322" height="44" viewBox="0 0 322 44">
|
||||
<defs>
|
||||
<clipPath id="clip-On-On_Light">
|
||||
<rect width="322" height="44"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g id="On-On_Light" data-name="On-On Light" clip-path="url(#clip-On-On_Light)">
|
||||
<rect width="322" height="44" fill="#f1f1f1"/>
|
||||
<g id="Background" fill="#f1f1f1">
|
||||
<path d="M 321.5 43.5 L 0.5 43.5 L 0.5 0.5 L 321.5 0.5 L 321.5 43.5 Z" stroke="none"/>
|
||||
<path d="M 1 1 L 1 43 L 321 43 L 321 1 L 1 1 M 0 0 L 322 0 L 322 44 L 0 44 L 0 0 Z" stroke="none" fill="#dbdbdb"/>
|
||||
</g>
|
||||
<rect id="Divider" width="1" height="24" transform="translate(161 10)" fill="#dbdbdb"/>
|
||||
<text id="Camera_label" data-name="Camera label" transform="translate(200 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Camera on</tspan></text>
|
||||
<path id="Camera_on_icon" data-name="Camera on icon" d="M16,512.359,12,510.3V512.3H0v-8.231H12v1.993L16,504Zm-5-7.266H1v6.173H11Zm4,.571-3,1.551v1.929l3,1.551Z" transform="translate(171 -486)"/>
|
||||
<text id="Mic_label" data-name="Mic label" transform="translate(38 13)" font-size="12" font-family="SegoeUI, Segoe UI"><tspan x="0" y="13">Microphone on</tspan></text>
|
||||
<path id="Mic_on_icon" data-name="Mic on icon" d="M259.518,12.092a1.476,1.476,0,0,1-.589-.118,1.5,1.5,0,0,1-.8-.8,1.486,1.486,0,0,1-.118-.59V1.511a1.486,1.486,0,0,1,.118-.59,1.5,1.5,0,0,1,.8-.8A1.476,1.476,0,0,1,259.518,0h4.02a1.476,1.476,0,0,1,.589.118,1.5,1.5,0,0,1,.8.8,1.487,1.487,0,0,1,.118.59V10.58a1.487,1.487,0,0,1-.118.59,1.5,1.5,0,0,1-.8.8,1.476,1.476,0,0,1-.589.118Zm-.5-1.511a.51.51,0,0,0,.5.5h4.02a.51.51,0,0,0,.5-.5V1.511a.485.485,0,0,0-.149-.354.482.482,0,0,0-.353-.15h-4.02a.482.482,0,0,0-.353.15.485.485,0,0,0-.149.354Zm8.04-2.519v2.85a3.106,3.106,0,0,1-.251,1.244,3.2,3.2,0,0,1-1.7,1.7,3.085,3.085,0,0,1-1.241.252H262.03v1.008h2.01v1.008h-5.025V15.115h2.01V14.107h-1.837a3.085,3.085,0,0,1-1.241-.252,3.2,3.2,0,0,1-1.7-1.7A3.107,3.107,0,0,1,256,10.911V8.061h1.005v2.85a2.128,2.128,0,0,0,.173.85,2.2,2.2,0,0,0,.463.693,2.281,2.281,0,0,0,.7.472,1.981,1.981,0,0,0,.848.173h4.68a2.113,2.113,0,0,0,.848-.173,2.195,2.195,0,0,0,.691-.464,2.288,2.288,0,0,0,.471-.7,2,2,0,0,0,.173-.85V8.061Z" transform="translate(-244.073 14)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
14
src/modules/videoconference/VideoConferenceModule/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Video Conference Mute
|
||||
|
||||
# Introduction
|
||||
The Video Conference Mute module allows muting microphone and/or web camera video stream during video calls or other activity.
|
||||
|
||||
# Usage
|
||||
If you'd like to mute your web camera, please select "PowerToys VideoConference Mute" device in your web camera-using app, then restart it.
|
||||
|
||||
During a video call, you can use default shortcuts to mute microphone, web camera or both. You'll see a toolbar indicating corresponding mute statuses.
|
||||
|
||||
# Options
|
||||
You can tweak the toolbar position on the screen as well as set web camera overlay image during muting.
|
||||
|
||||
# Backlog
|
335
src/modules/videoconference/VideoConferenceModule/Toolbar.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
#include "pch.h"
|
||||
#include "Toolbar.h"
|
||||
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <common/Themes/windows_colors.h>
|
||||
|
||||
#include "Logging.h"
|
||||
#include "VideoConferenceModule.h"
|
||||
|
||||
Toolbar* toolbar = nullptr;
|
||||
|
||||
const int REFRESH_RATE = 100;
|
||||
const int OVERLAY_SHOW_TIME = 500;
|
||||
const int BORDER_OFFSET = 12;
|
||||
|
||||
Toolbar::Toolbar()
|
||||
{
|
||||
toolbar = this;
|
||||
darkImages.camOnMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-On Dark.png");
|
||||
darkImages.camOffMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-Off Dark.png");
|
||||
darkImages.camOnMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-On Dark.png");
|
||||
darkImages.camOffMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-Off Dark.png");
|
||||
darkImages.camUnusedMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-NotInUse Dark.png");
|
||||
darkImages.camUnusedMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-NotInUse Dark.png");
|
||||
|
||||
lightImages.camOnMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-On Light.png");
|
||||
lightImages.camOffMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-Off Light.png");
|
||||
lightImages.camOnMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-On Light.png");
|
||||
lightImages.camOffMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-Off Light.png");
|
||||
lightImages.camUnusedMicOn = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/On-NotInUse Light.png");
|
||||
lightImages.camUnusedMicOff = Gdiplus::Image::FromFile(L"modules/VideoConference/Icons/Off-NotInUse Light.png");
|
||||
}
|
||||
|
||||
void Toolbar::scheduleModuleSettingsUpdate()
|
||||
{
|
||||
moduleSettingsUpdateScheduled = true;
|
||||
}
|
||||
|
||||
void Toolbar::scheduleGeneralSettingsUpdate()
|
||||
{
|
||||
generalSettingsUpdateScheduled = true;
|
||||
}
|
||||
|
||||
LRESULT Toolbar::WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_DESTROY:
|
||||
return 0;
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
int x = GET_X_LPARAM(lparam);
|
||||
int y = GET_Y_LPARAM(lparam);
|
||||
|
||||
if (x < 322 / 2)
|
||||
{
|
||||
VideoConferenceModule::reverseMicrophoneMute();
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoConferenceModule::reverseVirtualCameraMuteState();
|
||||
}
|
||||
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
case WM_CREATE:
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc;
|
||||
|
||||
hdc = BeginPaint(hwnd, &ps);
|
||||
|
||||
Gdiplus::Graphics graphic(hdc);
|
||||
|
||||
ToolbarImages* themeImages = &toolbar->darkImages;
|
||||
|
||||
if (toolbar->theme == L"light" || (toolbar->theme == L"system" && !WindowsColors::is_dark_mode()))
|
||||
{
|
||||
themeImages = &toolbar->lightImages;
|
||||
}
|
||||
else
|
||||
{
|
||||
themeImages = &toolbar->darkImages;
|
||||
}
|
||||
Gdiplus::Image* toolbarImage = nullptr;
|
||||
if (!toolbar->cameraInUse)
|
||||
{
|
||||
if (toolbar->microphoneMuted)
|
||||
{
|
||||
toolbarImage = themeImages->camUnusedMicOff;
|
||||
}
|
||||
else
|
||||
{
|
||||
toolbarImage = themeImages->camUnusedMicOn;
|
||||
}
|
||||
}
|
||||
else if (toolbar->microphoneMuted)
|
||||
{
|
||||
if (toolbar->cameraMuted)
|
||||
{
|
||||
toolbarImage = themeImages->camOffMicOff;
|
||||
}
|
||||
else
|
||||
{
|
||||
toolbarImage = themeImages->camOnMicOff;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (toolbar->cameraMuted)
|
||||
{
|
||||
toolbarImage = themeImages->camOffMicOn;
|
||||
}
|
||||
else
|
||||
{
|
||||
toolbarImage = themeImages->camOnMicOn;
|
||||
}
|
||||
}
|
||||
graphic.DrawImage(toolbarImage, 0, 0, toolbarImage->GetWidth(), toolbarImage->GetHeight());
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
break;
|
||||
}
|
||||
case WM_TIMER:
|
||||
{
|
||||
if (toolbar->generalSettingsUpdateScheduled)
|
||||
{
|
||||
instance->onGeneralSettingsChanged();
|
||||
toolbar->generalSettingsUpdateScheduled = false;
|
||||
}
|
||||
if (toolbar->moduleSettingsUpdateScheduled)
|
||||
{
|
||||
instance->onModuleSettingsChanged();
|
||||
toolbar->moduleSettingsUpdateScheduled = false;
|
||||
}
|
||||
|
||||
toolbar->cameraInUse = VideoConferenceModule::getVirtualCameraInUse();
|
||||
|
||||
InvalidateRect(hwnd, NULL, NULL);
|
||||
|
||||
using namespace std::chrono;
|
||||
const auto nowMillis = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||
const bool showOverlayTimeout = nowMillis - toolbar->lastTimeCamOrMicMuteStateChanged > OVERLAY_SHOW_TIME;
|
||||
|
||||
static bool previousShow = false;
|
||||
bool show = false;
|
||||
|
||||
if (toolbar->cameraInUse)
|
||||
{
|
||||
show = toolbar->HideToolbarWhenUnmuted ? toolbar->microphoneMuted || toolbar->cameraMuted : true;
|
||||
}
|
||||
else if (toolbar->previouscameraInUse)
|
||||
{
|
||||
VideoConferenceModule::unmuteAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
show = toolbar->microphoneMuted;
|
||||
}
|
||||
show = show || !showOverlayTimeout;
|
||||
if (show)
|
||||
{
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
}
|
||||
if (previousShow != show)
|
||||
{
|
||||
previousShow = show;
|
||||
LOG(show ? "Toolbar visibility changed to shown" : "Toolbar visibility changed to hidden");
|
||||
}
|
||||
|
||||
KillTimer(hwnd, toolbar->nTimerId);
|
||||
toolbar->previouscameraInUse = toolbar->cameraInUse;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
toolbar->nTimerId = SetTimer(hwnd, 101, REFRESH_RATE, nullptr);
|
||||
|
||||
return DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
void Toolbar::show(std::wstring position, std::wstring monitorString)
|
||||
{
|
||||
for (auto& hwnd : hwnds)
|
||||
{
|
||||
PostMessageW(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
hwnds.clear();
|
||||
|
||||
int overlayWidth = darkImages.camOffMicOff->GetWidth();
|
||||
int overlayHeight = darkImages.camOffMicOff->GetHeight();
|
||||
|
||||
// Register the window class
|
||||
LPCWSTR CLASS_NAME = L"MuteNotificationWindowClass";
|
||||
WNDCLASS wc{};
|
||||
wc.hInstance = GetModuleHandleW(nullptr);
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.lpfnWndProc = WindowProcessMessages;
|
||||
RegisterClassW(&wc);
|
||||
|
||||
// Create the window
|
||||
DWORD dwExtStyle = 0;
|
||||
DWORD dwStyle = WS_POPUPWINDOW;
|
||||
|
||||
std::vector<MonitorInfo> monitorInfos;
|
||||
|
||||
if (monitorString == L"All monitors")
|
||||
{
|
||||
monitorInfos = MonitorInfo::GetMonitors(false);
|
||||
}
|
||||
else //"Main monitor" or non-present
|
||||
{
|
||||
monitorInfos.push_back(MonitorInfo::GetPrimaryMonitor());
|
||||
}
|
||||
|
||||
for (auto& monitorInfo : monitorInfos)
|
||||
{
|
||||
int positionX = 0;
|
||||
int positionY = 0;
|
||||
|
||||
if (position == L"Top left corner")
|
||||
{
|
||||
positionX = monitorInfo.left() + BORDER_OFFSET;
|
||||
positionY = monitorInfo.top() + BORDER_OFFSET;
|
||||
}
|
||||
else if (position == L"Top center")
|
||||
{
|
||||
positionX = monitorInfo.middle().x - overlayWidth / 2;
|
||||
positionY = monitorInfo.top() + BORDER_OFFSET;
|
||||
}
|
||||
else if (position == L"Bottom left corner")
|
||||
{
|
||||
positionX = monitorInfo.left() + BORDER_OFFSET;
|
||||
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
|
||||
}
|
||||
else if (position == L"Bottom center")
|
||||
{
|
||||
positionX = monitorInfo.middle().x - overlayWidth / 2;
|
||||
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
|
||||
}
|
||||
else if (position == L"Bottom right corner")
|
||||
{
|
||||
positionX = monitorInfo.right() - overlayWidth - BORDER_OFFSET;
|
||||
positionY = monitorInfo.bottom() - overlayHeight - BORDER_OFFSET;
|
||||
}
|
||||
else //"Top right corner" or non-present
|
||||
{
|
||||
positionX = monitorInfo.right() - overlayWidth - BORDER_OFFSET;
|
||||
positionY = monitorInfo.top() + BORDER_OFFSET;
|
||||
}
|
||||
|
||||
HWND hwnd;
|
||||
hwnd = CreateWindowExW(
|
||||
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
|
||||
CLASS_NAME,
|
||||
CLASS_NAME,
|
||||
WS_POPUP,
|
||||
positionX,
|
||||
positionY,
|
||||
overlayWidth,
|
||||
overlayHeight,
|
||||
nullptr,
|
||||
nullptr,
|
||||
GetModuleHandleW(nullptr),
|
||||
nullptr);
|
||||
|
||||
auto transparrentColorKey = RGB(0, 0, 255);
|
||||
HBRUSH brush = CreateSolidBrush(transparrentColorKey);
|
||||
SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)brush);
|
||||
|
||||
SetLayeredWindowAttributes(hwnd, transparrentColorKey, 0, LWA_COLORKEY);
|
||||
|
||||
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
|
||||
hwnds.push_back(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void Toolbar::hide()
|
||||
{
|
||||
for (auto& hwnd : hwnds)
|
||||
{
|
||||
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
hwnds.clear();
|
||||
}
|
||||
|
||||
bool Toolbar::getCameraMute()
|
||||
{
|
||||
return cameraMuted;
|
||||
}
|
||||
|
||||
void Toolbar::setCameraMute(bool mute)
|
||||
{
|
||||
if (mute != cameraMuted)
|
||||
{
|
||||
lastTimeCamOrMicMuteStateChanged = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
cameraMuted = mute;
|
||||
}
|
||||
|
||||
bool Toolbar::getMicrophoneMute()
|
||||
{
|
||||
return microphoneMuted;
|
||||
}
|
||||
|
||||
void Toolbar::setMicrophoneMute(bool mute)
|
||||
{
|
||||
if (mute != microphoneMuted)
|
||||
{
|
||||
lastTimeCamOrMicMuteStateChanged = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
microphoneMuted = mute;
|
||||
}
|
||||
|
||||
void Toolbar::setHideToolbarWhenUnmuted(bool hide)
|
||||
{
|
||||
HideToolbarWhenUnmuted = hide;
|
||||
}
|
||||
|
||||
void Toolbar::setTheme(std::wstring theme)
|
||||
{
|
||||
Toolbar::theme = theme;
|
||||
}
|
61
src/modules/videoconference/VideoConferenceModule/Toolbar.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <gdiplus.h>
|
||||
#include <atomic>
|
||||
|
||||
#include <common/Display/monitors.h>
|
||||
|
||||
struct ToolbarImages
|
||||
{
|
||||
Gdiplus::Image* camOnMicOn = nullptr;
|
||||
Gdiplus::Image* camOffMicOn = nullptr;
|
||||
Gdiplus::Image* camOnMicOff = nullptr;
|
||||
Gdiplus::Image* camOffMicOff = nullptr;
|
||||
Gdiplus::Image* camUnusedMicOn = nullptr;
|
||||
Gdiplus::Image* camUnusedMicOff = nullptr;
|
||||
};
|
||||
|
||||
class Toolbar
|
||||
{
|
||||
public:
|
||||
Toolbar();
|
||||
|
||||
void scheduleModuleSettingsUpdate();
|
||||
void scheduleGeneralSettingsUpdate();
|
||||
|
||||
void show(std::wstring position, std::wstring monitorString);
|
||||
void hide();
|
||||
|
||||
bool getCameraMute();
|
||||
void setCameraMute(bool mute);
|
||||
bool getMicrophoneMute();
|
||||
void setMicrophoneMute(bool mute);
|
||||
|
||||
void setTheme(std::wstring theme);
|
||||
void setHideToolbarWhenUnmuted(bool hide);
|
||||
|
||||
private:
|
||||
static LRESULT CALLBACK WindowProcessMessages(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
||||
// Window callback can't be non-static so this members can't as well
|
||||
std::vector<HWND> hwnds;
|
||||
|
||||
ToolbarImages darkImages;
|
||||
ToolbarImages lightImages;
|
||||
|
||||
bool cameraMuted = false;
|
||||
bool cameraInUse = false;
|
||||
bool previouscameraInUse = false;
|
||||
bool microphoneMuted = false;
|
||||
|
||||
std::wstring theme = L"system";
|
||||
|
||||
bool HideToolbarWhenUnmuted = true;
|
||||
|
||||
uint64_t lastTimeCamOrMicMuteStateChanged;
|
||||
|
||||
std::atomic_bool moduleSettingsUpdateScheduled = false;
|
||||
std::atomic_bool generalSettingsUpdateScheduled = false;
|
||||
UINT_PTR nTimerId;
|
||||
};
|
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="keyboard_state.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="shortcut_guide.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="target_state.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="overlay_window.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="keyboard_state.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="shortcut_guide.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="target_state.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="overlay_window.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{2c7c97f7-0d87-4230-a4b2-baf2cfc35d58}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{aa4b6713-589d-42ef-804d-3a045833f83f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="shortcut_guide.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,183 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{5ABA70DE-3A3F-41F6-A1F5-D1F74F54F9BB}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>overlaywindow</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>VideoConferenceModule</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;OVERLAYWINDOW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..\..\..\;..\..\;..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>mfplat.lib;mf.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;gdiplus.lib;dwmapi.lib;uxtheme.lib;shcore.lib;Wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /I "$(ProjectDir)Icons\*" "$(OutDir)Icons"
|
||||
xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;OVERLAYWINDOW_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\..\;..\..\;..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>mfplat.lib;mf.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;gdiplus.lib;dwmapi.lib;uxtheme.lib;shcore.lib;Wtsapi32.lib;dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /y /I "$(ProjectDir)Icons\*" "$(OutDir)Icons"
|
||||
xcopy /y /I "$(ProjectDir)black.bmp*" "$(OutDir)"</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="Toolbar.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="VideoConferenceModule.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="Toolbar.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoConferenceModule.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VideoConferenceShared\VideoConferenceShared.vcxproj">
|
||||
<Project>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Icons\Off-NotInUse Dark.svg" />
|
||||
<None Include="Icons\Off-NotInUse Light.svg" />
|
||||
<None Include="Icons\Off-Off Dark.svg" />
|
||||
<None Include="Icons\Off-Off Light.svg" />
|
||||
<None Include="Icons\Off-On Dark.svg" />
|
||||
<None Include="Icons\Off-On Light.svg" />
|
||||
<None Include="Icons\On-NotInUse Dark.svg" />
|
||||
<None Include="Icons\On-NotInUse Light.svg" />
|
||||
<None Include="Icons\On-Off Dark.svg" />
|
||||
<None Include="Icons\On-Off Light.svg" />
|
||||
<None Include="Icons\On-On Dark.svg" />
|
||||
<None Include="Icons\On-On Light.svg" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="black.bmp" />
|
||||
<Image Include="Icons\Off-NotInUse Dark.png" />
|
||||
<Image Include="Icons\Off-NotInUse Light.png" />
|
||||
<Image Include="Icons\Off-Off Dark.png" />
|
||||
<Image Include="Icons\Off-Off Light.png" />
|
||||
<Image Include="Icons\Off-On Dark.png" />
|
||||
<Image Include="Icons\Off-On Light.png" />
|
||||
<Image Include="Icons\On-NotInUse Dark.png" />
|
||||
<Image Include="Icons\On-NotInUse Light.png" />
|
||||
<Image Include="Icons\On-Off Dark.png" />
|
||||
<Image Include="Icons\On-Off Light.png" />
|
||||
<Image Include="Icons\On-On Dark.png" />
|
||||
<Image Include="Icons\On-On Light.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
|
||||
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
|
||||
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="Toolbar.cpp" />
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="VideoConferenceModule.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="Toolbar.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="VideoConferenceModule.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="black.bmp" />
|
||||
<Image Include="Icons\Off-NotInUse Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\Off-NotInUse Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\Off-Off Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\Off-Off Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\Off-On Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\Off-On Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-NotInUse Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-NotInUse Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-Off Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-Off Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-On Dark.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
<Image Include="Icons\On-On Light.png">
|
||||
<Filter>Icons</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="Icons\Off-NotInUse Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\Off-NotInUse Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\Off-Off Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\Off-Off Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\Off-On Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\Off-On Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-NotInUse Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-NotInUse Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-Off Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-Off Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-On Dark.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
<None Include="Icons\On-On Light.svg">
|
||||
<Filter>Icons</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Icons">
|
||||
<UniqueIdentifier>{735361e2-82fa-4034-b9c9-cd6aa099eaa5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,568 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "VideoConferenceModule.h"
|
||||
|
||||
#include <WinUser.h>
|
||||
|
||||
#include <gdiplus.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <common/debug_control.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/process_path.h>
|
||||
|
||||
#include <CameraStateUpdateChannels.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "trace.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
VideoConferenceModule* instance = nullptr;
|
||||
|
||||
VideoConferenceSettings VideoConferenceModule::settings;
|
||||
Toolbar VideoConferenceModule::toolbar;
|
||||
|
||||
HHOOK VideoConferenceModule::hook_handle;
|
||||
|
||||
IAudioEndpointVolume* endpointVolume = NULL;
|
||||
|
||||
bool VideoConferenceModule::isKeyPressed(unsigned int keyCode)
|
||||
{
|
||||
return (GetKeyState(keyCode) & 0x8000);
|
||||
}
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
bool VideoConferenceModule::isHotkeyPressed(DWORD code, PowerToysSettings::HotkeyObject& hotkey)
|
||||
{
|
||||
return code == hotkey.get_code() &&
|
||||
isKeyPressed(VK_SHIFT) == hotkey.shift_pressed() &&
|
||||
isKeyPressed(VK_CONTROL) == hotkey.ctrl_pressed() &&
|
||||
isKeyPressed(VK_LWIN) == hotkey.win_pressed() &&
|
||||
(isKeyPressed(VK_LMENU)) == hotkey.alt_pressed();
|
||||
}
|
||||
|
||||
void VideoConferenceModule::reverseMicrophoneMute()
|
||||
{
|
||||
bool muted = false;
|
||||
for (auto& controlledMic : instance->_controlledMicrophones)
|
||||
{
|
||||
const bool was_muted = controlledMic.muted();
|
||||
controlledMic.toggle_muted();
|
||||
muted = muted || !was_muted;
|
||||
}
|
||||
if (muted)
|
||||
{
|
||||
Trace::MicrophoneMuted();
|
||||
}
|
||||
toolbar.setMicrophoneMute(muted);
|
||||
}
|
||||
|
||||
bool VideoConferenceModule::getMicrophoneMuteState()
|
||||
{
|
||||
return instance->_microphoneTrackedInUI ? instance->_microphoneTrackedInUI->muted() : false;
|
||||
}
|
||||
|
||||
void VideoConferenceModule::reverseVirtualCameraMuteState()
|
||||
{
|
||||
bool muted = false;
|
||||
if (!instance->_settingsUpdateChannel.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
instance->_settingsUpdateChannel->access([&muted](auto settingsMemory) {
|
||||
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
|
||||
settings->useOverlayImage = !settings->useOverlayImage;
|
||||
muted = settings->useOverlayImage;
|
||||
});
|
||||
|
||||
if (muted)
|
||||
{
|
||||
Trace::CameraMuted();
|
||||
}
|
||||
toolbar.setCameraMute(muted);
|
||||
}
|
||||
|
||||
bool VideoConferenceModule::getVirtualCameraMuteState()
|
||||
{
|
||||
bool disabled = false;
|
||||
if (!instance->_settingsUpdateChannel.has_value())
|
||||
{
|
||||
return disabled;
|
||||
}
|
||||
instance->_settingsUpdateChannel->access([&disabled](auto settingsMemory) {
|
||||
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
|
||||
disabled = settings->useOverlayImage;
|
||||
});
|
||||
return disabled;
|
||||
}
|
||||
|
||||
bool VideoConferenceModule::getVirtualCameraInUse()
|
||||
{
|
||||
if (!instance->_settingsUpdateChannel.has_value())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool inUse = false;
|
||||
instance->_settingsUpdateChannel->access([&inUse](auto settingsMemory) {
|
||||
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
|
||||
inUse = settings->cameraInUse;
|
||||
});
|
||||
return inUse;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK VideoConferenceModule::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (nCode == HC_ACTION)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case WM_KEYDOWN:
|
||||
KBDLLHOOKSTRUCT* kbd = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||
|
||||
if (isHotkeyPressed(kbd->vkCode, settings.cameraAndMicrophoneMuteHotkey))
|
||||
{
|
||||
const bool cameraInUse = getVirtualCameraInUse();
|
||||
const bool microphoneIsMuted = getMicrophoneMuteState();
|
||||
const bool cameraIsMuted = cameraInUse && getVirtualCameraMuteState();
|
||||
if (cameraInUse)
|
||||
{
|
||||
// we're likely on a video call, so we must mute the unmuted cam/mic or reverse the mute state
|
||||
// of everything, if cam and mic mute states are the same
|
||||
if (microphoneIsMuted == cameraIsMuted)
|
||||
{
|
||||
reverseMicrophoneMute();
|
||||
reverseVirtualCameraMuteState();
|
||||
}
|
||||
else if (cameraIsMuted)
|
||||
{
|
||||
reverseMicrophoneMute();
|
||||
}
|
||||
else if (microphoneIsMuted)
|
||||
{
|
||||
reverseVirtualCameraMuteState();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the camera is not in use, we just mute/unmute the mic
|
||||
reverseMicrophoneMute();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (isHotkeyPressed(kbd->vkCode, settings.microphoneMuteHotkey))
|
||||
{
|
||||
reverseMicrophoneMute();
|
||||
return 1;
|
||||
}
|
||||
else if (isHotkeyPressed(kbd->vkCode, settings.cameraMuteHotkey))
|
||||
{
|
||||
reverseVirtualCameraMuteState();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(hook_handle, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
void VideoConferenceModule::onGeneralSettingsChanged()
|
||||
{
|
||||
auto settings = PTSettingsHelper::load_general_settings();
|
||||
bool enabled = false;
|
||||
try
|
||||
{
|
||||
if (json::has(settings, L"enabled"))
|
||||
{
|
||||
for (const auto& mod : settings.GetNamedObject(L"enabled"))
|
||||
{
|
||||
const auto value = mod.Value();
|
||||
if (value.ValueType() != json::JsonValueType::Boolean)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (mod.Key() == get_key())
|
||||
{
|
||||
enabled = value.GetBoolean();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG("Couldn't get enabled state");
|
||||
}
|
||||
if (enabled)
|
||||
{
|
||||
enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
disable();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::onModuleSettingsChanged()
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
|
||||
//Trace::SettingsChanged(pressTime.value, overlayOpacity.value, theme.value);
|
||||
|
||||
if (_enabled)
|
||||
{
|
||||
if (const auto val = values.get_json(L"mute_camera_and_microphone_hotkey"))
|
||||
{
|
||||
settings.cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = values.get_json(L"mute_microphone_hotkey"))
|
||||
{
|
||||
settings.microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = values.get_json(L"mute_camera_hotkey"))
|
||||
{
|
||||
settings.cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = values.get_string_value(L"toolbar_position"))
|
||||
{
|
||||
settings.toolbarPositionString = val.value();
|
||||
}
|
||||
if (const auto val = values.get_string_value(L"toolbar_monitor"))
|
||||
{
|
||||
settings.toolbarMonitorString = val.value();
|
||||
}
|
||||
if (const auto val = values.get_string_value(L"selected_camera"); val && val != settings.selectedCamera)
|
||||
{
|
||||
settings.selectedCamera = val.value();
|
||||
sendSourceCameraNameUpdate();
|
||||
}
|
||||
if (const auto val = values.get_string_value(L"camera_overlay_image_path"); val && val != settings.imageOverlayPath)
|
||||
{
|
||||
settings.imageOverlayPath = val.value();
|
||||
sendOverlayImageUpdate();
|
||||
}
|
||||
if (const auto val = values.get_bool_value(L"hide_toolbar_when_unmuted"))
|
||||
{
|
||||
toolbar.setHideToolbarWhenUnmuted(val.value());
|
||||
}
|
||||
|
||||
const auto selectedMic = values.get_string_value(L"selected_mic");
|
||||
if (selectedMic && selectedMic != settings.selectedMicrophone)
|
||||
{
|
||||
settings.selectedMicrophone = *selectedMic;
|
||||
updateControlledMicrophones(settings.selectedMicrophone);
|
||||
}
|
||||
|
||||
toolbar.show(settings.toolbarPositionString, settings.toolbarMonitorString);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG("onModuleSettingsChanged encountered an exception");
|
||||
}
|
||||
}
|
||||
|
||||
VideoConferenceModule::VideoConferenceModule() :
|
||||
_generalSettingsWatcher{ PTSettingsHelper::get_powertoys_general_save_file_location(), [this] {
|
||||
toolbar.scheduleGeneralSettingsUpdate();
|
||||
} },
|
||||
_moduleSettingsWatcher{ PTSettingsHelper::get_module_save_file_location(get_key()), [this] { toolbar.scheduleModuleSettingsUpdate(); } }
|
||||
{
|
||||
init_settings();
|
||||
_settingsUpdateChannel =
|
||||
SerializedSharedMemory::create(CameraSettingsUpdateChannel::endpoint(), sizeof(CameraSettingsUpdateChannel), false);
|
||||
if (_settingsUpdateChannel)
|
||||
{
|
||||
_settingsUpdateChannel->access([](auto memory) {
|
||||
auto updatesChannel = new (memory._data) CameraSettingsUpdateChannel{};
|
||||
});
|
||||
}
|
||||
sendSourceCameraNameUpdate();
|
||||
sendOverlayImageUpdate();
|
||||
}
|
||||
|
||||
inline VideoConferenceModule::~VideoConferenceModule()
|
||||
{
|
||||
instance->unmuteAll();
|
||||
toolbar.hide();
|
||||
}
|
||||
|
||||
const wchar_t* VideoConferenceModule::get_name()
|
||||
{
|
||||
return L"Video Conference";
|
||||
}
|
||||
|
||||
const wchar_t* VideoConferenceModule::get_key()
|
||||
{
|
||||
return L"Video Conference";
|
||||
}
|
||||
|
||||
bool VideoConferenceModule::get_config(wchar_t* buffer, int* buffer_size)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoConferenceModule::set_config(const wchar_t* config)
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
|
||||
values.save_to_settings_file();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG("VideoConferenceModule::set_config: exception during saving new settings values");
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::init_settings()
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerToysSettings::PowerToyValues powerToysSettings = PowerToysSettings::PowerToyValues::load_from_settings_file(L"Video Conference");
|
||||
|
||||
if (const auto val = powerToysSettings.get_json(L"mute_camera_and_microphone_hotkey"))
|
||||
{
|
||||
settings.cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_json(L"mute_microphone_hotkey"))
|
||||
{
|
||||
settings.microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_json(L"mute_camera_hotkey"))
|
||||
{
|
||||
settings.cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_json(*val);
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_string_value(L"toolbar_position"))
|
||||
{
|
||||
settings.toolbarPositionString = val.value();
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_string_value(L"toolbar_monitor"))
|
||||
{
|
||||
settings.toolbarMonitorString = val.value();
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_string_value(L"selected_camera"))
|
||||
{
|
||||
settings.selectedCamera = val.value();
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_string_value(L"camera_overlay_image_path"))
|
||||
{
|
||||
settings.imageOverlayPath = val.value();
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_bool_value(L"hide_toolbar_when_unmuted"))
|
||||
{
|
||||
toolbar.setHideToolbarWhenUnmuted(val.value());
|
||||
}
|
||||
if (const auto val = powerToysSettings.get_string_value(L"selected_mic"); val && *val != settings.selectedMicrophone)
|
||||
{
|
||||
settings.selectedMicrophone = *val;
|
||||
updateControlledMicrophones(settings.selectedMicrophone);
|
||||
}
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
// Error while loading from the settings file. Just let default values stay as they are.
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto loaded = PTSettingsHelper::load_general_settings();
|
||||
std::wstring settings_theme{ static_cast<std::wstring_view>(loaded.GetNamedString(L"theme", L"system")) };
|
||||
if (settings_theme != L"dark" && settings_theme != L"light")
|
||||
{
|
||||
settings_theme = L"system";
|
||||
}
|
||||
toolbar.setTheme(settings_theme);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::updateControlledMicrophones(const std::wstring_view new_mic)
|
||||
{
|
||||
for (auto& controlledMic : _controlledMicrophones)
|
||||
{
|
||||
controlledMic.set_muted(false);
|
||||
}
|
||||
_controlledMicrophones.clear();
|
||||
_microphoneTrackedInUI = nullptr;
|
||||
auto allMics = MicrophoneDevice::getAllActive();
|
||||
if (new_mic == L"[All]")
|
||||
{
|
||||
_controlledMicrophones = std::move(allMics);
|
||||
if (auto defaultMic = MicrophoneDevice::getDefault())
|
||||
{
|
||||
for (auto& controlledMic : _controlledMicrophones)
|
||||
{
|
||||
if (controlledMic.id() == defaultMic->id())
|
||||
{
|
||||
_microphoneTrackedInUI = &controlledMic;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& controlledMic : allMics)
|
||||
{
|
||||
if (controlledMic.name() == new_mic)
|
||||
{
|
||||
_controlledMicrophones.emplace_back(std::move(controlledMic));
|
||||
_microphoneTrackedInUI = &_controlledMicrophones[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_microphoneTrackedInUI)
|
||||
{
|
||||
_microphoneTrackedInUI->set_mute_changed_callback([&](const bool muted) {
|
||||
toolbar.setMicrophoneMute(muted);
|
||||
});
|
||||
toolbar.setMicrophoneMute(_microphoneTrackedInUI->muted());
|
||||
}
|
||||
}
|
||||
|
||||
void toggleProxyCamRegistration(const bool enable)
|
||||
{
|
||||
if (!is_process_elevated())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto vcmRoot = fs::path{ get_module_folderpath() } / "modules";
|
||||
vcmRoot /= "VideoConference";
|
||||
|
||||
std::array<fs::path, 2> proxyFilters = { vcmRoot / "VideoConferenceProxyFilter_x64.dll", vcmRoot / "VideoConferenceProxyFilter_x86.dll" };
|
||||
for (const auto filter : proxyFilters)
|
||||
{
|
||||
std::wstring params{ L"/s " };
|
||||
if (!enable)
|
||||
{
|
||||
params += L"/u ";
|
||||
}
|
||||
params += '"';
|
||||
params += filter;
|
||||
params += '"';
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
|
||||
sei.lpFile = L"regsvr32";
|
||||
sei.lpParameters = params.c_str();
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
ShellExecuteExW(&sei);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::enable()
|
||||
{
|
||||
if (!_enabled)
|
||||
{
|
||||
toggleProxyCamRegistration(true);
|
||||
toolbar.setMicrophoneMute(getMicrophoneMuteState());
|
||||
toolbar.setCameraMute(getVirtualCameraMuteState());
|
||||
|
||||
toolbar.show(settings.toolbarPositionString, settings.toolbarMonitorString);
|
||||
|
||||
_enabled = true;
|
||||
|
||||
#if defined(DISABLE_LOWLEVEL_HOOKS_WHEN_DEBUGGED)
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::unmuteAll()
|
||||
{
|
||||
if (getVirtualCameraMuteState())
|
||||
{
|
||||
reverseVirtualCameraMuteState();
|
||||
}
|
||||
|
||||
if (getMicrophoneMuteState())
|
||||
{
|
||||
reverseMicrophoneMute();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoConferenceModule::disable()
|
||||
{
|
||||
if (_enabled)
|
||||
{
|
||||
toggleProxyCamRegistration(false);
|
||||
if (hook_handle)
|
||||
{
|
||||
bool success = UnhookWindowsHookEx(hook_handle);
|
||||
if (success)
|
||||
{
|
||||
hook_handle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
instance->unmuteAll();
|
||||
toolbar.hide();
|
||||
|
||||
_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool VideoConferenceModule::is_enabled()
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void VideoConferenceModule::destroy()
|
||||
{
|
||||
delete this;
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
void VideoConferenceModule::sendSourceCameraNameUpdate()
|
||||
{
|
||||
if (!_settingsUpdateChannel.has_value() || settings.selectedCamera.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_settingsUpdateChannel->access([](auto memory) {
|
||||
auto updatesChannel = reinterpret_cast<CameraSettingsUpdateChannel*>(memory._data);
|
||||
updatesChannel->sourceCameraName.emplace();
|
||||
std::copy(begin(settings.selectedCamera), end(settings.selectedCamera), begin(*updatesChannel->sourceCameraName));
|
||||
});
|
||||
}
|
||||
|
||||
void VideoConferenceModule::sendOverlayImageUpdate()
|
||||
{
|
||||
if (!_settingsUpdateChannel.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
_imageOverlayChannel.reset();
|
||||
|
||||
wchar_t powertoysDirectory[MAX_PATH + 1];
|
||||
|
||||
DWORD length = GetModuleFileNameW(nullptr, powertoysDirectory, MAX_PATH);
|
||||
PathRemoveFileSpecW(powertoysDirectory);
|
||||
|
||||
std::wstring blankImagePath(powertoysDirectory);
|
||||
blankImagePath += L"\\modules\\VideoConference\\black.bmp";
|
||||
|
||||
_imageOverlayChannel = SerializedSharedMemory::create_readonly(CameraOverlayImageChannel::endpoint(),
|
||||
settings.imageOverlayPath != L"" ? settings.imageOverlayPath : blankImagePath);
|
||||
|
||||
const auto imageSize = static_cast<uint32_t>(_imageOverlayChannel->size());
|
||||
_settingsUpdateChannel->access([imageSize](auto memory) {
|
||||
auto updatesChannel = reinterpret_cast<CameraSettingsUpdateChannel*>(memory._data);
|
||||
updatesChannel->overlayImageSize.emplace(imageSize);
|
||||
updatesChannel->newOverlayImagePosted = true;
|
||||
});
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/SettingsAPI/FileWatcher.h>
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_objects.h>
|
||||
#include <MicrophoneDevice.h>
|
||||
|
||||
#include "Toolbar.h"
|
||||
|
||||
#include <SerializedSharedMemory.h>
|
||||
|
||||
extern class VideoConferenceModule* instance;
|
||||
|
||||
struct VideoConferenceSettings
|
||||
{
|
||||
PowerToysSettings::HotkeyObject cameraAndMicrophoneMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, false, 78);
|
||||
PowerToysSettings::HotkeyObject microphoneMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, true, 65);
|
||||
PowerToysSettings::HotkeyObject cameraMuteHotkey = PowerToysSettings::HotkeyObject::from_settings(true, false, false, true, 79);
|
||||
|
||||
std::wstring toolbarPositionString;
|
||||
std::wstring toolbarMonitorString;
|
||||
|
||||
std::wstring selectedCamera;
|
||||
std::wstring imageOverlayPath;
|
||||
std::wstring selectedMicrophone;
|
||||
};
|
||||
|
||||
class VideoConferenceModule : public PowertoyModuleIface
|
||||
{
|
||||
public:
|
||||
VideoConferenceModule();
|
||||
~VideoConferenceModule();
|
||||
virtual const wchar_t* get_name() override;
|
||||
|
||||
virtual bool get_config(wchar_t* buffer, int* buffer_size) override;
|
||||
|
||||
virtual void set_config(const wchar_t* config) override;
|
||||
|
||||
virtual void enable() override;
|
||||
virtual void disable() override;
|
||||
virtual bool is_enabled() override;
|
||||
virtual void destroy() override;
|
||||
|
||||
virtual const wchar_t * get_key() override;
|
||||
|
||||
void sendSourceCameraNameUpdate();
|
||||
void sendOverlayImageUpdate();
|
||||
|
||||
static void unmuteAll();
|
||||
static void reverseMicrophoneMute();
|
||||
static bool getMicrophoneMuteState();
|
||||
static void reverseVirtualCameraMuteState();
|
||||
static bool getVirtualCameraMuteState();
|
||||
static bool getVirtualCameraInUse();
|
||||
|
||||
void onGeneralSettingsChanged();
|
||||
void onModuleSettingsChanged();
|
||||
private:
|
||||
|
||||
void init_settings();
|
||||
void updateControlledMicrophones(const std::wstring_view new_mic);
|
||||
// all callback methods and used by callback have to be static
|
||||
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
|
||||
static bool isKeyPressed(unsigned int keyCode);
|
||||
static bool isHotkeyPressed(DWORD code, PowerToysSettings::HotkeyObject& hotkey);
|
||||
|
||||
static HHOOK hook_handle;
|
||||
bool _enabled = false;
|
||||
|
||||
std::vector<MicrophoneDevice> _controlledMicrophones;
|
||||
MicrophoneDevice* _microphoneTrackedInUI = nullptr;
|
||||
|
||||
std::optional<SerializedSharedMemory> _imageOverlayChannel;
|
||||
std::optional<SerializedSharedMemory> _settingsUpdateChannel;
|
||||
|
||||
FileWatcher _generalSettingsWatcher;
|
||||
FileWatcher _moduleSettingsWatcher;
|
||||
|
||||
static VideoConferenceSettings settings;
|
||||
static Toolbar toolbar;
|
||||
};
|
BIN
src/modules/videoconference/VideoConferenceModule/black.bmp
Normal file
After Width: | Height: | Size: 822 B |
@ -0,0 +1,35 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
#include <interface/powertoy_module_interface.h>
|
||||
#include "trace.h"
|
||||
#include "VideoConferenceModule.h"
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
Trace::RegisterProvider();
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
Trace::UnregisterProvider();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||
{
|
||||
if (!instance)
|
||||
{
|
||||
instance = new VideoConferenceModule();
|
||||
return instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
|
||||
</packages>
|
@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
24
src/modules/videoconference/VideoConferenceModule/pch.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <Unknwn.h>
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <wil/com.h>
|
||||
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
||||
#include <Shobjidl.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#include <common/Telemetry/ProjectTelemetry.h>
|
57
src/modules/videoconference/VideoConferenceModule/trace.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
"Microsoft.PowerToys",
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::RegisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::UnregisterProvider() noexcept
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::SettingsChanged(const struct VideoConferenceSettings& settings) noexcept
|
||||
{
|
||||
bool CustomOverlayImage = (settings.imageOverlayPath.length() > 0);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"VideoConference_SettingsChanged",
|
||||
TraceLoggingWideString(settings.toolbarPositionString.c_str(), "ToolbarPosition"),
|
||||
TraceLoggingWideString(settings.toolbarMonitorString.c_str(), "ToolbarMonitorSelection"),
|
||||
TraceLoggingBool(CustomOverlayImage, "CustomImageOverlayUsed"),
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::MicrophoneMuted() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"VideoConference_MicrophoneMuted",
|
||||
TraceLoggingBoolean(true, "MicrophoneMuted"),
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
void Trace::CameraMuted() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"VideoConference_CameraMuted",
|
||||
TraceLoggingBoolean(true, "CameraMuted"),
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
12
src/modules/videoconference/VideoConferenceModule/trace.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "VideoConferenceModule.h"
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider() noexcept;
|
||||
static void UnregisterProvider() noexcept;
|
||||
static void SettingsChanged(const struct VideoConferenceSettings &settings) noexcept;
|
||||
static void MicrophoneMuted() noexcept;
|
||||
static void CameraMuted() noexcept;
|
||||
};
|
@ -0,0 +1,118 @@
|
||||
#include "DirectShowUtils.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
unique_media_type_ptr CopyMediaType(const AM_MEDIA_TYPE* source)
|
||||
{
|
||||
unique_media_type_ptr target{ static_cast<AM_MEDIA_TYPE*>(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))) };
|
||||
*target = *source;
|
||||
if (source->cbFormat)
|
||||
{
|
||||
target->pbFormat = static_cast<BYTE*>(CoTaskMemAlloc(source->cbFormat));
|
||||
std::copy(source->pbFormat, source->pbFormat + source->cbFormat, target->pbFormat);
|
||||
}
|
||||
|
||||
if (target->pUnk)
|
||||
{
|
||||
target->pUnk->AddRef();
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMemAllocator> GetPinAllocator(wil::com_ptr_nothrow<IPin>& inputPin)
|
||||
{
|
||||
if (!inputPin)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
wil::com_ptr_nothrow<IMemAllocator> allocator;
|
||||
if (auto memInput = inputPin.try_query<IMemInputPin>(); memInput)
|
||||
{
|
||||
memInput->GetAllocator(&allocator);
|
||||
return allocator;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unique_media_type_ptr CopyMediaType(const unique_media_type_ptr& source)
|
||||
{
|
||||
return CopyMediaType(source.get());
|
||||
}
|
||||
|
||||
void MyFreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0)
|
||||
{
|
||||
CoTaskMemFree(mt.pbFormat);
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = nullptr;
|
||||
}
|
||||
|
||||
if (mt.pUnk != nullptr)
|
||||
{
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void MyDeleteMediaType(AM_MEDIA_TYPE* pmt)
|
||||
{
|
||||
if (!pmt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MyFreeMediaType(*pmt);
|
||||
CoTaskMemFree(const_cast<AM_MEDIA_TYPE*>(pmt));
|
||||
}
|
||||
|
||||
HRESULT MediaTypeEnumerator::Next(ULONG cObjects, AM_MEDIA_TYPE** outObjects, ULONG* pcFetched)
|
||||
{
|
||||
if (!outObjects)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
ULONG fetched = 0;
|
||||
ULONG toFetch = cObjects;
|
||||
while (toFetch-- && _pos < _objects.size())
|
||||
{
|
||||
auto copy = CopyMediaType(_objects[_pos++]);
|
||||
outObjects[fetched++] = copy.release();
|
||||
}
|
||||
|
||||
if (pcFetched)
|
||||
{
|
||||
*pcFetched = fetched;
|
||||
}
|
||||
|
||||
return fetched == cObjects ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT MediaTypeEnumerator::Skip(ULONG cObjects)
|
||||
{
|
||||
_pos += cObjects;
|
||||
return _pos < _objects.size() ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT MediaTypeEnumerator::Reset()
|
||||
{
|
||||
_pos = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT MediaTypeEnumerator::Clone(IEnumMediaTypes** ppEnum)
|
||||
{
|
||||
auto cloned = winrt::make_self<MediaTypeEnumerator>();
|
||||
cloned->_objects.resize(_objects.size());
|
||||
for (size_t i = 0; i < _objects.size(); ++i)
|
||||
{
|
||||
cloned->_objects[i] = CopyMediaType(_objects[i]);
|
||||
}
|
||||
|
||||
cloned->_pos = _pos;
|
||||
cloned.as<IEnumMediaTypes>().copy_to(ppEnum);
|
||||
return S_OK;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <initguid.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <dshow.h>
|
||||
|
||||
#include <wil/com.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
void MyDeleteMediaType(AM_MEDIA_TYPE* pmt);
|
||||
|
||||
using unique_media_type_ptr =
|
||||
wistd::unique_ptr<AM_MEDIA_TYPE, wil::function_deleter<decltype(&MyDeleteMediaType), MyDeleteMediaType>>;
|
||||
|
||||
unique_media_type_ptr CopyMediaType(const unique_media_type_ptr& source);
|
||||
unique_media_type_ptr CopyMediaType(const AM_MEDIA_TYPE* source);
|
||||
|
||||
template<typename ObjectInterface, typename EnumeratorInterface>
|
||||
struct ObjectEnumerator : public winrt::implements<ObjectEnumerator<ObjectInterface, EnumeratorInterface>, EnumeratorInterface>
|
||||
{
|
||||
std::vector<wil::com_ptr_nothrow<ObjectInterface>> _objects;
|
||||
ULONG _pos = 0;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Next(ULONG cObjects, ObjectInterface** outObjects, ULONG* pcFetched) override
|
||||
{
|
||||
if (!outObjects)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
ULONG fetched = 0;
|
||||
ULONG toFetch = cObjects;
|
||||
while (toFetch-- && _pos < _objects.size())
|
||||
{
|
||||
_objects[_pos++].copy_to(&outObjects[fetched++]);
|
||||
}
|
||||
|
||||
if (pcFetched)
|
||||
{
|
||||
*pcFetched = fetched;
|
||||
}
|
||||
|
||||
return fetched == cObjects ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Skip(ULONG cObjects) override
|
||||
{
|
||||
_pos += cObjects;
|
||||
return _pos < _objects.size() ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Reset() override
|
||||
{
|
||||
_pos = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Clone(EnumeratorInterface** ppEnum) override
|
||||
{
|
||||
auto cloned = winrt::make_self<ObjectEnumerator>();
|
||||
cloned->_objects = _objects;
|
||||
cloned->_pos = _pos;
|
||||
cloned.as<EnumeratorInterface>().copy_to(ppEnum);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual ~ObjectEnumerator() = default;
|
||||
};
|
||||
|
||||
struct MediaTypeEnumerator : public winrt::implements<MediaTypeEnumerator, IEnumMediaTypes>
|
||||
{
|
||||
std::vector<unique_media_type_ptr> _objects;
|
||||
ULONG _pos = 0;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Next(ULONG cObjects, AM_MEDIA_TYPE** outObjects, ULONG* pcFetched) override;
|
||||
HRESULT STDMETHODCALLTYPE Skip(ULONG cObjects) override;
|
||||
HRESULT STDMETHODCALLTYPE Reset() override;
|
||||
HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes** ppEnum) override;
|
||||
|
||||
virtual ~MediaTypeEnumerator() = default;
|
||||
};
|
||||
|
||||
wil::com_ptr_nothrow<IMemAllocator> GetPinAllocator(wil::com_ptr_nothrow<IPin>& inputPin);
|
@ -0,0 +1,425 @@
|
||||
#include <initguid.h>
|
||||
|
||||
#include <dxgiformat.h>
|
||||
#include <assert.h>
|
||||
#include <winrt/base.h>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#include <wincodec.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <memory>
|
||||
#include <mfapi.h>
|
||||
#include <shcore.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <wil/com.h>
|
||||
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <mftransform.h>
|
||||
#include <dshow.h>
|
||||
#include <Wincodecsdk.h>
|
||||
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
IWICImagingFactory* _GetWIC() noexcept
|
||||
{
|
||||
static IWICImagingFactory* s_Factory = nullptr;
|
||||
|
||||
if (s_Factory)
|
||||
{
|
||||
return s_Factory;
|
||||
}
|
||||
|
||||
OK_OR_BAIL(CoCreateInstance(
|
||||
CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), (LPVOID*)&s_Factory));
|
||||
|
||||
return s_Factory;
|
||||
}
|
||||
|
||||
bool ReencodeJPGImage(BYTE* imageBuf, const DWORD imageSize, DWORD& reencodedSize)
|
||||
{
|
||||
auto pWIC = _GetWIC();
|
||||
wil::com_ptr_nothrow<IStream> imageStream = SHCreateMemStream(imageBuf, imageSize);
|
||||
if (!imageStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode jpg into bitmap
|
||||
wil::com_ptr_nothrow<IWICBitmapDecoder> bitmapDecoder;
|
||||
OK_OR_BAIL(pWIC->CreateDecoderFromStream(imageStream.get(), nullptr, WICDecodeMetadataCacheOnLoad, &bitmapDecoder));
|
||||
wil::com_ptr_nothrow<IWICBitmapFrameDecode> decodedFrame;
|
||||
OK_OR_BAIL(bitmapDecoder->GetFrame(0, &decodedFrame));
|
||||
wil::com_ptr_nothrow<IWICBitmapSource> bitmap;
|
||||
bitmap.attach(decodedFrame.detach());
|
||||
UINT width = 0, height = 0;
|
||||
OK_OR_BAIL(bitmap->GetSize(&width, &height));
|
||||
|
||||
// Initialize jpg encoder
|
||||
wil::com_ptr_nothrow<IWICBitmapEncoder> encoder;
|
||||
OK_OR_BAIL(pWIC->CreateEncoder(GUID_ContainerFormatJpeg, nullptr, &encoder));
|
||||
|
||||
wil::com_ptr_nothrow<IStream> outputStream;
|
||||
OK_OR_BAIL(CreateStreamOnHGlobal(nullptr, true, &outputStream));
|
||||
OK_OR_BAIL(encoder->Initialize(outputStream.get(), WICBitmapEncoderNoCache));
|
||||
wil::com_ptr_nothrow<IWICBitmapFrameEncode> encodedFrame;
|
||||
wil::com_ptr_nothrow<IPropertyBag2> encoderOptions;
|
||||
OK_OR_BAIL(encoder->CreateNewFrame(&encodedFrame, &encoderOptions));
|
||||
|
||||
ULONG nProperties = 0;
|
||||
OK_OR_BAIL(encoderOptions->CountProperties(&nProperties));
|
||||
for (ULONG propIdx = 0; propIdx < nProperties; ++propIdx)
|
||||
{
|
||||
PROPBAG2 propBag{};
|
||||
ULONG _;
|
||||
OK_OR_BAIL(encoderOptions->GetPropertyInfo(propIdx, 1, &propBag, &_));
|
||||
if (propBag.pstrName == std::wstring_view{ L"ImageQuality" })
|
||||
{
|
||||
wil::unique_variant variant;
|
||||
variant.vt = VT_R4;
|
||||
variant.fltVal = 0.1f;
|
||||
OK_OR_BAIL(encoderOptions->Write(1, &propBag, &variant));
|
||||
LOG("Successfully set jpg compression quality");
|
||||
// skip the rest of the properties
|
||||
propIdx = nProperties;
|
||||
}
|
||||
CoTaskMemFree(propBag.pstrName);
|
||||
}
|
||||
|
||||
OK_OR_BAIL(encodedFrame->Initialize(encoderOptions.get()));
|
||||
WICPixelFormatGUID intermediateFormat = GUID_WICPixelFormat24bppRGB;
|
||||
|
||||
OK_OR_BAIL(encodedFrame->SetPixelFormat(&intermediateFormat));
|
||||
OK_OR_BAIL(encodedFrame->SetSize(width, height));
|
||||
|
||||
// Commit the image encoding
|
||||
OK_OR_BAIL(encodedFrame->WriteSource(bitmap.get(), nullptr));
|
||||
OK_OR_BAIL(encodedFrame->Commit());
|
||||
OK_OR_BAIL(encoder->Commit());
|
||||
|
||||
STATSTG intermediateStreamStat{};
|
||||
OK_OR_BAIL(outputStream->Stat(&intermediateStreamStat, STATFLAG_NONAME));
|
||||
const ULONGLONG jpgStreamSize = intermediateStreamStat.cbSize.QuadPart;
|
||||
HGLOBAL streamMemoryHandle{};
|
||||
OK_OR_BAIL(GetHGlobalFromStream(outputStream.get(), &streamMemoryHandle));
|
||||
|
||||
auto jpgStreamMemory = static_cast<uint8_t*>(GlobalLock(streamMemoryHandle));
|
||||
std::copy(jpgStreamMemory, jpgStreamMemory + jpgStreamSize, imageBuf);
|
||||
auto unlockJpgStreamMemory = wil::scope_exit([jpgStreamMemory] { GlobalUnlock(jpgStreamMemory); });
|
||||
reencodedSize = (DWORD)jpgStreamSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IWICBitmapSource> LoadAsRGB24BitmapWithSize(IWICImagingFactory* pWIC,
|
||||
wil::com_ptr_nothrow<IStream> image,
|
||||
const UINT targetWidth,
|
||||
const UINT targetHeight)
|
||||
{
|
||||
wil::com_ptr_nothrow<IWICBitmapSource> bitmap;
|
||||
// Initialize image bitmap decoder from filename and get the image frame
|
||||
wil::com_ptr_nothrow<IWICBitmapDecoder> bitmapDecoder;
|
||||
OK_OR_BAIL(pWIC->CreateDecoderFromStream(image.get(), nullptr, WICDecodeMetadataCacheOnLoad, &bitmapDecoder));
|
||||
|
||||
wil::com_ptr_nothrow<IWICBitmapFrameDecode> decodedFrame;
|
||||
OK_OR_BAIL(bitmapDecoder->GetFrame(0, &decodedFrame));
|
||||
|
||||
UINT imageWidth = 0, imageHeight = 0;
|
||||
OK_OR_BAIL(decodedFrame->GetSize(&imageWidth, &imageHeight));
|
||||
|
||||
// Scale the image if required
|
||||
if (targetWidth != imageWidth || targetHeight != imageHeight)
|
||||
{
|
||||
wil::com_ptr_nothrow<IWICBitmapScaler> scaler;
|
||||
OK_OR_BAIL(pWIC->CreateBitmapScaler(&scaler));
|
||||
OK_OR_BAIL(
|
||||
scaler->Initialize(decodedFrame.get(), targetWidth, targetHeight, WICBitmapInterpolationModeHighQualityCubic));
|
||||
bitmap.attach(scaler.detach());
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap.attach(decodedFrame.detach());
|
||||
}
|
||||
WICPixelFormatGUID pixelFormat{};
|
||||
OK_OR_BAIL(bitmap->GetPixelFormat(&pixelFormat));
|
||||
|
||||
const auto targetPixelFormat = GUID_WICPixelFormat24bppBGR;
|
||||
if (pixelFormat != targetPixelFormat)
|
||||
{
|
||||
wil::com_ptr_nothrow<IWICBitmapSource> convertedBitmap;
|
||||
if (SUCCEEDED(WICConvertBitmapSource(targetPixelFormat, bitmap.get(), &convertedBitmap)))
|
||||
{
|
||||
return convertedBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IStream> EncodeBitmapToContainer(IWICImagingFactory* pWIC,
|
||||
wil::com_ptr_nothrow<IWICBitmapSource> bitmap,
|
||||
const GUID& containerGUID,
|
||||
const UINT width,
|
||||
const UINT height,
|
||||
const float quality)
|
||||
{
|
||||
wil::com_ptr_nothrow<IWICBitmapEncoder> encoder;
|
||||
pWIC->CreateEncoder(containerGUID, nullptr, &encoder);
|
||||
|
||||
if (!encoder)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prepare the encoder output memory stream and encoding params
|
||||
wil::com_ptr_nothrow<IStream> encodedBitmap;
|
||||
OK_OR_BAIL(CreateStreamOnHGlobal(nullptr, true, &encodedBitmap));
|
||||
OK_OR_BAIL(encoder->Initialize(encodedBitmap.get(), WICBitmapEncoderNoCache));
|
||||
wil::com_ptr_nothrow<IWICBitmapFrameEncode> encodedFrame;
|
||||
|
||||
wil::com_ptr_nothrow<IPropertyBag2> encoderOptions;
|
||||
OK_OR_BAIL(encoder->CreateNewFrame(&encodedFrame, &encoderOptions));
|
||||
|
||||
ULONG nProperties = 0;
|
||||
OK_OR_BAIL(encoderOptions->CountProperties(&nProperties));
|
||||
for (ULONG propIdx = 0; propIdx < nProperties; ++propIdx)
|
||||
{
|
||||
PROPBAG2 propBag{};
|
||||
ULONG _;
|
||||
OK_OR_BAIL(encoderOptions->GetPropertyInfo(propIdx, 1, &propBag, &_));
|
||||
if (propBag.pstrName == std::wstring_view{ L"ImageQuality" })
|
||||
{
|
||||
wil::unique_variant variant;
|
||||
variant.vt = VT_R4;
|
||||
variant.fltVal = quality;
|
||||
OK_OR_BAIL(encoderOptions->Write(1, &propBag, &variant));
|
||||
LOG("Successfully set jpg compression quality");
|
||||
// skip the rest of the properties
|
||||
propIdx = nProperties;
|
||||
}
|
||||
CoTaskMemFree(propBag.pstrName);
|
||||
}
|
||||
|
||||
OK_OR_BAIL(encodedFrame->Initialize(encoderOptions.get()));
|
||||
|
||||
WICPixelFormatGUID intermediateFormat = GUID_WICPixelFormat24bppRGB;
|
||||
OK_OR_BAIL(encodedFrame->SetPixelFormat(&intermediateFormat));
|
||||
OK_OR_BAIL(encodedFrame->SetSize(width, height));
|
||||
|
||||
// Commit the image encoding
|
||||
OK_OR_BAIL(encodedFrame->WriteSource(bitmap.get(), nullptr));
|
||||
OK_OR_BAIL(encodedFrame->Commit());
|
||||
OK_OR_BAIL(encoder->Commit());
|
||||
return encodedBitmap;
|
||||
}
|
||||
|
||||
IMFSample* ConvertIMFVideoSample(const MFT_REGISTER_TYPE_INFO& inputType,
|
||||
IMFMediaType* outputMediaType,
|
||||
const wil::com_ptr_nothrow<IMFSample>& inputSample,
|
||||
const UINT width,
|
||||
const UINT height)
|
||||
{
|
||||
IMFActivate** ppVDActivate = nullptr;
|
||||
UINT32 count = 0;
|
||||
|
||||
MFT_REGISTER_TYPE_INFO outputType = { MFMediaType_Video, {} };
|
||||
outputMediaType->GetGUID(MF_MT_SUBTYPE, &outputType.guidSubtype);
|
||||
|
||||
const std::array<GUID, 3> transformerCategories = {
|
||||
MFT_CATEGORY_VIDEO_PROCESSOR, MFT_CATEGORY_VIDEO_DECODER, MFT_CATEGORY_VIDEO_ENCODER
|
||||
};
|
||||
|
||||
for (const auto& transformerCategory : transformerCategories)
|
||||
{
|
||||
OK_OR_BAIL(MFTEnumEx(transformerCategory, MFT_ENUM_FLAG_SYNCMFT, &inputType, &outputType, &ppVDActivate, &count));
|
||||
if (count != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMFTransform> videoTransformer;
|
||||
|
||||
bool videoDecoderActivated = false;
|
||||
for (UINT32 i = 0; i < count; ++i)
|
||||
{
|
||||
if (!videoDecoderActivated && !FAILED(ppVDActivate[i]->ActivateObject(IID_PPV_ARGS(&videoTransformer))))
|
||||
{
|
||||
videoDecoderActivated = true;
|
||||
}
|
||||
ppVDActivate[i]->Release();
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
CoTaskMemFree(ppVDActivate);
|
||||
}
|
||||
|
||||
if (!videoDecoderActivated)
|
||||
{
|
||||
LOG("No converter avialable for the selected format");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto shutdownVideoDecoder = wil::scope_exit([&videoTransformer] { MFShutdownObject(videoTransformer.get()); });
|
||||
// Set input/output types for the decoder
|
||||
wil::com_ptr_nothrow<IMFMediaType> intermediateFrameMediaType;
|
||||
OK_OR_BAIL(MFCreateMediaType(&intermediateFrameMediaType));
|
||||
intermediateFrameMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
||||
intermediateFrameMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24);
|
||||
intermediateFrameMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
|
||||
intermediateFrameMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
|
||||
OK_OR_BAIL(MFSetAttributeSize(intermediateFrameMediaType.get(), MF_MT_FRAME_SIZE, width, height));
|
||||
OK_OR_BAIL(MFSetAttributeRatio(intermediateFrameMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, width, height));
|
||||
OK_OR_BAIL(videoTransformer->SetInputType(0, intermediateFrameMediaType.get(), 0));
|
||||
OK_OR_BAIL(videoTransformer->SetOutputType(0, outputMediaType, 0));
|
||||
|
||||
// Process the input sample
|
||||
OK_OR_BAIL(videoTransformer->ProcessInput(0, inputSample.get(), 0));
|
||||
|
||||
// Check whether we need to allocate output sample and buffer ourselves
|
||||
MFT_OUTPUT_STREAM_INFO outputStreamInfo{};
|
||||
OK_OR_BAIL(videoTransformer->GetOutputStreamInfo(0, &outputStreamInfo));
|
||||
const bool onlyProvidesSamples = outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
|
||||
const bool canProvideSamples = outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES;
|
||||
const bool mustAllocateSample =
|
||||
(!onlyProvidesSamples && !canProvideSamples) ||
|
||||
(!onlyProvidesSamples && (outputStreamInfo.dwFlags & MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER));
|
||||
|
||||
MFT_OUTPUT_DATA_BUFFER outputSamples{};
|
||||
IMFSample* outputSample = nullptr;
|
||||
|
||||
// If so, do the allocation
|
||||
if (mustAllocateSample)
|
||||
{
|
||||
OK_OR_BAIL(MFCreateSample(&outputSample));
|
||||
OK_OR_BAIL(outputSample->SetSampleDuration(333333));
|
||||
OK_OR_BAIL(outputSample->SetSampleTime(1));
|
||||
OK_OR_BAIL(outputSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
|
||||
IMFMediaBuffer* outputMediaBuffer = nullptr;
|
||||
OK_OR_BAIL(
|
||||
MFCreateAlignedMemoryBuffer(outputStreamInfo.cbSize, outputStreamInfo.cbAlignment - 1, &outputMediaBuffer));
|
||||
OK_OR_BAIL(outputMediaBuffer->SetCurrentLength(outputStreamInfo.cbSize));
|
||||
OK_OR_BAIL(outputSample->AddBuffer(outputMediaBuffer));
|
||||
outputSamples.pSample = outputSample;
|
||||
}
|
||||
|
||||
// Finally, produce the output sample
|
||||
DWORD processStatus = 0;
|
||||
if (failed(videoTransformer->ProcessOutput(0, 1, &outputSamples, &processStatus)))
|
||||
{
|
||||
LOG("Failed to convert image frame");
|
||||
}
|
||||
if (outputSamples.pEvents)
|
||||
{
|
||||
outputSamples.pEvents->Release();
|
||||
}
|
||||
|
||||
return outputSamples.pSample;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMFSample> LoadImageAsSample(wil::com_ptr_nothrow<IStream> imageStream,
|
||||
IMFMediaType* sampleMediaType,
|
||||
const float quality) noexcept
|
||||
{
|
||||
UINT targetWidth = 0;
|
||||
UINT targetHeight = 0;
|
||||
OK_OR_BAIL(MFGetAttributeSize(sampleMediaType, MF_MT_FRAME_SIZE, &targetWidth, &targetHeight));
|
||||
MFT_REGISTER_TYPE_INFO outputType = { MFMediaType_Video, {} };
|
||||
OK_OR_BAIL(sampleMediaType->GetGUID(MF_MT_SUBTYPE, &outputType.guidSubtype));
|
||||
|
||||
IWICImagingFactory* pWIC = _GetWIC();
|
||||
if (!pWIC)
|
||||
{
|
||||
LOG("Failed to create IWICImagingFactory");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!imageStream)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto srcImageBitmap = LoadAsRGB24BitmapWithSize(pWIC, imageStream, targetWidth, targetHeight);
|
||||
if (!srcImageBitmap)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// First, let's create a sample containing RGB24 bitmap
|
||||
IMFSample* outputSample = nullptr;
|
||||
OK_OR_BAIL(MFCreateSample(&outputSample));
|
||||
OK_OR_BAIL(outputSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
|
||||
OK_OR_BAIL(outputSample->SetSampleDuration(333333));
|
||||
OK_OR_BAIL(outputSample->SetSampleTime(1));
|
||||
IMFMediaBuffer* outputMediaBuffer = nullptr;
|
||||
const DWORD nPixelBytes = targetWidth * targetHeight * 3;
|
||||
OK_OR_BAIL(MFCreateAlignedMemoryBuffer(nPixelBytes, MF_64_BYTE_ALIGNMENT, &outputMediaBuffer));
|
||||
|
||||
const UINT stride = 3 * targetWidth;
|
||||
|
||||
DWORD max_length = 0, current_length = 0;
|
||||
BYTE* sampleBufferMemory = nullptr;
|
||||
OK_OR_BAIL(outputMediaBuffer->Lock(&sampleBufferMemory, &max_length, ¤t_length));
|
||||
OK_OR_BAIL(srcImageBitmap->CopyPixels(nullptr, stride, nPixelBytes, sampleBufferMemory));
|
||||
OK_OR_BAIL(outputMediaBuffer->Unlock());
|
||||
|
||||
OK_OR_BAIL(outputMediaBuffer->SetCurrentLength(nPixelBytes));
|
||||
OK_OR_BAIL(outputSample->AddBuffer(outputMediaBuffer));
|
||||
|
||||
if (outputType.guidSubtype == MFVideoFormat_RGB24)
|
||||
{
|
||||
return outputSample;
|
||||
}
|
||||
|
||||
// Special case for mjpg, since we need to use jpg container for it instead of supplying raw pixels
|
||||
if (outputType.guidSubtype == MFVideoFormat_MJPG)
|
||||
{
|
||||
// Use an intermediate jpg container sample which will be transcoded to the target format
|
||||
wil::com_ptr_nothrow<IStream> jpgStream =
|
||||
EncodeBitmapToContainer(pWIC, srcImageBitmap, GUID_ContainerFormatJpeg, targetWidth, targetHeight, quality);
|
||||
|
||||
// Obtain stream size and lock its memory pointer
|
||||
STATSTG intermediateStreamStat{};
|
||||
OK_OR_BAIL(jpgStream->Stat(&intermediateStreamStat, STATFLAG_NONAME));
|
||||
const ULONGLONG jpgStreamSize = intermediateStreamStat.cbSize.QuadPart;
|
||||
HGLOBAL streamMemoryHandle{};
|
||||
OK_OR_BAIL(GetHGlobalFromStream(jpgStream.get(), &streamMemoryHandle));
|
||||
|
||||
auto jpgStreamMemory = static_cast<uint8_t*>(GlobalLock(streamMemoryHandle));
|
||||
auto unlockJpgStreamMemory = wil::scope_exit([jpgStreamMemory] { GlobalUnlock(jpgStreamMemory); });
|
||||
|
||||
// Create a sample from the input image buffer
|
||||
wil::com_ptr_nothrow<IMFSample> jpgSample;
|
||||
OK_OR_BAIL(MFCreateSample(&jpgSample));
|
||||
OK_OR_BAIL(jpgSample->SetUINT32(MF_MT_VIDEO_ROTATION, MFVideoRotationFormat::MFVideoRotationFormat_0));
|
||||
IMFMediaBuffer* inputMediaBuffer = nullptr;
|
||||
OK_OR_BAIL(MFCreateAlignedMemoryBuffer(static_cast<DWORD>(jpgStreamSize), MF_64_BYTE_ALIGNMENT, &inputMediaBuffer));
|
||||
BYTE* inputBuf = nullptr;
|
||||
OK_OR_BAIL(inputMediaBuffer->Lock(&inputBuf, &max_length, ¤t_length));
|
||||
if (max_length < jpgStreamSize)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::copy(jpgStreamMemory, jpgStreamMemory + jpgStreamSize, inputBuf);
|
||||
unlockJpgStreamMemory.reset();
|
||||
OK_OR_BAIL(inputMediaBuffer->Unlock());
|
||||
OK_OR_BAIL(inputMediaBuffer->SetCurrentLength(static_cast<DWORD>(jpgStreamSize)));
|
||||
OK_OR_BAIL(jpgSample->AddBuffer(inputMediaBuffer));
|
||||
|
||||
return jpgSample;
|
||||
}
|
||||
|
||||
// Now we are ready to convert it to the requested media type
|
||||
MFT_REGISTER_TYPE_INFO intermediateType = { MFMediaType_Video, MFVideoFormat_RGB24 };
|
||||
|
||||
// But if no conversion is needed, just return the input sample
|
||||
|
||||
return ConvertIMFVideoSample(intermediateType, sampleMediaType, outputSample, targetWidth, targetHeight);
|
||||
}
|
@ -0,0 +1,634 @@
|
||||
#include "Logging.h"
|
||||
#include "VideoCaptureDevice.h"
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <cguid.h>
|
||||
|
||||
struct VideoCaptureReceiverFilter : winrt::implements<VideoCaptureReceiverFilter, IBaseFilter, IAMFilterMiscFlags>
|
||||
{
|
||||
FILTER_STATE _state = State_Stopped;
|
||||
IFilterGraph* _graph = nullptr;
|
||||
wil::com_ptr_nothrow<IPin> _videoReceiverPin;
|
||||
|
||||
ULONG STDMETHODCALLTYPE GetMiscFlags() override { return AM_FILTER_MISC_FLAGS_IS_RENDERER; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetClassID(CLSID*) override { return E_NOTIMPL; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Stop() override
|
||||
{
|
||||
_state = State_Stopped;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Pause() override
|
||||
{
|
||||
_state = State_Paused;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME) override
|
||||
{
|
||||
_state = State_Running;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetState(DWORD, FILTER_STATE* outState) override
|
||||
{
|
||||
*outState = _state;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock** outRefClock) override
|
||||
{
|
||||
*outRefClock = nullptr;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock*) override { return S_OK; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins** ppEnum) override
|
||||
{
|
||||
auto enumerator = winrt::make_self<ObjectEnumerator<IPin, IEnumPins>>();
|
||||
enumerator->_objects.emplace_back(_videoReceiverPin);
|
||||
*ppEnum = enumerator.detach();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR, IPin**) override { return E_NOTIMPL; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR) override
|
||||
{
|
||||
_graph = pGraph;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO* pInfo) override
|
||||
{
|
||||
std::copy(std::begin(NAME), std::end(NAME), pInfo->achName);
|
||||
if (_graph)
|
||||
{
|
||||
pInfo->pGraph = _graph;
|
||||
_graph->AddRef();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR* pVendorInfo) override
|
||||
{
|
||||
auto info = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(VENDOR)));
|
||||
std::copy(std::begin(VENDOR), std::end(VENDOR), info);
|
||||
*pVendorInfo = info;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual ~VideoCaptureReceiverFilter() = default;
|
||||
|
||||
constexpr static inline wchar_t NAME[] = L"PowerToysVCMCaptureFilter";
|
||||
constexpr static inline wchar_t VENDOR[] = L"Microsoft Corporation";
|
||||
};
|
||||
|
||||
struct VideoCaptureReceiverPin : winrt::implements<VideoCaptureReceiverPin, IPin, IMemInputPin>
|
||||
{
|
||||
VideoCaptureReceiverFilter* _owningFilter = nullptr;
|
||||
unique_media_type_ptr _expectedMediaType;
|
||||
wil::com_ptr_nothrow<IPin> _captureInputPin;
|
||||
unique_media_type_ptr _inputCaptureMediaType;
|
||||
std::atomic_bool _flushing = false;
|
||||
VideoCaptureDevice::callback_t _frameCallback;
|
||||
|
||||
wil::com_ptr_nothrow<IMemAllocator> _allocator;
|
||||
|
||||
VideoCaptureReceiverPin(unique_media_type_ptr mediaType, VideoCaptureReceiverFilter* filter) :
|
||||
_expectedMediaType{ std::move(mediaType) }, _owningFilter{ filter }
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Connect(IPin*, const AM_MEDIA_TYPE* pmt) override
|
||||
{
|
||||
if (_owningFilter->_state == State_Running)
|
||||
{
|
||||
return VFW_E_NOT_STOPPED;
|
||||
}
|
||||
|
||||
if (_captureInputPin)
|
||||
{
|
||||
return VFW_E_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
if (!pmt || pmt->majortype == GUID_NULL)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (pmt->majortype != _expectedMediaType->majortype || pmt->subtype != _expectedMediaType->subtype)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) override
|
||||
{
|
||||
if (!pConnector || !pmt)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (_captureInputPin)
|
||||
{
|
||||
return VFW_E_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
if (_owningFilter->_state != State_Stopped)
|
||||
{
|
||||
return VFW_E_NOT_STOPPED;
|
||||
}
|
||||
|
||||
if (QueryAccept(pmt) != S_OK)
|
||||
{
|
||||
return VFW_E_TYPE_NOT_ACCEPTED;
|
||||
}
|
||||
|
||||
_captureInputPin = pConnector;
|
||||
_inputCaptureMediaType = CopyMediaType(pmt);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Disconnect() override
|
||||
{
|
||||
_allocator.reset();
|
||||
_captureInputPin.reset();
|
||||
_inputCaptureMediaType.reset();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ConnectedTo(IPin** pPin) override
|
||||
{
|
||||
if (!_captureInputPin)
|
||||
{
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
_captureInputPin.copy_to(pPin);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE* pmt) override
|
||||
{
|
||||
if (!pmt)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (!_inputCaptureMediaType)
|
||||
{
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
*pmt = *CopyMediaType(_inputCaptureMediaType).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO* pInfo) override
|
||||
{
|
||||
if (!pInfo)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
pInfo->pFilter = _owningFilter;
|
||||
if (_owningFilter)
|
||||
{
|
||||
_owningFilter->AddRef();
|
||||
}
|
||||
|
||||
pInfo->dir = PINDIR_INPUT;
|
||||
std::copy(std::begin(NAME), std::end(NAME), pInfo->achName);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION* pPinDir) override
|
||||
{
|
||||
if (!pPinDir)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*pPinDir = PINDIR_INPUT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryId(LPWSTR* lpId) override
|
||||
{
|
||||
if (!lpId)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*lpId = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(NAME)));
|
||||
|
||||
std::copy(std::begin(NAME), std::end(NAME), *lpId);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE* pmt) override
|
||||
{
|
||||
if (!pmt)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (pmt->majortype != _expectedMediaType->majortype || pmt->subtype != _expectedMediaType->subtype)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (_captureInputPin)
|
||||
{
|
||||
_inputCaptureMediaType.reset(const_cast<AM_MEDIA_TYPE*>(pmt));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes** ppEnum) override
|
||||
{
|
||||
if (!ppEnum)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
auto enumerator = winrt::make_self<MediaTypeEnumerator>();
|
||||
enumerator->_objects.emplace_back(CopyMediaType(_expectedMediaType));
|
||||
*ppEnum = enumerator.detach();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin**, ULONG*) override { return E_NOTIMPL; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EndOfStream() override { return S_OK; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE BeginFlush() override
|
||||
{
|
||||
_flushing = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EndFlush() override
|
||||
{
|
||||
_flushing = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME, REFERENCE_TIME, double) override { return S_OK; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator** allocator) override
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
if (!_allocator)
|
||||
{
|
||||
return VFW_E_NO_ALLOCATOR;
|
||||
}
|
||||
|
||||
_allocator.copy_to(allocator);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator* allocator, BOOL readOnly) override
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
LOG(readOnly ? "Allocator READONLY: true" : "Allocator READONLY: false");
|
||||
_allocator = allocator;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES*) override { return E_NOTIMPL; }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Receive(IMediaSample* pSample) override
|
||||
{
|
||||
if (_flushing)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (!pSample)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (pSample && _frameCallback)
|
||||
{
|
||||
_frameCallback(pSample);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample** pSamples, long nSamples, long* nSamplesProcessed) override
|
||||
{
|
||||
if (!pSamples && nSamples)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (_flushing)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
for (long i = 0; i < nSamples; i++)
|
||||
{
|
||||
Receive(pSamples[i]);
|
||||
}
|
||||
|
||||
*nSamplesProcessed = nSamples;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReceiveCanBlock() override { return S_FALSE; }
|
||||
|
||||
virtual ~VideoCaptureReceiverPin() = default;
|
||||
|
||||
constexpr static inline wchar_t NAME[] = L"PowerToysVCMCapturePin";
|
||||
};
|
||||
|
||||
constexpr long MINIMAL_FPS_ALLOWED = 29;
|
||||
|
||||
const char* GetMediaSubTypeString(const GUID& guid)
|
||||
{
|
||||
if (guid == MEDIASUBTYPE_RGB24)
|
||||
{
|
||||
return "MEDIASUBTYPE_RGB24";
|
||||
}
|
||||
|
||||
if (guid == MEDIASUBTYPE_YUY2)
|
||||
{
|
||||
return "MEDIASUBTYPE_YUY2";
|
||||
}
|
||||
|
||||
if (guid == MEDIASUBTYPE_MJPG)
|
||||
{
|
||||
return "MEDIASUBTYPE_MJPG";
|
||||
}
|
||||
|
||||
if (guid == MEDIASUBTYPE_NV12)
|
||||
{
|
||||
return "MEDIASUBTYPE_NV12";
|
||||
}
|
||||
|
||||
return "MEDIASUBTYPE_UNKNOWN";
|
||||
}
|
||||
|
||||
std::optional<VideoStreamFormat> SelectBestMediaType(wil::com_ptr_nothrow<IPin>& pin)
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
wil::com_ptr_nothrow<IEnumMediaTypes> mediaTypeEnum;
|
||||
if (pin->EnumMediaTypes(&mediaTypeEnum); !mediaTypeEnum)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ULONG _ = 0;
|
||||
VideoStreamFormat bestFormat;
|
||||
unique_media_type_ptr mt;
|
||||
while (mediaTypeEnum->Next(1, wil::out_param(mt), &_) == S_OK)
|
||||
{
|
||||
if (mt->majortype != MEDIATYPE_Video)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto format = reinterpret_cast<VIDEOINFOHEADER*>(mt->pbFormat);
|
||||
if (!format || !format->AvgTimePerFrame)
|
||||
{
|
||||
LOG("VideoInfoHeader not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto formatAvgFPS = 10000000LL / format->AvgTimePerFrame;
|
||||
if (format->AvgTimePerFrame > bestFormat.avgFrameTime || formatAvgFPS < MINIMAL_FPS_ALLOWED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (format->bmiHeader.biWidth < bestFormat.width || format->bmiHeader.biHeight < bestFormat.height)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mt->subtype != MEDIASUBTYPE_YUY2 && mt->subtype != MEDIASUBTYPE_MJPG && mt->subtype != MEDIASUBTYPE_RGB24)
|
||||
{
|
||||
OLECHAR* guidString;
|
||||
StringFromCLSID(mt->subtype, &guidString);
|
||||
LOG("Skipping mediatype due to unsupported subtype: ");
|
||||
LOG(guidString);
|
||||
::CoTaskMemFree(guidString);
|
||||
continue;
|
||||
}
|
||||
|
||||
bestFormat.avgFrameTime = format->AvgTimePerFrame;
|
||||
bestFormat.width = format->bmiHeader.biWidth;
|
||||
bestFormat.height = format->bmiHeader.biHeight;
|
||||
bestFormat.mediaType = std::move(mt);
|
||||
}
|
||||
|
||||
if (!bestFormat.mediaType)
|
||||
{
|
||||
LOG(L"Couldn't select a suitable media format");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
char selectedFormat[512]{};
|
||||
sprintf_s(selectedFormat, "Selected media format: %s %ldx%ld %lld fps", GetMediaSubTypeString(bestFormat.mediaType->subtype), bestFormat.width, bestFormat.height, 10000000LL / bestFormat.avgFrameTime);
|
||||
LOG(selectedFormat);
|
||||
|
||||
return std::move(bestFormat);
|
||||
}
|
||||
|
||||
std::vector<VideoCaptureDeviceInfo> VideoCaptureDevice::ListAll()
|
||||
{
|
||||
std::vector<VideoCaptureDeviceInfo> devices;
|
||||
auto enumeratorFactory = wil::CoCreateInstanceNoThrow<ICreateDevEnum>(CLSID_SystemDeviceEnum);
|
||||
if (!enumeratorFactory)
|
||||
{
|
||||
LOG("Couldn't create devenum factory");
|
||||
return devices;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IEnumMoniker> enumMoniker;
|
||||
enumeratorFactory->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumMoniker, CDEF_DEVMON_PNP_DEVICE);
|
||||
if (!enumMoniker)
|
||||
{
|
||||
LOG("Couldn't create class enumerator");
|
||||
return devices;
|
||||
}
|
||||
|
||||
ULONG _ = 0;
|
||||
wil::com_ptr_nothrow<IMoniker> moniker;
|
||||
while (enumMoniker->Next(1, &moniker, &_) == S_OK)
|
||||
{
|
||||
LOG("Inspecting moniker");
|
||||
VideoCaptureDeviceInfo deviceInfo;
|
||||
|
||||
wil::com_ptr_nothrow<IPropertyBag> propertyData;
|
||||
moniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, reinterpret_cast<void**>(&propertyData));
|
||||
if (!propertyData)
|
||||
{
|
||||
LOG("BindToStorage failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
wil::unique_variant propVal;
|
||||
propVal.vt = VT_BSTR;
|
||||
|
||||
if (FAILED(propertyData->Read(L"FriendlyName", &propVal, nullptr)))
|
||||
{
|
||||
LOG("Couldn't obtain FriendlyName property");
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.friendlyName = { propVal.bstrVal, SysStringLen(propVal.bstrVal) };
|
||||
LOG(deviceInfo.friendlyName);
|
||||
|
||||
propVal.reset();
|
||||
propVal.vt = VT_BSTR;
|
||||
|
||||
if (FAILED(propertyData->Read(L"DevicePath", &propVal, nullptr)))
|
||||
{
|
||||
LOG("Couldn't obtain DevicePath property");
|
||||
continue;
|
||||
}
|
||||
deviceInfo.devicePath = { propVal.bstrVal, SysStringLen(propVal.bstrVal) };
|
||||
|
||||
wil::com_ptr_nothrow<IBaseFilter> filter;
|
||||
moniker->BindToObject(nullptr, nullptr, IID_IBaseFilter, reinterpret_cast<void**>(&filter));
|
||||
if (!filter)
|
||||
{
|
||||
LOG("Couldn't BindToObject");
|
||||
continue;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IEnumPins> pinsEnum;
|
||||
if (FAILED(filter->EnumPins(&pinsEnum)))
|
||||
{
|
||||
LOG("BindToObject EnumPins");
|
||||
continue;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IPin> pin;
|
||||
while (pinsEnum->Next(1, &pin, &_) == S_OK)
|
||||
{
|
||||
LOG("Inspecting pin");
|
||||
// Skip pins which do not belong to capture category
|
||||
GUID category{};
|
||||
DWORD __;
|
||||
if (auto props = pin.try_copy<IKsPropertySet>();
|
||||
!props ||
|
||||
FAILED(props->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, nullptr, 0, &category, sizeof(GUID), &__)) ||
|
||||
category != PIN_CATEGORY_CAPTURE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip non-output pins
|
||||
if (PIN_DIRECTION direction = {}; FAILED(pin->QueryDirection(&direction)) || direction != PINDIR_OUTPUT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG("Found a pin of suitable category and direction, selecting format");
|
||||
auto bestFormat = SelectBestMediaType(pin);
|
||||
if (!bestFormat)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceInfo.captureOutputPin = std::move(pin);
|
||||
deviceInfo.bestFormat = std::move(bestFormat.value());
|
||||
deviceInfo.captureOutputFilter = std::move(filter);
|
||||
devices.emplace_back(std::move(deviceInfo));
|
||||
}
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
std::optional<VideoCaptureDevice> VideoCaptureDevice::Create(VideoCaptureDeviceInfo&& vdi, callback_t callback)
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
VideoCaptureDevice result;
|
||||
|
||||
result._graph = wil::CoCreateInstanceNoThrow<IGraphBuilder>(CLSID_FilterGraph);
|
||||
result._builder = wil::CoCreateInstanceNoThrow<ICaptureGraphBuilder2>(CLSID_CaptureGraphBuilder2);
|
||||
if (!result._graph || !result._builder)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (FAILED(result._builder->SetFiltergraph(result._graph.get())))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result._control = result._graph.try_query<IMediaControl>();
|
||||
if (!result._control)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto pinConfig = vdi.captureOutputPin.try_query<IAMStreamConfig>();
|
||||
if (!pinConfig)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (FAILED(pinConfig->SetFormat(vdi.bestFormat.mediaType.get())))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto captureInputFilter = winrt::make_self<VideoCaptureReceiverFilter>();
|
||||
auto receiverPin = winrt::make_self<VideoCaptureReceiverPin>(std::move(vdi.bestFormat.mediaType), captureInputFilter.get());
|
||||
receiverPin->_frameCallback = std::move(callback);
|
||||
captureInputFilter->_videoReceiverPin.attach(receiverPin.get());
|
||||
auto detachReceiverPin = wil::scope_exit([&receiverPin]() { receiverPin.detach(); });
|
||||
|
||||
if (FAILED(result._graph->AddFilter(captureInputFilter.get(), nullptr)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (FAILED(result._graph->AddFilter(vdi.captureOutputFilter.get(), nullptr)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (FAILED(result._graph->ConnectDirect(vdi.captureOutputPin.get(), captureInputFilter->_videoReceiverPin.get(), nullptr)))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
result._allocator = receiverPin->_allocator;
|
||||
return std::make_optional(std::move(result));
|
||||
}
|
||||
|
||||
bool VideoCaptureDevice::StartCapture()
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
return SUCCEEDED(_control->Run());
|
||||
}
|
||||
|
||||
bool VideoCaptureDevice::StopCapture()
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
return SUCCEEDED(_control->Stop());
|
||||
}
|
||||
|
||||
VideoCaptureDevice::~VideoCaptureDevice()
|
||||
{
|
||||
StopCapture();
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <initguid.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
#include <dshow.h>
|
||||
|
||||
#include <wil/com.h>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "DirectShowUtils.h"
|
||||
|
||||
struct VideoStreamFormat
|
||||
{
|
||||
long width = 0;
|
||||
long height = 0;
|
||||
REFERENCE_TIME avgFrameTime = std::numeric_limits<REFERENCE_TIME>::max();
|
||||
unique_media_type_ptr mediaType;
|
||||
|
||||
VideoStreamFormat() = default;
|
||||
|
||||
VideoStreamFormat(const VideoStreamFormat&) = delete;
|
||||
VideoStreamFormat& operator=(const VideoStreamFormat&) = delete;
|
||||
|
||||
VideoStreamFormat(VideoStreamFormat&&) = default;
|
||||
VideoStreamFormat& operator=(VideoStreamFormat&&) = default;
|
||||
};
|
||||
|
||||
struct VideoCaptureDeviceInfo
|
||||
{
|
||||
std::wstring friendlyName;
|
||||
std::wstring devicePath;
|
||||
wil::com_ptr_nothrow<IPin> captureOutputPin;
|
||||
wil::com_ptr_nothrow<IBaseFilter> captureOutputFilter;
|
||||
VideoStreamFormat bestFormat;
|
||||
};
|
||||
|
||||
class VideoCaptureDevice final
|
||||
{
|
||||
public:
|
||||
wil::com_ptr_nothrow<IMemAllocator> _allocator;
|
||||
|
||||
using callback_t = std::function<void(IMediaSample*)>;
|
||||
|
||||
static std::vector<VideoCaptureDeviceInfo> ListAll();
|
||||
static std::optional<VideoCaptureDevice> Create(VideoCaptureDeviceInfo&& vdi, callback_t callback);
|
||||
|
||||
bool StartCapture();
|
||||
bool StopCapture();
|
||||
|
||||
~VideoCaptureDevice();
|
||||
|
||||
private:
|
||||
wil::com_ptr_nothrow<IGraphBuilder> _graph;
|
||||
wil::com_ptr_nothrow<ICaptureGraphBuilder2> _builder;
|
||||
wil::com_ptr_nothrow<IMediaControl> _control;
|
||||
callback_t _callback;
|
||||
};
|
@ -0,0 +1,919 @@
|
||||
#include "VideoCaptureProxyFilter.h"
|
||||
|
||||
#include "VideoCaptureDevice.h"
|
||||
#include <mfidl.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <mfapi.h>
|
||||
#include <fstream>
|
||||
|
||||
constexpr static inline wchar_t FILTER_NAME[] = L"PowerToysVCMProxyFilter";
|
||||
constexpr static inline wchar_t PIN_NAME[] = L"PowerToysVCMProxyPIN";
|
||||
constexpr static inline wchar_t VENDOR[] = L"Microsoft Corporation";
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr float initialJpgQuality = 0.5f;
|
||||
constexpr std::array<unsigned char, 3> overlayColor = { 0, 0, 0 };
|
||||
// clang-format off
|
||||
unsigned char bmpPixelData[58] = {
|
||||
0x42, 0x4D, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, overlayColor[0], overlayColor[1], overlayColor[2], 0x00
|
||||
};
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMemAllocator> VideoCaptureProxyPin::FindAllocator()
|
||||
{
|
||||
auto allocator = GetPinAllocator(_connectedInputPin);
|
||||
if (!allocator && _owningFilter->_captureDevice)
|
||||
{
|
||||
allocator = _owningFilter->_captureDevice->_allocator;
|
||||
}
|
||||
|
||||
return allocator;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMFSample> LoadImageAsSample(wil::com_ptr_nothrow<IStream> imageStream,
|
||||
IMFMediaType* sampleMediaType,
|
||||
const float quality) noexcept;
|
||||
bool ReencodeJPGImage(BYTE* imageBuf, const DWORD imageSize, DWORD& reencodedSize);
|
||||
|
||||
HRESULT VideoCaptureProxyPin::Connect(IPin* pReceivePin, const AM_MEDIA_TYPE*)
|
||||
{
|
||||
if (!pReceivePin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED pReceivePin");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (_owningFilter->_state == State_Running)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED _owningFilter->_state");
|
||||
return VFW_E_NOT_STOPPED;
|
||||
}
|
||||
|
||||
if (_connectedInputPin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED _connectedInputPin");
|
||||
return VFW_E_ALREADY_CONNECTED;
|
||||
}
|
||||
|
||||
if (FAILED(pReceivePin->ReceiveConnection(this, _mediaFormat.get())))
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED pReceivePin->ReceiveConnection");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
_connectedInputPin = pReceivePin;
|
||||
|
||||
auto memInput = _connectedInputPin.try_query<IMemInputPin>();
|
||||
if (!memInput)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED _connectedInputPin.try_query");
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
}
|
||||
|
||||
auto allocator = FindAllocator();
|
||||
if (allocator == nullptr)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED FindAllocator");
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
}
|
||||
|
||||
if (FAILED(memInput->NotifyAllocator(allocator.get(), false)))
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Connect FAILED memInput->NotifyAllocator");
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::ReceiveConnection(IPin*, const AM_MEDIA_TYPE*)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::Disconnect(void)
|
||||
{
|
||||
if (!_connectedInputPin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Disconnect FAILED _connectedInputPin");
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
_connectedInputPin.reset();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::ConnectedTo(IPin** pPin)
|
||||
{
|
||||
if (!_connectedInputPin)
|
||||
{
|
||||
*pPin = nullptr;
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
_connectedInputPin.try_copy_to(pPin);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::ConnectionMediaType(AM_MEDIA_TYPE* pmt)
|
||||
{
|
||||
if (!_connectedInputPin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::ConnectionMediaType FAILED _connectedInputPin");
|
||||
return VFW_E_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
*pmt = *CopyMediaType(_mediaFormat).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QueryPinInfo(PIN_INFO* pInfo)
|
||||
{
|
||||
if (!pInfo)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QueryPinInfo FAILED pInfo");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
pInfo->pFilter = _owningFilter;
|
||||
if (_owningFilter)
|
||||
{
|
||||
_owningFilter->AddRef();
|
||||
}
|
||||
|
||||
if (_mediaFormat->majortype == MEDIATYPE_Video)
|
||||
{
|
||||
std::copy(std::begin(PIN_NAME), std::end(PIN_NAME), pInfo->achName);
|
||||
}
|
||||
|
||||
pInfo->dir = PINDIR_OUTPUT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QueryDirection(PIN_DIRECTION* pPinDir)
|
||||
{
|
||||
if (!pPinDir)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QueryDirection FAILED pPinDir");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*pPinDir = PINDIR_OUTPUT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QueryId(LPWSTR* Id)
|
||||
{
|
||||
if (!Id)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QueryId FAILED Id");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*Id = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(PIN_NAME)));
|
||||
std::copy(std::begin(PIN_NAME), std::end(PIN_NAME), *Id);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QueryAccept(const AM_MEDIA_TYPE*)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::EnumMediaTypes(IEnumMediaTypes** ppEnum)
|
||||
{
|
||||
if (!ppEnum)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::EnumMediaTypes FAILED ppEnum");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
auto enumerator = winrt::make_self<MediaTypeEnumerator>();
|
||||
enumerator->_objects.emplace_back(CopyMediaType(_mediaFormat));
|
||||
*ppEnum = enumerator.detach();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QueryInternalConnections(IPin**, ULONG*)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::EndOfStream(void)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::BeginFlush(void)
|
||||
{
|
||||
_flushing = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::EndFlush(void)
|
||||
{
|
||||
_flushing = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::NewSegment(REFERENCE_TIME, REFERENCE_TIME, double)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::SetFormat(AM_MEDIA_TYPE* pmt)
|
||||
{
|
||||
if (pmt == nullptr)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_mediaFormat = CopyMediaType(pmt);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::GetFormat(AM_MEDIA_TYPE** ppmt)
|
||||
{
|
||||
if (!ppmt)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::GetFormat FAILED ppmt");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*ppmt = CopyMediaType(_mediaFormat).release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::GetNumberOfCapabilities(int* piCount, int* piSize)
|
||||
{
|
||||
if (!piCount || !piSize)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::GetNumberOfCapabilities FAILED piCount || piSize");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
*piCount = 1;
|
||||
*piSize = sizeof(VIDEO_STREAM_CONFIG_CAPS);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC)
|
||||
{
|
||||
if (!ppmt || !pSCC)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::GetStreamCaps FAILED ppmt || pSCC");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (iIndex != 0)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::GetStreamCaps FAILED iIndex");
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
VIDEOINFOHEADER* vih = reinterpret_cast<decltype(vih)>(_mediaFormat->pbFormat);
|
||||
|
||||
VIDEO_STREAM_CONFIG_CAPS caps{};
|
||||
caps.guid = FORMAT_VideoInfo;
|
||||
caps.MinFrameInterval = vih->AvgTimePerFrame;
|
||||
caps.MaxFrameInterval = vih->AvgTimePerFrame;
|
||||
caps.MinOutputSize.cx = vih->bmiHeader.biWidth;
|
||||
caps.MinOutputSize.cy = vih->bmiHeader.biHeight;
|
||||
caps.MaxOutputSize = caps.MinOutputSize;
|
||||
caps.InputSize = caps.MinOutputSize;
|
||||
caps.MinCroppingSize = caps.MinOutputSize;
|
||||
caps.MaxCroppingSize = caps.MinOutputSize;
|
||||
caps.CropGranularityX = vih->bmiHeader.biWidth;
|
||||
caps.CropGranularityY = vih->bmiHeader.biHeight;
|
||||
caps.MinBitsPerSecond = vih->dwBitRate;
|
||||
caps.MaxBitsPerSecond = caps.MinBitsPerSecond;
|
||||
|
||||
*ppmt = CopyMediaType(_mediaFormat).release();
|
||||
|
||||
const auto caps_begin = reinterpret_cast<const char*>(&caps);
|
||||
std::copy(caps_begin, caps_begin + sizeof(caps), pSCC);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::Set(REFGUID, DWORD, LPVOID, DWORD, LPVOID, DWORD)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::Get(
|
||||
REFGUID guidPropSet,
|
||||
DWORD dwPropID,
|
||||
LPVOID,
|
||||
DWORD,
|
||||
LPVOID pPropData,
|
||||
DWORD cbPropData,
|
||||
DWORD* pcbReturned)
|
||||
{
|
||||
if (guidPropSet != AMPROPSETID_Pin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Get FAILED guidPropSet");
|
||||
return E_PROP_SET_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Get FAILED dwPropID");
|
||||
return E_PROP_ID_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!pPropData)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Get FAILED pPropData || pcbReturned");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (pcbReturned)
|
||||
{
|
||||
*pcbReturned = sizeof(GUID);
|
||||
}
|
||||
|
||||
if (cbPropData < sizeof(GUID))
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Get FAILED cbPropData");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
*(GUID*)pPropData = PIN_CATEGORY_CAPTURE;
|
||||
|
||||
LOG("VideoCaptureProxyPin::Get SUCCESS");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyPin::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport)
|
||||
{
|
||||
if (guidPropSet != AMPROPSETID_Pin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QuerySupported FAILED guidPropSet");
|
||||
return E_PROP_SET_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (dwPropID != AMPROPERTY_PIN_CATEGORY)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QuerySupported FAILED dwPropID");
|
||||
return E_PROP_ID_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (pTypeSupport)
|
||||
{
|
||||
*pTypeSupport = KSPROPERTY_SUPPORT_GET;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
long GetImageSize(wil::com_ptr_nothrow<IMFSample>& image)
|
||||
{
|
||||
if (!image)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD imageSize = 0;
|
||||
wil::com_ptr_nothrow<IMFMediaBuffer> imageBuf;
|
||||
|
||||
OK_OR_BAIL(image->GetBufferByIndex(0, &imageBuf));
|
||||
OK_OR_BAIL(imageBuf->GetCurrentLength(&imageSize));
|
||||
return imageSize;
|
||||
}
|
||||
|
||||
void ReencodeFrame(IMediaSample* frame)
|
||||
{
|
||||
BYTE* frameData = nullptr;
|
||||
frame->GetPointer(&frameData);
|
||||
if (!frameData)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::ReencodeFrame FAILED frameData");
|
||||
return;
|
||||
}
|
||||
const DWORD frameSize = frame->GetSize();
|
||||
DWORD reencodedSize = 0;
|
||||
if (!ReencodeJPGImage(frameData, frameSize, reencodedSize))
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::ReencodeJPGImage FAILED");
|
||||
return;
|
||||
}
|
||||
frame->SetActualDataLength(reencodedSize);
|
||||
}
|
||||
|
||||
bool OverwriteFrame(IMediaSample* frame, wil::com_ptr_nothrow<IMFSample>& image)
|
||||
{
|
||||
if (!image)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BYTE* frameData = nullptr;
|
||||
frame->GetPointer(&frameData);
|
||||
if (!frameData)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED frameData");
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMFMediaBuffer> imageBuf;
|
||||
const DWORD frameSize = frame->GetSize();
|
||||
|
||||
image->GetBufferByIndex(0, &imageBuf);
|
||||
if (!imageBuf)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED imageBuf");
|
||||
return false;
|
||||
}
|
||||
|
||||
BYTE* imageData = nullptr;
|
||||
DWORD _ = 0, imageSize = 0;
|
||||
imageBuf->Lock(&imageData, &_, &imageSize);
|
||||
if (!imageData)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::OverwriteFrame FAILED imageData");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (imageSize > frameSize && failed(frame->SetActualDataLength(imageSize)))
|
||||
{
|
||||
char buf[512]{};
|
||||
sprintf_s(buf, "VideoCaptureProxyPin::OverwriteFrame FAILED overlay image size %lu is larger than frame size %lu", imageSize, frameSize);
|
||||
LOG(buf);
|
||||
imageBuf->Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::copy(imageData, imageData + imageSize, frameData);
|
||||
imageBuf->Unlock();
|
||||
frame->SetActualDataLength(imageSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//#define DEBUG_FRAME_DATA
|
||||
//#define DEBUG_OVERWRITE_FRAME
|
||||
//#define DEBUG_REENCODE_JPG_DATA
|
||||
|
||||
#if defined(DEBUG_OVERWRITE_FRAME)
|
||||
void DebugOverwriteFrame(IMediaSample* frame, std::string_view filepath)
|
||||
{
|
||||
std::ifstream file{ filepath.data(), std::ios::binary };
|
||||
std::streampos fileSize = 0;
|
||||
fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::end);
|
||||
fileSize = file.tellg() - fileSize;
|
||||
|
||||
BYTE* frameData = nullptr;
|
||||
if (!frame)
|
||||
{
|
||||
LOG("null frame provided");
|
||||
return;
|
||||
}
|
||||
frame->GetPointer(&frameData);
|
||||
const DWORD frameSize = frame->GetSize();
|
||||
|
||||
if (fileSize > frameSize || !frameData)
|
||||
{
|
||||
LOG("frame can't be filled with data");
|
||||
return;
|
||||
}
|
||||
file.read((char*)frameData, fileSize);
|
||||
frame->SetActualDataLength((long)fileSize);
|
||||
LOG("DebugOverwriteFrame success");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_FRAME_DATA)
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
void DumpSample(IMediaSample* frame, const std::string_view filename)
|
||||
{
|
||||
BYTE* data = nullptr;
|
||||
frame->GetPointer(&data);
|
||||
if (!data)
|
||||
{
|
||||
LOG("Couldn't get sample pointer");
|
||||
return;
|
||||
}
|
||||
const long nBytes = frame->GetActualDataLength();
|
||||
std::ofstream file{ fs::temp_directory_path() / filename, std::ios::binary };
|
||||
file.write((const char*)data, nBytes);
|
||||
}
|
||||
#endif
|
||||
|
||||
VideoCaptureProxyFilter::VideoCaptureProxyFilter() :
|
||||
_worker_thread{
|
||||
std::thread{
|
||||
[this]() {
|
||||
using namespace std::chrono_literals;
|
||||
const auto uninitializedSleepInterval = 15ms;
|
||||
std::vector<float> lowerJpgQualityModes = { 0.1f, 0.25f };
|
||||
while (!_shutdown_request)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{ _worker_mutex };
|
||||
_worker_cv.wait(lock, [this] { return _pending_frame != nullptr || _shutdown_request; });
|
||||
|
||||
if (!_outPin || !_outPin->_connectedInputPin)
|
||||
{
|
||||
lock.unlock();
|
||||
std::this_thread::sleep_for(uninitializedSleepInterval);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto input = _outPin->_connectedInputPin.try_query<IMemInputPin>();
|
||||
if (!input)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IMediaSample* sample = _pending_frame;
|
||||
if (!sample)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#if defined(DEBUG_FRAME_DATA)
|
||||
static bool realFrameSaved = false;
|
||||
if (!realFrameSaved)
|
||||
{
|
||||
DumpSample(sample, "PowerToysVCMRealFrame.binary");
|
||||
realFrameSaved = true;
|
||||
}
|
||||
#endif
|
||||
auto newSettings = SyncCurrentSettings();
|
||||
if (newSettings.webcamDisabled)
|
||||
{
|
||||
#if !defined(DEBUG_OVERWRITE_FRAME)
|
||||
bool overwritten = OverwriteFrame(_pending_frame, _overlayImage ? _overlayImage : _blankImage);
|
||||
while (!overwritten && _overlayImage)
|
||||
{
|
||||
_overlayImage.reset();
|
||||
newSettings = SyncCurrentSettings();
|
||||
if (!lowerJpgQualityModes.empty() && newSettings.overlayImage)
|
||||
{
|
||||
const float quality = lowerJpgQualityModes.back();
|
||||
lowerJpgQualityModes.pop_back();
|
||||
char buf[512]{};
|
||||
sprintf_s(buf, "Reload overlay image with quality %f", quality);
|
||||
LOG(buf);
|
||||
_overlayImage = LoadImageAsSample(newSettings.overlayImage, _targetMediaType.get(), quality);
|
||||
overwritten = OverwriteFrame(_pending_frame, _overlayImage);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Couldn't overwrite frame with image with all available quality modes.");
|
||||
}
|
||||
}
|
||||
#if defined(DEBUG_FRAME_DATA)
|
||||
static bool overlayFrameSaved = false;
|
||||
if (!overlayFrameSaved && _overlayImage && overwritten)
|
||||
{
|
||||
DumpSample(sample, "PowerToysVCMOverlayImageFrame.binary");
|
||||
overlayFrameSaved = true;
|
||||
}
|
||||
#endif
|
||||
if (!overwritten && !_overlayImage)
|
||||
{
|
||||
OverwriteFrame(_pending_frame, _blankImage);
|
||||
}
|
||||
#else
|
||||
DebugOverwriteFrame(_pending_frame, "R:\\frame.data");
|
||||
#endif
|
||||
}
|
||||
#if defined(DEBUG_REENCODE_JPG_DATA)
|
||||
else
|
||||
{
|
||||
GUID subtype{};
|
||||
_targetMediaType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
if (subtype == MFVideoFormat_MJPG)
|
||||
{
|
||||
ReencodeFrame(_pending_frame);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
_pending_frame = nullptr;
|
||||
input->Receive(sample);
|
||||
sample->Release();
|
||||
}
|
||||
} }
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::Stop(void)
|
||||
{
|
||||
if (_state != State_Stopped && _captureDevice)
|
||||
{
|
||||
_captureDevice->StopCapture();
|
||||
}
|
||||
|
||||
_state = State_Stopped;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::Pause(void)
|
||||
{
|
||||
if (_state == State_Stopped)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{ _worker_mutex };
|
||||
|
||||
if (!_outPin)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Pause FAILED _outPin");
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
}
|
||||
|
||||
auto allocator = _outPin->FindAllocator();
|
||||
if (!allocator)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::Pause FAILED allocator");
|
||||
return VFW_E_NO_TRANSPORT;
|
||||
}
|
||||
|
||||
allocator->Commit();
|
||||
}
|
||||
|
||||
_state = State_Paused;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::Run(REFERENCE_TIME)
|
||||
{
|
||||
_state = State_Running;
|
||||
if (_captureDevice)
|
||||
{
|
||||
_captureDevice->StartCapture();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::GetState(DWORD, FILTER_STATE* State)
|
||||
{
|
||||
*State = _state;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::SetSyncSource(IReferenceClock* pClock)
|
||||
{
|
||||
_clock = pClock;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::GetSyncSource(IReferenceClock** pClock)
|
||||
{
|
||||
if (!pClock)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
_clock.try_copy_to(pClock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
GUID MapDShowSubtypeToMFT(const GUID& dshowSubtype)
|
||||
{
|
||||
if (dshowSubtype == MEDIASUBTYPE_YUY2)
|
||||
{
|
||||
return MFVideoFormat_YUY2;
|
||||
}
|
||||
else if (dshowSubtype == MEDIASUBTYPE_MJPG)
|
||||
{
|
||||
return MFVideoFormat_MJPG;
|
||||
}
|
||||
else if (dshowSubtype == MEDIASUBTYPE_RGB24)
|
||||
{
|
||||
return MFVideoFormat_RGB24;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("MapDShowSubtypeToMFT: Unsupported media type format provided!");
|
||||
return MFVideoFormat_MJPG;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::EnumPins(IEnumPins** ppEnum)
|
||||
{
|
||||
if (!ppEnum)
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins null arg provided");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock{ _worker_mutex };
|
||||
|
||||
// We cannot initialize capture device and outpin during VideoCaptureProxyFilter ctor
|
||||
// since that results in a deadlock -> initializing now.
|
||||
if (!_outPin)
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins started pin initialization");
|
||||
const auto newSettings = SyncCurrentSettings();
|
||||
std::vector<VideoCaptureDeviceInfo> webcams;
|
||||
webcams = VideoCaptureDevice::ListAll();
|
||||
if (webcams.empty())
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins no physical webcams found");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
std::optional<size_t> selectedCamIdx;
|
||||
for (size_t i = 0; i < size(webcams); ++i)
|
||||
{
|
||||
if (newSettings.newCameraName == webcams[i].friendlyName)
|
||||
{
|
||||
selectedCamIdx = i;
|
||||
LOG("VideoCaptureProxyFilter::EnumPins webcam selected using settings");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedCamIdx)
|
||||
{
|
||||
for (size_t i = 0; i < size(webcams); ++i)
|
||||
{
|
||||
if (newSettings.newCameraName != CAMERA_NAME)
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins webcam selected using first fit");
|
||||
selectedCamIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedCamIdx)
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins FAILED webcam couldn't be selected");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
auto& webcam = webcams[*selectedCamIdx];
|
||||
auto pin = winrt::make_self<VideoCaptureProxyPin>();
|
||||
pin->_mediaFormat = CopyMediaType(webcam.bestFormat.mediaType);
|
||||
pin->_owningFilter = this;
|
||||
_outPin.attach(pin.detach());
|
||||
|
||||
auto frameCallback = [this](IMediaSample* sample) {
|
||||
std::unique_lock<std::mutex> lock{ _worker_mutex };
|
||||
sample->AddRef();
|
||||
_pending_frame = sample;
|
||||
_worker_cv.notify_one();
|
||||
};
|
||||
|
||||
_targetMediaType.reset();
|
||||
MFCreateMediaType(&_targetMediaType);
|
||||
_targetMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
||||
_targetMediaType->SetGUID(MF_MT_SUBTYPE, MapDShowSubtypeToMFT(webcam.bestFormat.mediaType->subtype));
|
||||
_targetMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
|
||||
_targetMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
|
||||
MFSetAttributeSize(
|
||||
_targetMediaType.get(), MF_MT_FRAME_SIZE, webcam.bestFormat.width, webcam.bestFormat.height);
|
||||
MFSetAttributeRatio(_targetMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
|
||||
|
||||
_captureDevice = VideoCaptureDevice::Create(std::move(webcam), std::move(frameCallback));
|
||||
if (_captureDevice)
|
||||
{
|
||||
if (!_blankImage)
|
||||
{
|
||||
wil::com_ptr_nothrow<IStream> blackBMPImage = SHCreateMemStream(bmpPixelData, sizeof(bmpPixelData));
|
||||
_blankImage = LoadImageAsSample(blackBMPImage, _targetMediaType.get(), initialJpgQuality);
|
||||
}
|
||||
|
||||
_overlayImage = LoadImageAsSample(newSettings.overlayImage, _targetMediaType.get(), initialJpgQuality);
|
||||
LOG("VideoCaptureProxyFilter::EnumPins capture device created successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("VideoCaptureProxyFilter::EnumPins FAILED couldn't create capture device");
|
||||
}
|
||||
}
|
||||
|
||||
auto enumerator = winrt::make_self<ObjectEnumerator<IPin, IEnumPins>>();
|
||||
enumerator->_objects.emplace_back(_outPin);
|
||||
*ppEnum = enumerator.detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::FindPin(LPCWSTR, IPin**)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::QueryFilterInfo(FILTER_INFO* pInfo)
|
||||
{
|
||||
if (!pInfo)
|
||||
{
|
||||
LOG("VideoCaptureProxyPin::QueryFilterInfo FAILED pInfo");
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
VERBOSE_LOG;
|
||||
std::copy(std::begin(FILTER_NAME), std::end(FILTER_NAME), pInfo->achName);
|
||||
|
||||
pInfo->pGraph = _graph;
|
||||
if (_graph)
|
||||
{
|
||||
_graph->AddRef();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR)
|
||||
{
|
||||
_graph = pGraph;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::QueryVendorInfo(LPWSTR* pVendorInfo)
|
||||
{
|
||||
auto info = static_cast<LPWSTR>(CoTaskMemAlloc(sizeof(VENDOR)));
|
||||
std::copy(std::begin(VENDOR), std::end(VENDOR), info);
|
||||
*pVendorInfo = info;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureProxyFilter::GetClassID(CLSID*)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
ULONG VideoCaptureProxyFilter::GetMiscFlags(void)
|
||||
{
|
||||
return AM_FILTER_MISC_FLAGS_IS_SOURCE;
|
||||
}
|
||||
|
||||
VideoCaptureProxyFilter::~VideoCaptureProxyFilter()
|
||||
{
|
||||
VERBOSE_LOG;
|
||||
_shutdown_request = true;
|
||||
|
||||
_worker_cv.notify_one();
|
||||
_worker_thread.join();
|
||||
}
|
||||
|
||||
VideoCaptureProxyFilter::SyncedSettings VideoCaptureProxyFilter::SyncCurrentSettings()
|
||||
{
|
||||
SyncedSettings result;
|
||||
if (!_settingsUpdateChannel.has_value())
|
||||
{
|
||||
_settingsUpdateChannel = SerializedSharedMemory::open(CameraSettingsUpdateChannel::endpoint(), sizeof(CameraSettingsUpdateChannel), false);
|
||||
}
|
||||
|
||||
if (!_settingsUpdateChannel)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
_settingsUpdateChannel->access([this, &result](auto settingsMemory) {
|
||||
auto settings = reinterpret_cast<CameraSettingsUpdateChannel*>(settingsMemory._data);
|
||||
bool cameraNameUpdated = false;
|
||||
result.webcamDisabled = settings->useOverlayImage;
|
||||
|
||||
settings->cameraInUse = true;
|
||||
|
||||
if (settings->sourceCameraName.has_value())
|
||||
{
|
||||
std::wstring_view newCameraNameView{ settings->sourceCameraName->data() };
|
||||
if (!_currentSourceCameraName.has_value() || *_currentSourceCameraName != newCameraNameView)
|
||||
{
|
||||
cameraNameUpdated = true;
|
||||
result.newCameraName = newCameraNameView;
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings->overlayImageSize.has_value())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (settings->newOverlayImagePosted || !_overlayImage)
|
||||
{
|
||||
auto imageChannel =
|
||||
SerializedSharedMemory::open(CameraOverlayImageChannel::endpoint(), *settings->overlayImageSize, true);
|
||||
if (!imageChannel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
imageChannel->access([this, settings, &result](auto imageMemory) {
|
||||
result.overlayImage = SHCreateMemStream(imageMemory._data, static_cast<UINT>(imageMemory._size));
|
||||
if (!result.overlayImage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
settings->newOverlayImagePosted = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <dshow.h>
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <wil/resource.h>
|
||||
#include <wil/com.h>
|
||||
|
||||
#include <CameraStateUpdateChannels.h>
|
||||
#include <SerializedSharedMemory.h>
|
||||
|
||||
#include "VideoCaptureDevice.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
struct VideoCaptureProxyPin;
|
||||
struct IMFSample;
|
||||
struct IMFMediaType;
|
||||
|
||||
inline const wchar_t CAMERA_NAME[] = L"PowerToys VideoConference Mute";
|
||||
|
||||
struct VideoCaptureProxyFilter : winrt::implements<VideoCaptureProxyFilter, IBaseFilter, IAMFilterMiscFlags>
|
||||
{
|
||||
// BLOCK START: member accessed concurrently
|
||||
wil::com_ptr_nothrow<VideoCaptureProxyPin> _outPin;
|
||||
IMediaSample* _pending_frame = nullptr;
|
||||
std::atomic_bool _shutdown_request = false;
|
||||
std::optional<SerializedSharedMemory> _settingsUpdateChannel;
|
||||
std::optional<std::wstring> _currentSourceCameraName;
|
||||
wil::com_ptr_nothrow<IMFSample> _blankImage;
|
||||
wil::com_ptr_nothrow<IMFSample> _overlayImage;
|
||||
wil::com_ptr_nothrow<IMFMediaType> _targetMediaType;
|
||||
// BLOCK END: member accessed concurrently
|
||||
|
||||
std::mutex _worker_mutex;
|
||||
std::condition_variable _worker_cv;
|
||||
|
||||
FILTER_STATE _state = State_Stopped;
|
||||
wil::com_ptr_nothrow<IReferenceClock> _clock;
|
||||
IFilterGraph* _graph = nullptr;
|
||||
std::optional<VideoCaptureDevice> _captureDevice;
|
||||
|
||||
std::thread _worker_thread;
|
||||
|
||||
VideoCaptureProxyFilter();
|
||||
~VideoCaptureProxyFilter();
|
||||
|
||||
struct SyncedSettings
|
||||
{
|
||||
bool webcamDisabled = false;
|
||||
std::wstring newCameraName;
|
||||
wil::com_ptr_nothrow<IStream> overlayImage;
|
||||
};
|
||||
|
||||
SyncedSettings SyncCurrentSettings();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Stop(void) override;
|
||||
HRESULT STDMETHODCALLTYPE Pause(void) override;
|
||||
HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart) override;
|
||||
HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE* State) override;
|
||||
HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock* pClock) override;
|
||||
HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock** pClock) override;
|
||||
HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins** ppEnum) override;
|
||||
HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin** ppPin) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO* pInfo) override;
|
||||
HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR* pVendorInfo) override;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetClassID(CLSID* pClassID) override;
|
||||
ULONG STDMETHODCALLTYPE GetMiscFlags(void) override;
|
||||
};
|
||||
struct VideoCaptureProxyPin : winrt::implements<VideoCaptureProxyPin, IPin, IAMStreamConfig, IKsPropertySet>
|
||||
{
|
||||
VideoCaptureProxyFilter* _owningFilter = nullptr;
|
||||
wil::com_ptr_nothrow<IPin> _connectedInputPin;
|
||||
unique_media_type_ptr _mediaFormat;
|
||||
std::atomic_bool _flushing = false;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Connect(IPin* pReceivePin, const AM_MEDIA_TYPE* pmt) override;
|
||||
HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin* pConnector, const AM_MEDIA_TYPE* pmt) override;
|
||||
HRESULT STDMETHODCALLTYPE Disconnect(void) override;
|
||||
HRESULT STDMETHODCALLTYPE ConnectedTo(IPin** pPin) override;
|
||||
HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE* pmt) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO* pInfo) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION* pPinDir) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryId(LPWSTR* Id) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE* pmt) override;
|
||||
HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes** ppEnum) override;
|
||||
HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin** apPin, ULONG* nPin) override;
|
||||
HRESULT STDMETHODCALLTYPE EndOfStream(void) override;
|
||||
HRESULT STDMETHODCALLTYPE BeginFlush(void) override;
|
||||
HRESULT STDMETHODCALLTYPE EndFlush(void) override;
|
||||
HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) override;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE* pmt) override;
|
||||
HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE** ppmt) override;
|
||||
HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int* piCount, int* piSize) override;
|
||||
HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE** ppmt, BYTE* pSCC) override;
|
||||
HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet,
|
||||
DWORD dwPropID,
|
||||
LPVOID pInstanceData,
|
||||
DWORD cbInstanceData,
|
||||
LPVOID pPropData,
|
||||
DWORD cbPropData) override;
|
||||
HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet,
|
||||
DWORD dwPropID,
|
||||
LPVOID pInstanceData,
|
||||
DWORD cbInstanceData,
|
||||
LPVOID pPropData,
|
||||
DWORD cbPropData,
|
||||
DWORD* pcbReturned) override;
|
||||
HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD* pTypeSupport) override;
|
||||
|
||||
wil::com_ptr_nothrow<IMemAllocator> FindAllocator();
|
||||
};
|
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{AC2857B4-103D-4D6D-9740-926EBF785042}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>VideoConferenceProxyFilter</RootNamespace>
|
||||
<ProjectName>VideoConferenceProxyFilter</ProjectName>
|
||||
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\src\;$(ProjectDir)..\..\..\</AdditionalIncludeDirectories>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
|
||||
</Lib>
|
||||
<PreBuildEvent Condition="'$(Platform)'=='x64'">
|
||||
<Command>call "$(ProjectDir)build_vcm_x86.cmd"</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'!='Win32'">
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<TargetName>VideoConferenceProxyFilter_x64</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='Win32'">
|
||||
<OutDir>..\..\..\..\x86\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<TargetName>VideoConferenceProxyFilter_x86</TargetName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\VideoConferenceShared\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_LIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MultiThreaded</RuntimeLibrary>
|
||||
<RuntimeLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>$(OutDir)VideoConferenceShared.lib;mfplat.lib;Mfsensorgroup.lib;OneCoreUAP.lib;Mf.lib;Shlwapi.lib;Strmiids.lib;%(AdditionalDependencies);</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>module.def</ModuleDefinitionFile>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DirectShowUtils.h" />
|
||||
<ClInclude Include="VideoCaptureDevice.h" />
|
||||
<ClInclude Include="VideoCaptureProxyFilter.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DirectShowUtils.cpp" />
|
||||
<ClCompile Include="VideoCaptureDevice.cpp" />
|
||||
<ClCompile Include="VideoCaptureProxyFilter.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="ImageLoading.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="module.def" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VideoConferenceShared\VideoConferenceShared.vcxproj">
|
||||
<Project>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
@ -0,0 +1,41 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30907.101
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceProxyFilter", "VideoConferenceProxyFilter.vcxproj", "{AC2857B4-103D-4D6D-9740-926EBF785042}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VideoConferenceShared", "..\VideoConferenceShared\VideoConferenceShared.vcxproj", "{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|Win32.Build.0 = Release|Win32
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.ActiveCfg = Release|x64
|
||||
{AC2857B4-103D-4D6D-9740-926EBF785042}.Release|x64.Build.0 = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Debug|x64.Build.0 = Debug|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|Win32.Build.0 = Release|Win32
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.ActiveCfg = Release|x64
|
||||
{459E0768-7EBD-4C41-BBA1-6DB3B3815E0A}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0E41348C-22CB-45A4-8A16-8D7BEA070BB2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,3 @@
|
||||
msbuild VideoConferenceProxyFilterx86.sln -p:Configuration="Release" -p:Platform="Win32"
|
||||
|
||||
exit 0
|
@ -0,0 +1,242 @@
|
||||
#include "VideoCaptureProxyFilter.h"
|
||||
|
||||
#include <winrt/base.h>
|
||||
|
||||
#include <wil/registry.h>
|
||||
#include <cguid.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
class __declspec(uuid("{31AD75E9-8C3A-49C8-B9ED-5880D6B4A764}")) GUID_DECL_POWERTOYS_VCM;
|
||||
#elif defined(_WIN32)
|
||||
class __declspec(uuid("{31AD75E9-8C3A-49C8-B9ED-5880D6B4A732}")) GUID_DECL_POWERTOYS_VCM;
|
||||
#endif
|
||||
const GUID CLSID_POWERTOYS_VCM = __uuidof(GUID_DECL_POWERTOYS_VCM);
|
||||
|
||||
const REGPINTYPES MEDIA_TYPES = { &MEDIATYPE_Video, &MEDIASUBTYPE_MJPG };
|
||||
|
||||
const wchar_t FILTER_NAME[] = L"Output";
|
||||
const REGFILTERPINS PINS_REGISTRATION = {
|
||||
(wchar_t*)FILTER_NAME,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
&CLSID_NULL,
|
||||
nullptr,
|
||||
1,
|
||||
&MEDIA_TYPES
|
||||
};
|
||||
|
||||
HINSTANCE DLLInstance{};
|
||||
}
|
||||
|
||||
struct __declspec(uuid("9DCAF869-9C13-4BDF-BD0D-3592C5579DD6")) VideoCaptureProxyFilterFactory : winrt::implements<VideoCaptureProxyFilterFactory, IClassFactory>
|
||||
{
|
||||
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown*, REFIID riid, void** ppvObject) noexcept override
|
||||
{
|
||||
try
|
||||
{
|
||||
return winrt::make<VideoCaptureProxyFilter>()->QueryInterface(riid, ppvObject);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return winrt::to_hresult();
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) noexcept override
|
||||
{
|
||||
if (fLock)
|
||||
{
|
||||
++winrt::get_module_lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
--winrt::get_module_lock();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DllCanUnloadNow()
|
||||
{
|
||||
if (winrt::get_module_lock())
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
winrt::clear_factory_cache();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DllGetClassObject(GUID const& clsid, GUID const& iid, void** result)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
if (iid != IID_IClassFactory && iid != IID_IUnknown)
|
||||
{
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
if (clsid != CLSID_POWERTOYS_VCM)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
*result = nullptr;
|
||||
|
||||
auto factory = winrt::make<VideoCaptureProxyFilterFactory>();
|
||||
factory->AddRef();
|
||||
*result = static_cast<void*>(factory.get());
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return winrt::to_hresult();
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring RegistryPath()
|
||||
{
|
||||
std::wstring registryPath;
|
||||
registryPath.resize(CHARS_IN_GUID, L'\0');
|
||||
|
||||
StringFromGUID2(CLSID_POWERTOYS_VCM, registryPath.data(), CHARS_IN_GUID);
|
||||
registryPath.resize(registryPath.size() - 1);
|
||||
registryPath = L"CLSID\\" + registryPath;
|
||||
return registryPath;
|
||||
}
|
||||
|
||||
bool RegisterServer()
|
||||
{
|
||||
std::wstring dllPath;
|
||||
dllPath.resize(MAX_PATH, L'\0');
|
||||
if (auto length = GetModuleFileNameW(DLLInstance, dllPath.data(), MAX_PATH); length != 0)
|
||||
{
|
||||
dllPath.resize(length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wil::unique_hkey key;
|
||||
wil::unique_hkey subkey;
|
||||
const auto registryPath = RegistryPath();
|
||||
if (RegCreateKeyW(HKEY_CLASSES_ROOT, registryPath.c_str(), &key))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RegSetValueW(key.get(), nullptr, REG_SZ, CAMERA_NAME, sizeof(CAMERA_NAME)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RegCreateKeyW(key.get(), L"InprocServer32", &subkey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (RegSetValueW(subkey.get(), nullptr, REG_SZ, dllPath.c_str(), static_cast<DWORD>((dllPath.length() + 1) * sizeof(wchar_t))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const wchar_t THREADING_MODEL[] = L"Both";
|
||||
RegSetValueExW(subkey.get(), L"ThreadingModel", 0, REG_SZ, (const BYTE*)THREADING_MODEL, sizeof(THREADING_MODEL));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnregisterServer()
|
||||
{
|
||||
const auto registryPath = RegistryPath();
|
||||
return !RegDeleteTreeW(HKEY_CLASSES_ROOT, registryPath.c_str());
|
||||
}
|
||||
|
||||
bool RegisterFilter()
|
||||
{
|
||||
auto filterMapper = wil::CoCreateInstanceNoThrow<IFilterMapper2>(CLSID_FilterMapper2);
|
||||
if (!filterMapper)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
REGFILTER2 regFilter{ .dwVersion = 1, .dwMerit = MERIT_DO_NOT_USE, .cPins = 1, .rgPins = &PINS_REGISTRATION };
|
||||
|
||||
wil::com_ptr_nothrow<IMoniker> moniker;
|
||||
|
||||
return SUCCEEDED(filterMapper->RegisterFilter(
|
||||
CLSID_POWERTOYS_VCM, CAMERA_NAME, &moniker, &CLSID_VideoInputDeviceCategory, nullptr, ®Filter));
|
||||
}
|
||||
|
||||
bool UnregisterFilter()
|
||||
{
|
||||
auto filterMapper = wil::CoCreateInstanceNoThrow<IFilterMapper2>(CLSID_FilterMapper2);
|
||||
if (!filterMapper)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return SUCCEEDED(filterMapper->UnregisterFilter(&CLSID_VideoInputDeviceCategory, nullptr, CLSID_POWERTOYS_VCM));
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DllRegisterServer()
|
||||
{
|
||||
if (!RegisterServer())
|
||||
{
|
||||
UnregisterServer();
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
auto COMContext = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);
|
||||
|
||||
if (!RegisterFilter())
|
||||
{
|
||||
UnregisterFilter();
|
||||
UnregisterServer();
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DllUnregisterServer()
|
||||
{
|
||||
auto COMContext = wil::CoInitializeEx(COINIT_APARTMENTTHREADED);
|
||||
|
||||
UnregisterFilter();
|
||||
UnregisterServer();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DllInstall(BOOL install, LPCWSTR)
|
||||
{
|
||||
if (install)
|
||||
{
|
||||
return DllRegisterServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
return DllUnregisterServer();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
DLLInstance = hinstDLL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
EXPORTS
|
||||
DllMain PRIVATE
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllRegisterServer PRIVATE
|
||||
DllUnregisterServer PRIVATE
|
||||
DllInstall PRIVATE
|
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
|
||||
</packages>
|
@ -0,0 +1,15 @@
|
||||
#include "CameraStateUpdateChannels.h"
|
||||
|
||||
#include "naming.h"
|
||||
|
||||
std::wstring_view CameraOverlayImageChannel::endpoint()
|
||||
{
|
||||
static const std::wstring endpoint = ObtainStableGlobalNameForKernelObject(L"PowerToysVideoConferenceCameraOverlayImageChannelSharedMemory", true);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
std::wstring_view CameraSettingsUpdateChannel::endpoint()
|
||||
{
|
||||
static const std::wstring endpoint = ObtainStableGlobalNameForKernelObject(L"PowerToysVideoConferenceSettingsChannelSharedMemory", true);
|
||||
return endpoint;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
|
||||
struct alignas(16) CameraSettingsUpdateChannel
|
||||
{
|
||||
bool useOverlayImage = false;
|
||||
bool cameraInUse = false;
|
||||
|
||||
std::optional<uint32_t> overlayImageSize;
|
||||
std::optional<std::array<wchar_t, 256>> sourceCameraName;
|
||||
|
||||
bool newOverlayImagePosted = false;
|
||||
|
||||
static std::wstring_view endpoint();
|
||||
};
|
||||
|
||||
namespace CameraOverlayImageChannel
|
||||
{
|
||||
std::wstring_view endpoint();
|
||||
}
|
203
src/modules/videoconference/VideoConferenceShared/Logging.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
#include "Logging.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
|
||||
#include <mfapi.h>
|
||||
|
||||
#pragma warning(disable : 4127)
|
||||
|
||||
static std::mutex logMutex;
|
||||
constexpr inline size_t maxLogSizeMegabytes = 10;
|
||||
constexpr inline bool alwaysLogVerbose = true;
|
||||
|
||||
void LogToFile(std::wstring what, const bool verbose)
|
||||
{
|
||||
std::error_code _;
|
||||
const auto tempPath = std::filesystem::temp_directory_path(_);
|
||||
if (verbose)
|
||||
{
|
||||
const bool verboseIndicatorFilePresent = std::filesystem::exists(tempPath / L"PowerToysVideoConferenceVerbose.flag", _);
|
||||
if (!alwaysLogVerbose && !verboseIndicatorFilePresent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
std::tm tm;
|
||||
localtime_s(&tm, &now);
|
||||
char prefix[64];
|
||||
const auto pid = GetCurrentProcessId();
|
||||
const auto iter = prefix + sprintf_s(prefix, "[%ld]", pid);
|
||||
std::strftime(iter, sizeof(prefix) - (prefix - iter), "[%d.%m %H:%M:%S] ", &tm);
|
||||
|
||||
std::lock_guard lock{ logMutex };
|
||||
std::wstring logFilePath = tempPath;
|
||||
#if defined(_WIN64)
|
||||
logFilePath += L"\\PowerToysVideoConference_x64.log";
|
||||
#elif defined(_WIN32)
|
||||
logFilePath += L"\\PowerToysVideoConference_x86.log";
|
||||
#endif
|
||||
size_t logSizeMBs = 0;
|
||||
try
|
||||
{
|
||||
logSizeMBs = static_cast<size_t>(std::filesystem::file_size(logFilePath) >> 20);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
if (logSizeMBs > maxLogSizeMegabytes)
|
||||
{
|
||||
std::error_code __;
|
||||
// Truncate the log file to zero
|
||||
std::filesystem::resize_file(logFilePath, 0, __);
|
||||
}
|
||||
std::wofstream myfile;
|
||||
myfile.open(logFilePath, std::fstream::app);
|
||||
|
||||
static const auto newLaunch = [&] {
|
||||
myfile << prefix << "\n\n<<<NEW SESSION>>";
|
||||
return 0;
|
||||
}();
|
||||
|
||||
myfile << prefix << what << "\n";
|
||||
myfile.close();
|
||||
}
|
||||
|
||||
void LogToFile(std::string what, const bool verbose)
|
||||
{
|
||||
std::wstring native{ begin(what), end(what) };
|
||||
LogToFile(std::move(native), verbose);
|
||||
}
|
||||
|
||||
std::string toMediaTypeString(GUID subtype)
|
||||
{
|
||||
if (subtype == MFVideoFormat_YUY2)
|
||||
return "MFVideoFormat_YUY2";
|
||||
else if (subtype == MFVideoFormat_RGB32)
|
||||
return "MFVideoFormat_RGB32";
|
||||
else if (subtype == MFVideoFormat_RGB24)
|
||||
return "MFVideoFormat_RGB24";
|
||||
else if (subtype == MFVideoFormat_ARGB32)
|
||||
return "MFVideoFormat_ARGB32";
|
||||
else if (subtype == MFVideoFormat_RGB555)
|
||||
return "MFVideoFormat_RGB555";
|
||||
else if (subtype == MFVideoFormat_RGB565)
|
||||
return "MFVideoFormat_RGB565";
|
||||
else if (subtype == MFVideoFormat_RGB8)
|
||||
return "MFVideoFormat_RGB8";
|
||||
else if (subtype == MFVideoFormat_L8)
|
||||
return "MFVideoFormat_L8";
|
||||
else if (subtype == MFVideoFormat_L16)
|
||||
return "MFVideoFormat_L16";
|
||||
else if (subtype == MFVideoFormat_D16)
|
||||
return "MFVideoFormat_D16";
|
||||
else if (subtype == MFVideoFormat_AYUV)
|
||||
return "MFVideoFormat_AYUV";
|
||||
else if (subtype == MFVideoFormat_YUY2)
|
||||
return "MFVideoFormat_YUY2";
|
||||
else if (subtype == MFVideoFormat_YVYU)
|
||||
return "MFVideoFormat_YVYU";
|
||||
else if (subtype == MFVideoFormat_YVU9)
|
||||
return "MFVideoFormat_YVU9";
|
||||
else if (subtype == MFVideoFormat_UYVY)
|
||||
return "MFVideoFormat_UYVY";
|
||||
else if (subtype == MFVideoFormat_NV11)
|
||||
return "MFVideoFormat_NV11";
|
||||
else if (subtype == MFVideoFormat_NV12)
|
||||
return "MFVideoFormat_NV12";
|
||||
else if (subtype == MFVideoFormat_YV12)
|
||||
return "MFVideoFormat_YV12";
|
||||
else if (subtype == MFVideoFormat_I420)
|
||||
return "MFVideoFormat_I420";
|
||||
else if (subtype == MFVideoFormat_IYUV)
|
||||
return "MFVideoFormat_IYUV";
|
||||
else if (subtype == MFVideoFormat_Y210)
|
||||
return "MFVideoFormat_Y210";
|
||||
else if (subtype == MFVideoFormat_Y216)
|
||||
return "MFVideoFormat_Y216";
|
||||
else if (subtype == MFVideoFormat_Y410)
|
||||
return "MFVideoFormat_Y410";
|
||||
else if (subtype == MFVideoFormat_Y416)
|
||||
return "MFVideoFormat_Y416";
|
||||
else if (subtype == MFVideoFormat_Y41P)
|
||||
return "MFVideoFormat_Y41P";
|
||||
else if (subtype == MFVideoFormat_Y41T)
|
||||
return "MFVideoFormat_Y41T";
|
||||
else if (subtype == MFVideoFormat_Y42T)
|
||||
return "MFVideoFormat_Y42T";
|
||||
else if (subtype == MFVideoFormat_P210)
|
||||
return "MFVideoFormat_P210";
|
||||
else if (subtype == MFVideoFormat_P216)
|
||||
return "MFVideoFormat_P216";
|
||||
else if (subtype == MFVideoFormat_P010)
|
||||
return "MFVideoFormat_P010";
|
||||
else if (subtype == MFVideoFormat_P016)
|
||||
return "MFVideoFormat_P016";
|
||||
else if (subtype == MFVideoFormat_v210)
|
||||
return "MFVideoFormat_v210";
|
||||
else if (subtype == MFVideoFormat_v216)
|
||||
return "MFVideoFormat_v216";
|
||||
else if (subtype == MFVideoFormat_v410)
|
||||
return "MFVideoFormat_v410";
|
||||
else if (subtype == MFVideoFormat_MP43)
|
||||
return "MFVideoFormat_MP43";
|
||||
else if (subtype == MFVideoFormat_MP4S)
|
||||
return "MFVideoFormat_MP4S";
|
||||
else if (subtype == MFVideoFormat_M4S2)
|
||||
return "MFVideoFormat_M4S2";
|
||||
else if (subtype == MFVideoFormat_MP4V)
|
||||
return "MFVideoFormat_MP4V";
|
||||
else if (subtype == MFVideoFormat_WMV1)
|
||||
return "MFVideoFormat_WMV1";
|
||||
else if (subtype == MFVideoFormat_WMV2)
|
||||
return "MFVideoFormat_WMV2";
|
||||
else if (subtype == MFVideoFormat_WMV3)
|
||||
return "MFVideoFormat_WMV3";
|
||||
else if (subtype == MFVideoFormat_WVC1)
|
||||
return "MFVideoFormat_WVC1";
|
||||
else if (subtype == MFVideoFormat_MSS1)
|
||||
return "MFVideoFormat_MSS1";
|
||||
else if (subtype == MFVideoFormat_MSS2)
|
||||
return "MFVideoFormat_MSS2";
|
||||
else if (subtype == MFVideoFormat_MPG1)
|
||||
return "MFVideoFormat_MPG1";
|
||||
else if (subtype == MFVideoFormat_DVSL)
|
||||
return "MFVideoFormat_DVSL";
|
||||
else if (subtype == MFVideoFormat_DVSD)
|
||||
return "MFVideoFormat_DVSD";
|
||||
else if (subtype == MFVideoFormat_DVHD)
|
||||
return "MFVideoFormat_DVHD";
|
||||
else if (subtype == MFVideoFormat_DV25)
|
||||
return "MFVideoFormat_DV25";
|
||||
else if (subtype == MFVideoFormat_DV50)
|
||||
return "MFVideoFormat_DV50";
|
||||
else if (subtype == MFVideoFormat_DVH1)
|
||||
return "MFVideoFormat_DVH1";
|
||||
else if (subtype == MFVideoFormat_DVC)
|
||||
return "MFVideoFormat_DVC";
|
||||
else if (subtype == MFVideoFormat_H264)
|
||||
return "MFVideoFormat_H264";
|
||||
else if (subtype == MFVideoFormat_H265)
|
||||
return "MFVideoFormat_H265";
|
||||
else if (subtype == MFVideoFormat_MJPG)
|
||||
return "MFVideoFormat_MJPG";
|
||||
else if (subtype == MFVideoFormat_420O)
|
||||
return "MFVideoFormat_420O";
|
||||
else if (subtype == MFVideoFormat_HEVC)
|
||||
return "MFVideoFormat_HEVC";
|
||||
else if (subtype == MFVideoFormat_HEVC_ES)
|
||||
return "MFVideoFormat_HEVC_ES";
|
||||
else if (subtype == MFVideoFormat_VP80)
|
||||
return "MFVideoFormat_VP80";
|
||||
else if (subtype == MFVideoFormat_VP90)
|
||||
return "MFVideoFormat_VP90";
|
||||
else if (subtype == MFVideoFormat_ORAW)
|
||||
return "MFVideoFormat_ORAW";
|
||||
else
|
||||
return "Other VideoFormat";
|
||||
}
|
62
src/modules/videoconference/VideoConferenceShared/Logging.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <guiddef.h>
|
||||
#include <system_error>
|
||||
|
||||
#include <wil/com.h>
|
||||
#include <Windows.h>
|
||||
|
||||
void LogToFile(std::string what, const bool verbose = false);
|
||||
void LogToFile(std::wstring what, const bool verbose = false);
|
||||
std::string toMediaTypeString(GUID subtype);
|
||||
|
||||
#define RETURN_IF_FAILED_WITH_LOGGING(val) \
|
||||
hr = (val); \
|
||||
if (FAILED(hr)) \
|
||||
{ \
|
||||
LogToFile(std::string(__FUNCTION__ "() ") + #val + ": " + std::system_category().message(hr)); \
|
||||
return hr; \
|
||||
}
|
||||
|
||||
#define RETURN_NULLPTR_IF_FAILED_WITH_LOGGING(val) \
|
||||
hr = val; \
|
||||
if (FAILED(hr)) \
|
||||
{ \
|
||||
LogToFile(std::string(__FUNCTION__ "() ") + #val + ": " + std::system_category().message(hr)); \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
#define VERBOSE_LOG \
|
||||
std::string functionNameTMPVAR = __FUNCTION__; \
|
||||
LogToFile(std::string(functionNameTMPVAR + " enter"), true); \
|
||||
auto verboseLogOnScopeEnd = wil::scope_exit([&] { \
|
||||
LogToFile(std::string(functionNameTMPVAR + " exit"), true); \
|
||||
});
|
||||
|
||||
#if defined(PowerToysInterop)
|
||||
#undef LOG
|
||||
#define LOG(...)
|
||||
#else
|
||||
#define LOG(str) LogToFile(str, false);
|
||||
#endif
|
||||
|
||||
inline bool failed(HRESULT hr)
|
||||
{
|
||||
return hr != S_OK;
|
||||
}
|
||||
|
||||
inline bool failed(bool val)
|
||||
{
|
||||
return val == false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool failed(wil::com_ptr_nothrow<T>& ptr)
|
||||
{
|
||||
return ptr == nullptr;
|
||||
}
|
||||
|
||||
#define OK_OR_BAIL(expr) \
|
||||
if (failed(expr)) \
|
||||
return {};
|
@ -0,0 +1,152 @@
|
||||
#include "MicrophoneDevice.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
#include <Functiondiscoverykeys_devpkey.h>
|
||||
|
||||
MicrophoneDevice::MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint) :
|
||||
_device{ std::move(device) },
|
||||
_endpoint{ std::move(endpoint) }
|
||||
{
|
||||
if (!_device || !_endpoint)
|
||||
{
|
||||
throw std::logic_error("MicrophoneDevice was initialized with null objects");
|
||||
}
|
||||
_device->GetId(&_id);
|
||||
wil::com_ptr_nothrow<IPropertyStore> props;
|
||||
_device->OpenPropertyStore(
|
||||
STGM_READ, &props);
|
||||
if (props)
|
||||
{
|
||||
props->GetValue(PKEY_Device_FriendlyName, &_friendly_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("MicrophoneDevice::MicrophoneDevice couldn't open property store");
|
||||
}
|
||||
}
|
||||
|
||||
MicrophoneDevice::~MicrophoneDevice()
|
||||
{
|
||||
if (_notifier)
|
||||
{
|
||||
_endpoint->UnregisterControlChangeNotify(_notifier.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool MicrophoneDevice::active() const noexcept
|
||||
{
|
||||
DWORD state = 0;
|
||||
_device->GetState(&state);
|
||||
return state == DEVICE_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
void MicrophoneDevice::set_muted(const bool muted) noexcept
|
||||
{
|
||||
_endpoint->SetMute(muted, nullptr);
|
||||
}
|
||||
|
||||
bool MicrophoneDevice::muted() const noexcept
|
||||
{
|
||||
BOOL muted = FALSE;
|
||||
_endpoint->GetMute(&muted);
|
||||
return muted;
|
||||
}
|
||||
|
||||
void MicrophoneDevice::toggle_muted() noexcept
|
||||
{
|
||||
set_muted(!muted());
|
||||
}
|
||||
|
||||
std::wstring_view MicrophoneDevice::id() const noexcept
|
||||
{
|
||||
return _id ? _id.get() : FALLBACK_ID;
|
||||
}
|
||||
|
||||
std::wstring_view MicrophoneDevice::name() const noexcept
|
||||
{
|
||||
return _friendly_name.pwszVal ? _friendly_name.pwszVal : FALLBACK_NAME;
|
||||
}
|
||||
|
||||
void MicrophoneDevice::set_mute_changed_callback(mute_changed_cb_t callback) noexcept
|
||||
{
|
||||
_mute_changed_callback = std::move(callback);
|
||||
_notifier = winrt::make<VolumeNotifier>(this);
|
||||
|
||||
_endpoint->RegisterControlChangeNotify(_notifier.get());
|
||||
}
|
||||
|
||||
std::optional<MicrophoneDevice> MicrophoneDevice::getDefault()
|
||||
{
|
||||
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||||
if (!deviceEnumerator)
|
||||
{
|
||||
LOG("MicrophoneDevice::getDefault MMDeviceEnumerator returned null");
|
||||
return std::nullopt;
|
||||
}
|
||||
wil::com_ptr_nothrow<IMMDevice> captureDevice;
|
||||
deviceEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &captureDevice);
|
||||
if (!captureDevice)
|
||||
{
|
||||
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||||
return std::nullopt;
|
||||
}
|
||||
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
||||
captureDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
||||
if (!microphoneEndpoint)
|
||||
{
|
||||
LOG("MicrophoneDevice::getDefault captureDevice is null");
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::make_optional<MicrophoneDevice>(std::move(captureDevice), std::move(microphoneEndpoint));
|
||||
}
|
||||
|
||||
std::vector<MicrophoneDevice> MicrophoneDevice::getAllActive()
|
||||
{
|
||||
std::vector<MicrophoneDevice> microphoneDevices;
|
||||
auto deviceEnumerator = wil::CoCreateInstanceNoThrow<MMDeviceEnumerator, IMMDeviceEnumerator>();
|
||||
if (!deviceEnumerator)
|
||||
{
|
||||
LOG("MicrophoneDevice::getAllActive MMDeviceEnumerator returned null");
|
||||
return microphoneDevices;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IMMDeviceCollection> captureDevices;
|
||||
deviceEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &captureDevices);
|
||||
if (!captureDevices)
|
||||
{
|
||||
LOG("MicrophoneDevice::getAllActive EnumAudioEndpoints returned null");
|
||||
return microphoneDevices;
|
||||
}
|
||||
UINT nDevices = 0;
|
||||
captureDevices->GetCount(&nDevices);
|
||||
microphoneDevices.reserve(nDevices);
|
||||
for (UINT i = 0; i < nDevices; ++i)
|
||||
{
|
||||
wil::com_ptr_nothrow<IMMDevice> device;
|
||||
captureDevices->Item(i, &device);
|
||||
if (!device)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
wil::com_ptr_nothrow<IAudioEndpointVolume> microphoneEndpoint;
|
||||
device->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<LPVOID*>(µphoneEndpoint));
|
||||
if (!microphoneEndpoint)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
microphoneDevices.emplace_back(std::move(device), std::move(microphoneEndpoint));
|
||||
}
|
||||
return microphoneDevices;
|
||||
}
|
||||
|
||||
MicrophoneDevice::VolumeNotifier::VolumeNotifier(MicrophoneDevice* subscribedDevice) :
|
||||
_subscribedDevice{ subscribedDevice }
|
||||
{
|
||||
}
|
||||
|
||||
HRESULT __stdcall MicrophoneDevice::VolumeNotifier::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data)
|
||||
{
|
||||
_subscribedDevice->_mute_changed_callback(data->bMuted);
|
||||
return S_OK;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#define NOMINMAX
|
||||
|
||||
#include <Windows.h>
|
||||
#include <Unknwn.h>
|
||||
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <wil/com.h>
|
||||
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include <Mmdeviceapi.h>
|
||||
#include <Endpointvolume.h>
|
||||
|
||||
class MicrophoneDevice
|
||||
{
|
||||
public:
|
||||
using mute_changed_cb_t = std::function<void(bool muted)>;
|
||||
|
||||
private:
|
||||
friend struct VolumeNotifier;
|
||||
|
||||
struct VolumeNotifier : winrt::implements<VolumeNotifier, IAudioEndpointVolumeCallback>
|
||||
{
|
||||
MicrophoneDevice* _subscribedDevice = nullptr;
|
||||
VolumeNotifier(MicrophoneDevice* subscribedDevice);
|
||||
|
||||
virtual HRESULT __stdcall OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA data) override;
|
||||
};
|
||||
|
||||
wil::unique_cotaskmem_string _id;
|
||||
wil::unique_prop_variant _friendly_name;
|
||||
mute_changed_cb_t _mute_changed_callback;
|
||||
winrt::com_ptr<IAudioEndpointVolumeCallback> _notifier;
|
||||
wil::com_ptr_nothrow<IAudioEndpointVolume> _endpoint;
|
||||
wil::com_ptr_nothrow<IMMDevice> _device;
|
||||
|
||||
constexpr static inline std::wstring_view FALLBACK_NAME = L"Unknown device";
|
||||
constexpr static inline std::wstring_view FALLBACK_ID = L"UNKNOWN_ID";
|
||||
|
||||
public:
|
||||
MicrophoneDevice(MicrophoneDevice&&) noexcept = default;
|
||||
MicrophoneDevice(wil::com_ptr_nothrow<IMMDevice> device, wil::com_ptr_nothrow<IAudioEndpointVolume> endpoint);
|
||||
~MicrophoneDevice();
|
||||
|
||||
bool active() const noexcept;
|
||||
void set_muted(const bool muted) noexcept;
|
||||
bool muted() const noexcept;
|
||||
void toggle_muted() noexcept;
|
||||
|
||||
std::wstring_view id() const noexcept;
|
||||
std::wstring_view name() const noexcept;
|
||||
void set_mute_changed_callback(mute_changed_cb_t callback) noexcept;
|
||||
|
||||
static std::optional<MicrophoneDevice> getDefault();
|
||||
static std::vector<MicrophoneDevice> getAllActive();
|
||||
};
|
@ -0,0 +1,188 @@
|
||||
#include "SerializedSharedMemory.h"
|
||||
|
||||
inline char* SerializedSharedMemory::lock_flag_addr() noexcept
|
||||
{
|
||||
return reinterpret_cast<char*>(_memory._data + _memory._size);
|
||||
}
|
||||
|
||||
inline void SerializedSharedMemory::lock() noexcept
|
||||
{
|
||||
if (_read_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while (LOCKED == _InterlockedCompareExchange8(lock_flag_addr(), LOCKED, !LOCKED))
|
||||
{
|
||||
while (*lock_flag_addr() == LOCKED)
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void SerializedSharedMemory::unlock() noexcept
|
||||
{
|
||||
if (_read_only)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_InterlockedExchange8(lock_flag_addr(), !LOCKED);
|
||||
}
|
||||
|
||||
SerializedSharedMemory::SerializedSharedMemory(std::array<wil::unique_handle, 2> handles,
|
||||
memory_t memory,
|
||||
const bool readonly) noexcept
|
||||
:
|
||||
_handles{ std::move(handles) }, _memory{ std::move(memory) }, _read_only(readonly)
|
||||
{
|
||||
}
|
||||
|
||||
SerializedSharedMemory::~SerializedSharedMemory() noexcept
|
||||
{
|
||||
if (_memory._data)
|
||||
{
|
||||
UnmapViewOfFile(_memory._data);
|
||||
}
|
||||
}
|
||||
|
||||
SerializedSharedMemory::SerializedSharedMemory(SerializedSharedMemory&& rhs) noexcept
|
||||
{
|
||||
*this = std::move(rhs);
|
||||
}
|
||||
|
||||
SerializedSharedMemory& SerializedSharedMemory::operator=(SerializedSharedMemory&& rhs) noexcept
|
||||
{
|
||||
_handles = {};
|
||||
_handles.swap(rhs._handles);
|
||||
_memory = std::move(rhs._memory);
|
||||
rhs._memory = {};
|
||||
_read_only = rhs._read_only;
|
||||
rhs._read_only = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<SerializedSharedMemory> SerializedSharedMemory::create(const std::wstring_view object_name,
|
||||
const size_t size,
|
||||
const bool read_only,
|
||||
SECURITY_ATTRIBUTES* maybe_attributes) noexcept
|
||||
{
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES };
|
||||
if (!maybe_attributes)
|
||||
{
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = false;
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
|
||||
!SetSecurityDescriptorDacl(&sd, true, nullptr, false))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
// We need an extra byte for locking if it's not readonly
|
||||
const ULARGE_INTEGER UISize{ .QuadPart = size + !read_only };
|
||||
|
||||
wil::unique_handle hMapFile{ CreateFileMappingW(INVALID_HANDLE_VALUE,
|
||||
maybe_attributes ? maybe_attributes : &sa,
|
||||
read_only ? PAGE_READONLY : PAGE_READWRITE,
|
||||
UISize.HighPart,
|
||||
UISize.LowPart,
|
||||
object_name.data()) };
|
||||
if (!hMapFile)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
auto shmem = static_cast<uint8_t*>(
|
||||
MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, static_cast<SIZE_T>(UISize.QuadPart)));
|
||||
if (!shmem)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), {} };
|
||||
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only };
|
||||
}
|
||||
|
||||
std::optional<SerializedSharedMemory> SerializedSharedMemory::open(const std::wstring_view object_name,
|
||||
const size_t size,
|
||||
const bool read_only) noexcept
|
||||
{
|
||||
wil::unique_handle hMapFile{ OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, object_name.data()) };
|
||||
if (!hMapFile)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto shmem = static_cast<uint8_t*>(
|
||||
MapViewOfFile(hMapFile.get(), read_only ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, size + !read_only));
|
||||
|
||||
if (!shmem)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), {} };
|
||||
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, size }, read_only };
|
||||
}
|
||||
|
||||
std::optional<SerializedSharedMemory> SerializedSharedMemory::create_readonly(
|
||||
const std::wstring_view object_name,
|
||||
const std::wstring_view file_path,
|
||||
SECURITY_ATTRIBUTES* maybe_attributes) noexcept
|
||||
{
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
SECURITY_ATTRIBUTES sa = { sizeof SECURITY_ATTRIBUTES };
|
||||
if (!maybe_attributes)
|
||||
{
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = false;
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) ||
|
||||
!SetSecurityDescriptorDacl(&sd, true, nullptr, false))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
wil::unique_handle hFile{ CreateFileW(file_path.data(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
maybe_attributes ? maybe_attributes : &sa,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr) };
|
||||
|
||||
if (!hFile)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(hFile.get(), &fileSize))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
wil::unique_handle hMapFile{ CreateFileMappingW(hFile.get(),
|
||||
maybe_attributes ? maybe_attributes : &sa,
|
||||
PAGE_READONLY,
|
||||
fileSize.HighPart,
|
||||
fileSize.LowPart,
|
||||
object_name.data()) };
|
||||
if (!hMapFile)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto shmem = static_cast<uint8_t*>(MapViewOfFile(nullptr, FILE_MAP_READ, 0, 0, static_cast<size_t>(fileSize.QuadPart)));
|
||||
if (shmem)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
std::array<wil::unique_handle, 2> handles = { std::move(hMapFile), std::move(hFile) };
|
||||
|
||||
return SerializedSharedMemory{ std::move(handles), memory_t{ shmem, static_cast<size_t>(fileSize.QuadPart) }, true };
|
||||
}
|
||||
|
||||
void SerializedSharedMemory::access(std::function<void(memory_t)> access_routine) noexcept
|
||||
{
|
||||
lock();
|
||||
access_routine(_memory);
|
||||
unlock();
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <wil/resource.h>
|
||||
#include <functional>
|
||||
#include <array>
|
||||
|
||||
// Wrapper class allowing sharing readonly/writable memory with a serialized access via atomic locking.
|
||||
// Note that it doesn't protect against a 3rd party concurrently modifying physical file contents.
|
||||
class SerializedSharedMemory
|
||||
{
|
||||
public:
|
||||
struct memory_t
|
||||
{
|
||||
uint8_t * _data = nullptr;
|
||||
size_t _size = 0;
|
||||
};
|
||||
|
||||
static std::optional<SerializedSharedMemory> create(const std::wstring_view object_name,
|
||||
const size_t size,
|
||||
const bool read_only,
|
||||
SECURITY_ATTRIBUTES* maybe_attributes = nullptr) noexcept;
|
||||
static std::optional<SerializedSharedMemory> create_readonly(
|
||||
const std::wstring_view object_name,
|
||||
const std::wstring_view file_path,
|
||||
SECURITY_ATTRIBUTES* maybe_attributes = nullptr) noexcept;
|
||||
static std::optional<SerializedSharedMemory> open(const std::wstring_view object_name,
|
||||
const size_t size,
|
||||
const bool read_only) noexcept;
|
||||
|
||||
void access(std::function<void(memory_t)> access_routine) noexcept;
|
||||
inline size_t size() const noexcept { return _memory._size; }
|
||||
|
||||
~SerializedSharedMemory() noexcept;
|
||||
SerializedSharedMemory(SerializedSharedMemory&&) noexcept;
|
||||
SerializedSharedMemory& operator=(SerializedSharedMemory&&) noexcept;
|
||||
|
||||
private:
|
||||
std::array<wil::unique_handle, 2> _handles;
|
||||
memory_t _memory;
|
||||
bool _read_only = true;
|
||||
constexpr static inline int64_t LOCKED = 1;
|
||||
|
||||
char* lock_flag_addr() noexcept;
|
||||
void lock() noexcept;
|
||||
void unlock() noexcept;
|
||||
|
||||
SerializedSharedMemory(std::array<wil::unique_handle, 2> handles, memory_t memory, const bool readonly) noexcept;
|
||||
};
|
@ -0,0 +1,100 @@
|
||||
#include "VideoCaptureDeviceList.h"
|
||||
#include "Logging.h"
|
||||
#include <mfapi.h>
|
||||
#include <Mfidl.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
#include <wil/com.h>
|
||||
|
||||
void VideoCaptureDeviceList::Clear()
|
||||
{
|
||||
for (UINT32 i = 0; i < m_numberDevices; i++)
|
||||
{
|
||||
CoTaskMemFree(m_deviceFriendlyNames[i]);
|
||||
if (m_ppDevices[i])
|
||||
{
|
||||
m_ppDevices[i]->Release();
|
||||
}
|
||||
}
|
||||
CoTaskMemFree(m_ppDevices);
|
||||
m_ppDevices = nullptr;
|
||||
if (m_deviceFriendlyNames)
|
||||
{
|
||||
delete[] m_deviceFriendlyNames;
|
||||
}
|
||||
|
||||
m_deviceFriendlyNames = nullptr;
|
||||
m_numberDevices = 0;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureDeviceList::EnumerateDevices()
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
wil::com_ptr<IMFAttributes> pAttributes;
|
||||
Clear();
|
||||
|
||||
// Initialize an attribute store. We will use this to
|
||||
// specify the enumeration parameters.
|
||||
|
||||
hr = MFCreateAttributes(&pAttributes, 1);
|
||||
|
||||
// Ask for source type = video capture devices
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pAttributes->SetGUID(
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("VideoCaptureDeviceList::EnumerateDevices(): Couldn't MFCreateAttributes");
|
||||
}
|
||||
// Enumerate devices.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFEnumDeviceSources(pAttributes.get(), &m_ppDevices, &m_numberDevices);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("VideoCaptureDeviceList::EnumerateDevices(): Couldn't SetGUID");
|
||||
}
|
||||
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG("VideoCaptureDeviceList::EnumerateDevices(): MFEnumDeviceSources failed");
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_deviceFriendlyNames = new (std::nothrow) wchar_t*[m_numberDevices];
|
||||
for (UINT32 i = 0; i < m_numberDevices; i++)
|
||||
{
|
||||
UINT32 nameLength = 0;
|
||||
m_ppDevices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &m_deviceFriendlyNames[i], &nameLength);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT VideoCaptureDeviceList::GetDevice(UINT32 index, IMFActivate** ppActivate)
|
||||
{
|
||||
if (index >= Count())
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
*ppActivate = m_ppDevices[index];
|
||||
(*ppActivate)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
std::wstring_view VideoCaptureDeviceList::GetDeviceName(UINT32 index)
|
||||
{
|
||||
if (index >= Count())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return m_deviceFriendlyNames[index];
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <mfobjects.h>
|
||||
#include <string_view>
|
||||
|
||||
class VideoCaptureDeviceList
|
||||
{
|
||||
UINT32 m_numberDevices;
|
||||
// TODO: use wil
|
||||
IMFActivate** m_ppDevices = nullptr;
|
||||
wchar_t** m_deviceFriendlyNames = nullptr;
|
||||
|
||||
public:
|
||||
VideoCaptureDeviceList() :
|
||||
m_ppDevices(NULL), m_numberDevices(0)
|
||||
{
|
||||
}
|
||||
~VideoCaptureDeviceList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
UINT32 Count() const { return m_numberDevices; }
|
||||
|
||||
void Clear();
|
||||
HRESULT EnumerateDevices();
|
||||
HRESULT GetDevice(UINT32 index, IMFActivate** ppActivate);
|
||||
std::wstring_view GetDeviceName(UINT32 index);
|
||||
};
|
@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;OneCoreUAP.lib;Mf.lib;Shlwapi.lib;Strmiids.lib;%(AdditionalDependencies);</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{459e0768-7ebd-4c41-bba1-6db3b3815e0a}</ProjectGuid>
|
||||
<RootNamespace>VideoConferenceShared</RootNamespace>
|
||||
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Platform)'!='Win32'">
|
||||
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)'=='Win32'">
|
||||
<OutDir>..\..\..\..\x86\$(Configuration)\modules\VideoConference\</OutDir>
|
||||
<IntDir>..\..\..\..\x86\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)\src\;</AdditionalIncludeDirectories>
|
||||
<DebugInformationFormat Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<Lib>
|
||||
<TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CameraStateUpdateChannels.cpp" />
|
||||
<ClCompile Include="Logging.cpp" />
|
||||
<ClCompile Include="SerializedSharedMemory.cpp" />
|
||||
<ClCompile Include="naming.cpp" />
|
||||
<ClCompile Include="username.cpp" />
|
||||
<ClCompile Include="MicrophoneDevice.cpp" />
|
||||
<ClCompile Include="VideoCaptureDeviceList.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CameraStateUpdateChannels.h" />
|
||||
<ClInclude Include="Logging.h" />
|
||||
<ClInclude Include="SerializedSharedMemory.h" />
|
||||
<ClInclude Include="naming.h" />
|
||||
<ClInclude Include="MicrophoneDevice.h" />
|
||||
<ClInclude Include="VideoCaptureDeviceList.h" />
|
||||
<ClInclude Include="username.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.200519.2\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
19
src/modules/videoconference/VideoConferenceShared/naming.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "naming.h"
|
||||
|
||||
#include "username.h"
|
||||
|
||||
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted)
|
||||
{
|
||||
static const std::optional<std::wstring> username = ObtainActiveUserName();
|
||||
std::wstring result = L"Global\\";
|
||||
if (restricted)
|
||||
{
|
||||
result += L"Restricted\\";
|
||||
}
|
||||
if (username)
|
||||
{
|
||||
result += *username;
|
||||
}
|
||||
result += name;
|
||||
return result;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.200519.2" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
@ -0,0 +1,20 @@
|
||||
#include "username.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wtsapi32.h>
|
||||
|
||||
std::optional<std::wstring> ObtainActiveUserName()
|
||||
{
|
||||
const DWORD sessionId = WTSGetActiveConsoleSessionId();
|
||||
WCHAR* pUserName;
|
||||
DWORD _ = 0;
|
||||
|
||||
if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pUserName, &_))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
WTSGetActiveConsoleSessionId();
|
||||
std::wstring result{ pUserName };
|
||||
WTSFreeMemory(pUserName);
|
||||
return result;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
std::optional<std::wstring> ObtainActiveUserName();
|
||||
|
||||
std::wstring ObtainStableGlobalNameForKernelObject(const std::wstring_view name, const bool restricted);
|
20
src/modules/videoconference/make_cab.ddf
Normal file
@ -0,0 +1,20 @@
|
||||
; Disable default limits
|
||||
.option EXPLICIT
|
||||
.set CabinetFileCountThreshold=0
|
||||
.set FolderFileCountThreshold=0
|
||||
.set FolderSizeThreshold=0
|
||||
.set MaxCabinetSize=0
|
||||
.set MaxDiskFileCount=0
|
||||
.set MaxDiskSize=0
|
||||
|
||||
.set GenerateInf=ON
|
||||
.set Compress=OFF
|
||||
.set Cabinet=ON
|
||||
.set CabinetNameTemplate=driver.cab
|
||||
.set DestinationDir=cab_output
|
||||
.set DiskDirectoryTemplate=driver
|
||||
|
||||
VideoConferenceCustomMediaSource.dll
|
||||
videoconferencevirtualdriver.cat
|
||||
VideoConferenceVirtualDriver.dll
|
||||
VideoConferenceVirtualDriver.inf
|
@ -20,6 +20,7 @@
|
||||
#include <common/updating/updateState.h>
|
||||
#include <common/utils/appMutex.h>
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/os-detect.h>
|
||||
#include <common/utils/processApi.h>
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
@ -43,6 +44,7 @@
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/window.h>
|
||||
#include <common/version/version.h>
|
||||
#include <gdiplus.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -130,7 +132,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
chdir_current_executable();
|
||||
// Load Powertoys DLLs
|
||||
|
||||
const std::array<std::wstring_view, 9> knownModules = {
|
||||
std::vector<std::wstring_view> knownModules = {
|
||||
L"modules/FancyZones/FancyZonesModuleInterface.dll",
|
||||
L"modules/FileExplorerPreview/powerpreview.dll",
|
||||
L"modules/ImageResizer/ImageResizerExt.dll",
|
||||
@ -140,6 +142,8 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
L"modules/ShortcutGuide/ShortcutGuideModuleInterface/ShortcutGuideModuleInterface.dll",
|
||||
L"modules/ColorPicker/ColorPicker.dll",
|
||||
L"modules/Awake/AwakeModuleInterface.dll",
|
||||
// TODO(yuyoyuppe): uncomment when VCM should be enabled
|
||||
//L"modules/VideoConference/VideoConferenceModule.dll"
|
||||
};
|
||||
|
||||
for (const auto& moduleSubdir : knownModules)
|
||||
@ -264,6 +268,10 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
Gdiplus::GdiplusStartupInput gpStartupInput;
|
||||
ULONG_PTR gpToken;
|
||||
GdiplusStartup(&gpToken, &gpStartupInput, NULL);
|
||||
|
||||
winrt::init_apartment();
|
||||
const wchar_t* securityDescriptor =
|
||||
L"O:BA" // Owner: Builtin (local) administrator
|
||||
|
@ -38,7 +38,7 @@
|
||||
<Link>
|
||||
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalDependencies>Shcore.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Shcore.lib;gdiplus.lib;Msi.lib;WindowsApp.lib;taskschd.lib;Rstrtmgr.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<EnableDpiAwareness>false</EnableDpiAwareness>
|
||||
|
@ -80,6 +80,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
}
|
||||
}
|
||||
|
||||
private bool videoConference = true;
|
||||
|
||||
[JsonPropertyName("Video Conference")]
|
||||
public bool VideoConference
|
||||
{
|
||||
get => this.videoConference;
|
||||
set
|
||||
{
|
||||
if (this.videoConference != value)
|
||||
{
|
||||
LogTelemetryEvent(value);
|
||||
this.videoConference = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool powerRename = true;
|
||||
|
||||
public bool PowerRename
|
||||
|
@ -58,4 +58,11 @@
|
||||
<ProjectReference Include="..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Forms.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|