mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
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>
This commit is contained in:
@@ -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
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
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
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);
|
||||
Reference in New Issue
Block a user