Closed mauvealerts closed 2 years ago
API documentation suggests the cause is probably AUDCLNT_E_DEVICE_INVALIDATED
("The audio session is disconnected on the default audio device.") That makes me think it's an inherent race condition... I don't understand the purpose of this code well enough to speculate about better handling for this case.
IIUC, a SessionEventNotificationClient
instance is 1-1 with a session and SessionWatcher
instance. The SessionWatcher
has the info to construct the SessionKey
, butSessionEventNotificationClient
instance doesn't; the latter is what sends the event.
If that's correct, then we "just" need to plumb pid+session_id through so there's no need to query it in SessionMonitor::RemoveSession
?
Yeah so the reason this code is such a mess is because IAudioSessionNotification
(which we need to create per-device after session enumeration) only gives us session creation notifications (who would care about sessions expiring right?). To get the session expiry notifications we have to register a IAudioSessionEvents
per session which as you have seen is done by each session's SessionWatcher
.
The the SessionWatcher
s themselves need to keep the IAudioSessionControl
around to unregister the IAudioSessionEvents
notification client, but I agree there isn't any need to actually pass the session controls back up through SessionEvents::SessionExpired
. There should be a race issue every time we try to query the PID/SID pair from the session control since there is a chance they arrive already expired in IAudioSessionNotification::OnSessionCreated
but for sure the more common case would be on normal session removal.
If you are wondering why both the PID and SID are used it is because the SID on it's own is not actually unique (lol): if two processes of the same application create two sessions they will share an SID so we must also package it with the PID.
5ecaa981a69e19779d0a5540975e1444f15269c0 should fix all the races, could you give it go and see if the issue persists?
That change looks promising. I'm giving it a go, using a build against OBS main (via #155). I'm not sure I can gain confidence in it tonight... I tried repo-ing the exception with the release version, and just starting+exiting the game ~20 times didn't make it happen.
I'll try to report back in a few days. Feel free to close tho; I can reopen if the issue persists.
Re: Windows API stuff: I note there's IAudioSessionControl2::GetSessionInstanceIdentifier
. I haven't tried it, but sounds like it'd remove the need to cart around the pid. (Please excuse the pun)
It's been a few days and a bunch of restarting games. It's hard to be sure with race conditions, but I think this is likely resolved. Plugin definitely seems to be working fine
I've observed that the plugin seems to stop working sporadically, no longer capturing audio until I restart OBS.
Looking through OBS logs, the exception below seems a likely culprit. This occurred when the game I was capturing exited. Both
game-capture
andwin-capture-audio
should be capturing from the same process. The exception is thrown inSessionMonitor::RemoveSession
on the lineTHROW_IF_FAILED(session_control2->GetSessionIdentifier(session_id_raw.put()));