Closed Gordin closed 3 years ago
I was actually trying to do something similar because of Valve's decision to use DisplayPort for the audio instead of USB (video driver updates can change the Index audio's device ID). I wanted to validate that OBS had a valid audio device set. Unfortunately, it seems you can't get a list of available audio output devices in Unity (they only have an API for input devices). I might try looking for a library I can ILMerge into OBSControl to deal with listing devices, but it might be awhile.
If you want, you can start a PR with a class that can get a list of audio devices and add the option to the config. I can deal with integrating it into the mod later (and you could have your own build that sets it in OBS inside OBSController.OnConnect(object, EventArgs)
)
Ah, so I'm not the only one with that problem ^^ If I find time I might look into implementing something then.
In case anyone else with the same problem sees this, for now I'm using this script I wrote: https://github.com/Gordin/obs-audio-fixer It's not really ready for use if you are unfamiliar with python (no README yet), but it works. It connects to OBS via WebSockets and sets the Audio devices according to the config. It will also list out all possible devices on the system, they should be the same as the ones selectable in OBS. The human-readable names can be used in the config at the top of the file.
Sample output:
Available audio output devices:
Headphones (2- Rift S)
Digital Audio (S/PDIF) (High Definition Audio Device)
Speakers (USB Audio Device)
Acer CB241H (NVIDIA High Definition Audio)
Available audio input devices:
Microphone (USB Audio Device)
Headset Microphone (Rift S)
Default Audio Input (for this script) set to 'Headset Microphone (Rift S)'
Default Audio Output (for this script) set to 'Speakers (USB Audio Device)'
OBS WebSocket connection established.
Desktop Audio is set to 'Speakers (USB Audio Device)'
Mic/Aux is set to 'Headset Microphone (Rift S)'
Mic/Aux 2 is set to a device-id unknown to Windows: '{0.0.1.00000000}.{c82a60d9-22a9-4e22-a46a-041b7fe568ad}'
Setting Input devices
Setting OBS source Mic/Aux to Windows device Headset Microphone (Rift S)
Setting OBS source Mic/Aux 2 to Windows device Headset Microphone (Rift S)
Setting Output devices
Setting OBS source Desktop Audio to Windows device Speakers (USB Audio Device)
OBS WebSocket disconnected.
I've been playing around with the project and I found the "NAudio" NuGet package https://www.nuget.org/packages/NAudio/ It has functions that will list the GUID and human-readable names for audio devices very easily, I can list my devices at least in the debugger. I have no idea about the C#/Windows/NuGet/Beat Saber Mods infrastructure though, so I have no idea if adding a package to the project could be a problem or not (apart from maybe the size of the Mod DLL). Can I just add NuGet packages for stuff that I need to the project and the resulting plugin will work on other machines?
Almost, but not quite. I'm using ILRepack to merge my Nugets into the OBSControl.dll
. I can confirm the NAudio Nuget works with this. You can add the Nuget and add a line to ILRepack.targets
: <InputAssemblies Include="NAudio.dll" />
below <InputAssemblies Include="WebSocket4Net.dll" />
Ah, I'll try that :)
Is there an easy way to test the OBS Websocket stuff in a test (or any other way that doesn't require to have BeatSaber running) with a real OBS instance? Right now I have this:
It connects to OBS fine, but on the
.GetSpecialSources()
call it just dies. Doesn't even stop at an exception, it just quits the debugging interface and I have this in the log
OBSControl is working off this branch of obs-websocket-dotnet
, there's a TestClient project using Windows Forms that you can use to test things.
Thanks the TestClient from from-websocket-dotnet helped ^^
Also, working in Visual Studio is kinda horrible, but I'm getting somewhere...
I dropped NAudio for CSCore (which is what NAudio is using internally anyway), because NAudio has a couple other dependencies and would crash when trying to get the devices Beat Saber.
Got it working :)
So far, OBSControl fetches the system devices, OBS devices and OBS sources and it can set any source to an audio device based on its "friendlyName". I still have to read/write the config file, add one dropdown for each OBS source, and make sure all devices are set when a recording starts. I think your code should have examples for everything I need ^^
Nice, this should give me more motivation to finish the refactor I'm working on too.
Nice ^.^
When I'm done I'll have to refactor my stuff as well. Right now I have a million Logger.log.Debug
statements in there... Usually I work with debuggers instead of printing everything, but I couldn't figure out how to run Beat Saber with a debugger attached to the Plugin. It also doesn't help that Exceptions don't seem to go into the log unless you catch them and log them yourself.
Right now my process is write code => build => Start Beat Saber =>Quit Beat Saber => Read the Log file => repeat, but this time with more logs...
Is there anything I can improve about this?
Is there any way to attach a debugger or is this just not possible for Beat Saber plugins?
Or is there a way to reload a plugin DLL without having to completely restart Beat Saber?
Both of these would speed things up a lot, but I couldn't find any information about this.
Last commit from my PR now sets the configured devices from the config when Beat Saber starts :) Also, all devices now have shortened names, so they fit in the dropdown menus now... It's not ready for merge, but you could try it out. Here is a preview (watch with sound, obviously...) https://www.youtube.com/watch?v=pxZlsZMMlnE I still need to make it so it sets the configured devices every time before a song starts and not just when Beat Saber starts, and probably add some code to handle when devices from the config file aren't connected when the Plugin tries to set them. It should already work, but I haven't' tested it, so there are probably some Null-Reference-Exceptions somewhere...
Oh, could you tell me what the problem is with the builds by GitHub Actions? It fails when trying to do a wget ... bsfiles.zip
from a FILES_URL variable that is empty and I have no idea what that is supposed to be...
The zip is a clone of my Beat Saber game directory with all the DLLs stripped of their contents. Some modders used to include them in the repo for CI, but Beat Game would prefer we didn't do that. In my repo, I have a secret
with a link to zip that the Action downloads and extracts, but I guess the secret
doesn't work for PRs.
@Zingabopp you can take a look at the branch now if you like. The Menus now remember all devices that were in the list across restarts and show you when a device is not available or a source is disabled in OBS. It also now sets the devices every time a song starts
Also, I'm not that proud of the code, I tried my best not to copy&paste stuff, but having 6 possible sources makes it really hard, because as far as I can tell, everything I want to use in the bsml file has to be a separate variable :/ If You could put something like value=~someArray["desktop-1"].value
in the bsml file I could reduce the code a lot but from the documentation that isn't how it works, so there is a lot of Desktop1..., Desktop2.... , Mic1..., Mic2..., Mic3..., Mic4...
in the code...
Added in v2.0.0
btw, have you tested this again in the latest versions? It hasn't been working for me since at least 0.13.4. I'm going to look into it... (It just shows me "default" for all devices)
I haven't tested it lately. There is a bug where if an output and input device have the same name it breaks (duplicate key in the dictionary).
Ah, I see what the problem is. For something called Speakers (Some Name)
it tries to use Speakers
as short name, when it should be using Some Name
... I remember there was some weird naming differences between Inputs and Outputs, for outputs the part in ( )
is the actual name, and for inputs the part before the ( )
is the name. Looking into it...
Actually, that convention seems to have changed, which is why it is using the wrong part of the name. No idea if this is a change in some Windows 10 update or some library >_>
Nevermind, looks like both versions don't work if you have a certain combination of devices... Guess I'll have to rewrite this to use UUIDs internally instead of the short names...
Sometimes the configuration of my Audio Devices changes (Sometimes Windows decides that one of my monitors is supposed to output Audio instead of my USB Sound card, or the Oculus software re-adds the Headsets Audio to the Windows audio devices, and Windows will switch to it). This can sometimes lead to OBS forgetting which audio device it should record from. I've recorded videos multiple times only to find out afterwards that my videos don't actually have any sound because of this :/
To prevent this from happening I wrote a small script that will set the correct audio devices with the OBS Websocket plugin with the
SetSourceSettings
command. It would be awesome if something like this could be added to OBSControl as an option (even if just available through editing the JSON file).Here is (part of) a python example of setting my Desktop Audio to my USB sound card and my Mic to the Windows default. Available (configured) audio inputs can be listed with the
GetSpecialSources
command andGetSourceSettings
can be used to get the uuid of the currently selected device. Unfortunately it seems to me that the OBS Websocket API does not expose the human-readable names for the audio devices :( The device uuid I'm setting in the example shows up atSpeakers (USB Audio Device)
in OBS butGetSourceSettings
only shows the uuid. Right now I'm using thesoundcard
python library to get a mapping between the human-readable names, I'm guessing OBSControl would need some C# library to get the names as well.Would you be willing to add something like this to OBSControl? If you don't have time but would accept a PR I might try to add this myself, I have zero experience with writing Beat Saber plugins though...