fix(audio-info): crash when device name contains special characters (#4095)
This commit is contained in:
@@ -2,23 +2,38 @@ cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(sunshine_tools)
|
||||
|
||||
include_directories("${CMAKE_SOURCE_DIR}")
|
||||
include_directories(
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${FFMPEG_INCLUDE_DIRS}" # this is included only for logging
|
||||
)
|
||||
|
||||
add_executable(dxgi-info dxgi.cpp)
|
||||
set(TOOL_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/logging.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/platform/windows/utf_utils.cpp"
|
||||
)
|
||||
|
||||
add_executable(dxgi-info dxgi.cpp ${TOOL_SOURCES})
|
||||
set_target_properties(dxgi-info PROPERTIES CXX_STANDARD 23)
|
||||
target_link_libraries(dxgi-info
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${FFMPEG_LIBRARIES} # this is included only for logging
|
||||
dxgi
|
||||
${PLATFORM_LIBRARIES})
|
||||
libdisplaydevice::display_device # this is included only for logging
|
||||
${PLATFORM_LIBRARIES}
|
||||
)
|
||||
target_compile_options(dxgi-info PRIVATE ${SUNSHINE_COMPILE_OPTIONS})
|
||||
|
||||
add_executable(audio-info audio.cpp)
|
||||
add_executable(audio-info audio.cpp ${TOOL_SOURCES})
|
||||
set_target_properties(audio-info PROPERTIES CXX_STANDARD 23)
|
||||
target_link_libraries(audio-info
|
||||
${Boost_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${FFMPEG_LIBRARIES} # this is included only for logging
|
||||
libdisplaydevice::display_device # this is included only for logging
|
||||
ksuser
|
||||
${PLATFORM_LIBRARIES})
|
||||
${PLATFORM_LIBRARIES}
|
||||
)
|
||||
target_compile_options(audio-info PRIVATE ${SUNSHINE_COMPILE_OPTIONS})
|
||||
|
||||
add_executable(sunshinesvc sunshinesvc.cpp)
|
||||
|
||||
@@ -6,17 +6,13 @@
|
||||
|
||||
// platform includes
|
||||
#include <Audioclient.h>
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <locale>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <roapi.h>
|
||||
#include <synchapi.h>
|
||||
|
||||
// lib includes
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
// local includes
|
||||
#include "src/platform/windows/utf_utils.h"
|
||||
#include "src/utility.h"
|
||||
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
|
||||
@@ -35,7 +31,7 @@ namespace audio {
|
||||
|
||||
template<class T>
|
||||
void co_task_free(T *p) {
|
||||
CoTaskMemFree((LPVOID) p);
|
||||
CoTaskMemFree(static_cast<LPVOID>(p));
|
||||
}
|
||||
|
||||
using device_enum_t = util::safe_ptr<IMMDeviceEnumerator, Release<IMMDeviceEnumerator>>;
|
||||
@@ -63,10 +59,6 @@ namespace audio {
|
||||
PROPVARIANT prop;
|
||||
};
|
||||
|
||||
const wchar_t *no_null(const wchar_t *str) {
|
||||
return str ? str : L"Unknown";
|
||||
}
|
||||
|
||||
struct format_t {
|
||||
std::string_view name;
|
||||
int channels;
|
||||
@@ -118,7 +110,11 @@ namespace audio {
|
||||
wave_format->nAvgBytesPerSec = wave_format->nSamplesPerSec * wave_format->nBlockAlign;
|
||||
|
||||
if (wave_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
((PWAVEFORMATEXTENSIBLE) wave_format.get())->dwChannelMask = format.channel_mask;
|
||||
// Access the extended format through proper offsetting
|
||||
// WAVEFORMATEXTENSIBLE has WAVEFORMATEX as first member, so this is safe
|
||||
const auto ext_format =
|
||||
static_cast<PWAVEFORMATEXTENSIBLE>(static_cast<void *>(wave_format.get()));
|
||||
ext_format->dwChannelMask = format.channel_mask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +124,7 @@ namespace audio {
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL,
|
||||
nullptr,
|
||||
(void **) &audio_client
|
||||
static_cast<void **>(static_cast<void *>(&audio_client))
|
||||
);
|
||||
|
||||
if (FAILED(status)) {
|
||||
@@ -186,7 +182,7 @@ namespace audio {
|
||||
return;
|
||||
}
|
||||
|
||||
std::wstring device_state_string = L"Unknown"s;
|
||||
std::wstring device_state_string;
|
||||
switch (device_state) {
|
||||
case DEVICE_STATE_ACTIVE:
|
||||
device_state_string = L"Active"s;
|
||||
@@ -200,28 +196,36 @@ namespace audio {
|
||||
case DEVICE_STATE_NOTPRESENT:
|
||||
device_state_string = L"Not present"s;
|
||||
break;
|
||||
default:
|
||||
device_state_string = L"Unknown"s;
|
||||
break;
|
||||
}
|
||||
|
||||
std::wstring current_format = L"Unknown"s;
|
||||
std::string current_format = "Unknown";
|
||||
for (const auto &format : formats) {
|
||||
// This will fail for any format that's not the mix format for this device,
|
||||
// so we can take the first match as the current format to display.
|
||||
auto audio_client = make_audio_client(device, format);
|
||||
if (audio_client) {
|
||||
current_format = boost::locale::conv::utf_to_utf<wchar_t>(format.name.data());
|
||||
if (auto audio_client = make_audio_client(device, format)) {
|
||||
current_format = std::string(format.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::wcout
|
||||
<< L"===== Device ====="sv << std::endl
|
||||
<< L"Device ID : "sv << wstring.get() << std::endl
|
||||
<< L"Device name : "sv << no_null((LPWSTR) device_friendly_name.prop.pszVal) << std::endl
|
||||
<< L"Adapter name : "sv << no_null((LPWSTR) adapter_friendly_name.prop.pszVal) << std::endl
|
||||
<< L"Device description : "sv << no_null((LPWSTR) device_desc.prop.pszVal) << std::endl
|
||||
<< L"Device state : "sv << device_state_string << std::endl
|
||||
<< L"Current format : "sv << current_format << std::endl
|
||||
<< std::endl;
|
||||
auto safe_wstring_output = [](const wchar_t *wstr) -> std::string {
|
||||
if (!wstr) {
|
||||
return "Unknown";
|
||||
}
|
||||
return utf_utils::to_utf8(std::wstring(wstr));
|
||||
};
|
||||
|
||||
std::cout << "===== Device =====" << std::endl;
|
||||
std::cout << "Device ID : " << utf_utils::to_utf8(std::wstring(wstring.get())) << std::endl;
|
||||
std::cout << "Device name : " << safe_wstring_output(device_friendly_name.prop.pwszVal) << std::endl;
|
||||
std::cout << "Adapter name : " << safe_wstring_output(adapter_friendly_name.prop.pwszVal) << std::endl;
|
||||
std::cout << "Device description : " << safe_wstring_output(device_desc.prop.pwszVal) << std::endl;
|
||||
std::cout << "Device state : " << utf_utils::to_utf8(device_state_string) << std::endl;
|
||||
std::cout << "Current format : " << current_format << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
} // namespace audio
|
||||
|
||||
@@ -268,15 +272,13 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT status;
|
||||
|
||||
audio::device_enum_t device_enum;
|
||||
status = CoCreateInstance(
|
||||
HRESULT status = CoCreateInstance(
|
||||
CLSID_MMDeviceEnumerator,
|
||||
nullptr,
|
||||
CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator,
|
||||
(void **) &device_enum
|
||||
static_cast<void **>(static_cast<void *>(&device_enum))
|
||||
);
|
||||
|
||||
if (FAILED(status)) {
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
* @brief Displays information about connected displays and GPUs
|
||||
*/
|
||||
#define WINVER 0x0A00
|
||||
#include "src/platform/windows/utf_utils.h"
|
||||
#include "src/utility.h"
|
||||
|
||||
#include <d3dcommon.h>
|
||||
#include <dxgi.h>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std::literals;
|
||||
@@ -20,17 +22,14 @@ namespace dxgi {
|
||||
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
|
||||
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
|
||||
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
|
||||
|
||||
} // namespace dxgi
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
HRESULT status;
|
||||
|
||||
// Set ourselves as per-monitor DPI aware for accurate resolution values on High DPI systems
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
dxgi::factory1_t::pointer factory_p {};
|
||||
status = CreateDXGIFactory1(IID_IDXGIFactory1, (void **) &factory_p);
|
||||
const HRESULT status = CreateDXGIFactory1(IID_IDXGIFactory1, static_cast<void **>(static_cast<void *>(&factory_p)));
|
||||
dxgi::factory1_t factory {factory_p};
|
||||
if (FAILED(status)) {
|
||||
std::cout << "Failed to create DXGIFactory1 [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
|
||||
@@ -44,21 +43,24 @@ int main(int argc, char *argv[]) {
|
||||
DXGI_ADAPTER_DESC1 adapter_desc;
|
||||
adapter->GetDesc1(&adapter_desc);
|
||||
|
||||
std::cout
|
||||
<< "====== ADAPTER ====="sv << std::endl;
|
||||
std::wcout
|
||||
<< L"Device Name : "sv << adapter_desc.Description << std::endl;
|
||||
std::cout
|
||||
<< "Device Vendor ID : 0x"sv << util::hex(adapter_desc.VendorId).to_string_view() << std::endl
|
||||
<< "Device Device ID : 0x"sv << util::hex(adapter_desc.DeviceId).to_string_view() << std::endl
|
||||
<< "Device Video Mem : "sv << adapter_desc.DedicatedVideoMemory / 1048576 << " MiB"sv << std::endl
|
||||
<< "Device Sys Mem : "sv << adapter_desc.DedicatedSystemMemory / 1048576 << " MiB"sv << std::endl
|
||||
<< "Share Sys Mem : "sv << adapter_desc.SharedSystemMemory / 1048576 << " MiB"sv << std::endl
|
||||
<< std::endl
|
||||
<< " ====== OUTPUT ======"sv << std::endl;
|
||||
std::cout << "====== ADAPTER =====" << std::endl;
|
||||
std::cout << "Device Name : " << utf_utils::to_utf8(std::wstring(adapter_desc.Description)) << std::endl;
|
||||
std::cout << "Device Vendor ID : " << "0x" << util::hex(adapter_desc.VendorId).to_string() << std::endl;
|
||||
std::cout << "Device Device ID : " << "0x" << util::hex(adapter_desc.DeviceId).to_string() << std::endl;
|
||||
std::cout << "Device Video Mem : " << std::format("{} MiB", adapter_desc.DedicatedVideoMemory / 1048576) << std::endl;
|
||||
std::cout << "Device Sys Mem : " << std::format("{} MiB", adapter_desc.DedicatedSystemMemory / 1048576) << std::endl;
|
||||
std::cout << "Share Sys Mem : " << std::format("{} MiB", adapter_desc.SharedSystemMemory / 1048576) << std::endl;
|
||||
|
||||
dxgi::output_t::pointer output_p {};
|
||||
bool has_outputs = false;
|
||||
for (int y = 0; adapter->EnumOutputs(y, &output_p) != DXGI_ERROR_NOT_FOUND; ++y) {
|
||||
// Print the header only when we find the first output
|
||||
if (!has_outputs) {
|
||||
std::cout << std::endl
|
||||
<< " ====== OUTPUT ======" << std::endl;
|
||||
has_outputs = true;
|
||||
}
|
||||
|
||||
dxgi::output_t output {output_p};
|
||||
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
@@ -67,13 +69,11 @@ int main(int argc, char *argv[]) {
|
||||
auto width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
|
||||
auto height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;
|
||||
|
||||
std::wcout
|
||||
<< L" Output Name : "sv << desc.DeviceName << std::endl;
|
||||
std::cout
|
||||
<< " AttachedToDesktop : "sv << (desc.AttachedToDesktop ? "yes"sv : "no"sv) << std::endl
|
||||
<< " Resolution : "sv << width << 'x' << height << std::endl
|
||||
<< std::endl;
|
||||
std::cout << " Output Name : " << utf_utils::to_utf8(std::wstring(desc.DeviceName)) << std::endl;
|
||||
std::cout << " AttachedToDesktop : " << (desc.AttachedToDesktop ? "yes" : "no") << std::endl;
|
||||
std::cout << " Resolution : " << std::format("{}x{}", width, height) << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user