mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 07:16:02 +00:00
fix(windows): honor selected microphone in native capture
This commit is contained in:
@@ -3041,6 +3041,9 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
|
||||
const micPath = path.join(recordingsDir, `recording-${timestamp}.mic.wav`)
|
||||
config.captureMic = true
|
||||
config.micOutputPath = micPath
|
||||
if (options.microphoneDeviceId) {
|
||||
config.micDeviceId = options.microphoneDeviceId
|
||||
}
|
||||
if (options.microphoneLabel) {
|
||||
config.micDeviceName = options.microphoneLabel
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ struct CaptureConfig {
|
||||
std::string outputPath;
|
||||
std::string audioOutputPath;
|
||||
std::string micOutputPath;
|
||||
std::string micDeviceId;
|
||||
std::string micDeviceName;
|
||||
int fps = 60;
|
||||
int width = 0;
|
||||
@@ -113,6 +114,7 @@ static bool parseSimpleJson(const std::string& json, CaptureConfig& config) {
|
||||
|
||||
config.audioOutputPath = findString("audioOutputPath");
|
||||
config.micOutputPath = findString("micOutputPath");
|
||||
config.micDeviceId = findString("micDeviceId");
|
||||
config.micDeviceName = findString("micDeviceName");
|
||||
|
||||
auto findBool = [&](const std::string& key) -> bool {
|
||||
@@ -276,7 +278,10 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
if (config.captureMic && !config.micOutputPath.empty()) {
|
||||
micInitialized = micCapture.initializeMic(config.micOutputPath, config.micDeviceName);
|
||||
micInitialized = micCapture.initializeMic(
|
||||
config.micOutputPath,
|
||||
config.micDeviceId,
|
||||
config.micDeviceName);
|
||||
if (!micInitialized) {
|
||||
std::cerr << "WARNING: Failed to initialize WASAPI mic capture" << std::endl;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,36 @@ static std::wstring utf8ToWide(const std::string& str) {
|
||||
return wstr;
|
||||
}
|
||||
|
||||
IMMDevice* WasapiCapture::findCaptureDeviceById(const std::wstring& targetId) {
|
||||
IMMDeviceCollection* collection = nullptr;
|
||||
HRESULT hr = enumerator_->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr)) return nullptr;
|
||||
|
||||
UINT count = 0;
|
||||
collection->GetCount(&count);
|
||||
|
||||
for (UINT i = 0; i < count; i++) {
|
||||
IMMDevice* dev = nullptr;
|
||||
collection->Item(i, &dev);
|
||||
|
||||
LPWSTR deviceId = nullptr;
|
||||
hr = dev->GetId(&deviceId);
|
||||
if (SUCCEEDED(hr) && deviceId) {
|
||||
const bool matches = targetId == deviceId;
|
||||
CoTaskMemFree(deviceId);
|
||||
if (matches) {
|
||||
collection->Release();
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
dev->Release();
|
||||
}
|
||||
|
||||
collection->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IMMDevice* WasapiCapture::findCaptureDeviceByName(const std::wstring& targetName) {
|
||||
IMMDeviceCollection* collection = nullptr;
|
||||
HRESULT hr = enumerator_->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &collection);
|
||||
@@ -37,6 +67,8 @@ IMMDevice* WasapiCapture::findCaptureDeviceByName(const std::wstring& targetName
|
||||
UINT count = 0;
|
||||
collection->GetCount(&count);
|
||||
|
||||
IMMDevice* partialMatch = nullptr;
|
||||
|
||||
for (UINT i = 0; i < count; i++) {
|
||||
IMMDevice* dev = nullptr;
|
||||
collection->Item(i, &dev);
|
||||
@@ -50,15 +82,21 @@ IMMDevice* WasapiCapture::findCaptureDeviceByName(const std::wstring& targetName
|
||||
PropVariantClear(&pv);
|
||||
store->Release();
|
||||
|
||||
if (name.find(targetName) != std::wstring::npos || targetName.find(name) != std::wstring::npos) {
|
||||
if (name == targetName) {
|
||||
collection->Release();
|
||||
return dev;
|
||||
}
|
||||
|
||||
if (!partialMatch && (name.find(targetName) != std::wstring::npos || targetName.find(name) != std::wstring::npos)) {
|
||||
partialMatch = dev;
|
||||
continue;
|
||||
}
|
||||
|
||||
dev->Release();
|
||||
}
|
||||
|
||||
collection->Release();
|
||||
return nullptr;
|
||||
return partialMatch;
|
||||
}
|
||||
|
||||
bool WasapiCapture::initializeLoopback(const std::string& outputPath) {
|
||||
@@ -76,7 +114,10 @@ bool WasapiCapture::initializeLoopback(const std::string& outputPath) {
|
||||
return initializeCommon();
|
||||
}
|
||||
|
||||
bool WasapiCapture::initializeMic(const std::string& outputPath, const std::string& deviceName) {
|
||||
bool WasapiCapture::initializeMic(
|
||||
const std::string& outputPath,
|
||||
const std::string& deviceId,
|
||||
const std::string& deviceName) {
|
||||
outputPath_ = outputPath;
|
||||
streamFlags_ = 0;
|
||||
|
||||
@@ -85,7 +126,10 @@ bool WasapiCapture::initializeMic(const std::string& outputPath, const std::stri
|
||||
IID_IMMDeviceEnumerator_, reinterpret_cast<void**>(&enumerator_));
|
||||
if (FAILED(hr)) return false;
|
||||
|
||||
if (!deviceName.empty()) {
|
||||
if (!deviceId.empty()) {
|
||||
device_ = findCaptureDeviceById(utf8ToWide(deviceId));
|
||||
}
|
||||
if (!device_ && !deviceName.empty()) {
|
||||
device_ = findCaptureDeviceByName(utf8ToWide(deviceName));
|
||||
}
|
||||
if (!device_) {
|
||||
|
||||
@@ -14,7 +14,10 @@ public:
|
||||
~WasapiCapture();
|
||||
|
||||
bool initializeLoopback(const std::string& outputPath);
|
||||
bool initializeMic(const std::string& outputPath, const std::string& deviceName = "");
|
||||
bool initializeMic(
|
||||
const std::string& outputPath,
|
||||
const std::string& deviceId = "",
|
||||
const std::string& deviceName = "");
|
||||
bool start();
|
||||
bool pause();
|
||||
bool resume();
|
||||
@@ -24,6 +27,7 @@ private:
|
||||
bool initializeCommon();
|
||||
void captureThread();
|
||||
bool writeWavHeader(HANDLE file, DWORD dataSize);
|
||||
IMMDevice* findCaptureDeviceById(const std::wstring& id);
|
||||
IMMDevice* findCaptureDeviceByName(const std::wstring& name);
|
||||
|
||||
std::string outputPath_;
|
||||
|
||||
Reference in New Issue
Block a user