fix(audio-info): crash when device name contains special characters (#4095)

This commit is contained in:
David Lane
2026-01-16 22:41:23 -05:00
committed by GitHub
parent fd2bfaac7e
commit ab52e27e0e
14 changed files with 476 additions and 163 deletions

View File

@ -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)) {