Jelajahi Sumber

win-wasapi: Don't reconnect when inactive

Unnecessary reconnect attempts may cause noticeable hitches.
jpark37 3 tahun lalu
induk
melakukan
8efb109144
1 mengubah file dengan 63 tambahan dan 11 penghapusan
  1. 63 11
      plugins/win-wasapi/win-wasapi.cpp

+ 63 - 11
plugins/win-wasapi/win-wasapi.cpp

@@ -182,7 +182,7 @@ class WASAPISource {
 	std::atomic<bool> isDefaultDevice = false;
 
 	bool previouslyFailed = false;
-	WinHandle reconnectThread;
+	WinHandle reconnectThread = NULL;
 
 	class CallbackStartCapture : public ARtwqAsyncCallback {
 	public:
@@ -238,6 +238,7 @@ class WASAPISource {
 	WinHandle stopSignal;
 	WinHandle receiveSignal;
 	WinHandle restartSignal;
+	WinHandle reconnectExitSignal;
 	WinHandle exitSignal;
 	WinHandle initSignal;
 	DWORD reconnectDuration = 0;
@@ -298,6 +299,9 @@ public:
 	void Update(obs_data_t *settings);
 	void OnWindowChanged(obs_data_t *settings);
 
+	void Activate();
+	void Deactivate();
+
 	void SetDefaultDevice(EDataFlow flow, ERole role, LPCWSTR id);
 
 	void OnStartCapture();
@@ -390,6 +394,10 @@ WASAPISource::WASAPISource(obs_data_t *settings, obs_source_t *source_,
 	if (!restartSignal.Valid())
 		throw "Could not create restart signal";
 
+	reconnectExitSignal = CreateEvent(nullptr, true, false, nullptr);
+	if (!reconnectExitSignal.Valid())
+		throw "Could not create reconnect exit signal";
+
 	exitSignal = CreateEvent(nullptr, true, false, nullptr);
 	if (!exitSignal.Valid())
 		throw "Could not create exit signal";
@@ -402,11 +410,6 @@ WASAPISource::WASAPISource(obs_data_t *settings, obs_source_t *source_,
 	if (!reconnectSignal.Valid())
 		throw "Could not create reconnect signal";
 
-	reconnectThread = CreateThread(
-		nullptr, 0, WASAPISource::ReconnectThread, this, 0, nullptr);
-	if (!reconnectThread.Valid())
-		throw "Failed to create reconnect thread";
-
 	notify = new WASAPINotify(this);
 	if (!notify)
 		throw "Could not create WASAPINotify";
@@ -525,6 +528,9 @@ void WASAPISource::Start()
 
 void WASAPISource::Stop()
 {
+	if (!reconnectThread.Valid())
+		WaitForSingleObject(reconnectSignal, INFINITE);
+
 	SetEvent(stopSignal);
 
 	blog(LOG_INFO, "WASAPI: Device '%s' Terminated", device_name.c_str());
@@ -532,11 +538,15 @@ void WASAPISource::Stop()
 	if (rtwq_supported)
 		SetEvent(receiveSignal);
 
-	WaitForSingleObject(idleSignal, INFINITE);
+	if (reconnectThread.Valid())
+		WaitForSingleObject(idleSignal, INFINITE);
 
 	SetEvent(exitSignal);
 
-	WaitForSingleObject(reconnectThread, INFINITE);
+	if (reconnectThread.Valid()) {
+		SetEvent(reconnectExitSignal);
+		WaitForSingleObject(reconnectThread, INFINITE);
+	}
 
 	if (rtwq_supported)
 		rtwq_unlock_work_queue(sampleReady.GetQueueId());
@@ -657,6 +667,25 @@ void WASAPISource::OnWindowChanged(obs_data_t *settings)
 		SetEvent(restartSignal);
 }
 
+void WASAPISource::Activate()
+{
+	if (!reconnectThread.Valid()) {
+		ResetEvent(reconnectExitSignal);
+		reconnectThread = CreateThread(nullptr, 0,
+					       WASAPISource::ReconnectThread,
+					       this, 0, nullptr);
+	}
+}
+
+void WASAPISource::Deactivate()
+{
+	if (reconnectThread.Valid()) {
+		SetEvent(reconnectExitSignal);
+		WaitForSingleObject(reconnectThread, INFINITE);
+		reconnectThread = NULL;
+	}
+}
+
 ComPtr<IMMDevice> WASAPISource::InitDevice(IMMDeviceEnumerator *enumerator,
 					   bool isDefaultDevice,
 					   SourceType type,
@@ -1005,10 +1034,15 @@ DWORD WINAPI WASAPISource::ReconnectThread(LPVOID param)
 	WASAPISource *source = (WASAPISource *)param;
 
 	const HANDLE sigs[] = {
-		source->exitSignal,
+		source->reconnectExitSignal,
 		source->reconnectSignal,
 	};
 
+	const HANDLE reconnect_sigs[] = {
+		source->reconnectExitSignal,
+		source->stopSignal,
+	};
+
 	bool exit = false;
 	while (!exit) {
 		const DWORD ret = WaitForMultipleObjects(_countof(sigs), sigs,
@@ -1020,8 +1054,10 @@ DWORD WINAPI WASAPISource::ReconnectThread(LPVOID param)
 		default:
 			assert(ret == (WAIT_OBJECT_0 + 1));
 			if (source->reconnectDuration > 0) {
-				WaitForSingleObject(source->stopSignal,
-						    source->reconnectDuration);
+				WaitForMultipleObjects(
+					_countof(reconnect_sigs),
+					reconnect_sigs, false,
+					source->reconnectDuration);
 			}
 			source->Start();
 		}
@@ -1426,6 +1462,16 @@ static void UpdateWASAPISource(void *obj, obs_data_t *settings)
 	static_cast<WASAPISource *>(obj)->Update(settings);
 }
 
+static void ActivateWASAPISource(void *obj)
+{
+	static_cast<WASAPISource *>(obj)->Activate();
+}
+
+static void DeactivateWASAPISource(void *obj)
+{
+	static_cast<WASAPISource *>(obj)->Deactivate();
+}
+
 static bool UpdateWASAPIMethod(obs_properties_t *props, obs_property_t *,
 			       obs_data_t *settings)
 {
@@ -1542,6 +1588,8 @@ void RegisterWASAPIInput()
 	info.create = CreateWASAPIInput;
 	info.destroy = DestroyWASAPISource;
 	info.update = UpdateWASAPISource;
+	info.activate = ActivateWASAPISource;
+	info.deactivate = DeactivateWASAPISource;
 	info.get_defaults = GetWASAPIDefaultsInput;
 	info.get_properties = GetWASAPIPropertiesInput;
 	info.icon_type = OBS_ICON_TYPE_AUDIO_INPUT;
@@ -1559,6 +1607,8 @@ void RegisterWASAPIDeviceOutput()
 	info.create = CreateWASAPIDeviceOutput;
 	info.destroy = DestroyWASAPISource;
 	info.update = UpdateWASAPISource;
+	info.activate = ActivateWASAPISource;
+	info.deactivate = DeactivateWASAPISource;
 	info.get_defaults = GetWASAPIDefaultsDeviceOutput;
 	info.get_properties = GetWASAPIPropertiesDeviceOutput;
 	info.icon_type = OBS_ICON_TYPE_AUDIO_OUTPUT;
@@ -1576,6 +1626,8 @@ void RegisterWASAPIProcessOutput()
 	info.create = CreateWASAPIProcessOutput;
 	info.destroy = DestroyWASAPISource;
 	info.update = UpdateWASAPISource;
+	info.activate = ActivateWASAPISource;
+	info.deactivate = DeactivateWASAPISource;
 	info.get_defaults = GetWASAPIDefaultsProcessOutput;
 	info.get_properties = GetWASAPIPropertiesProcessOutput;
 	info.icon_type = OBS_ICON_TYPE_PROCESS_AUDIO_OUTPUT;