m1dugh / native-sound-mixer

MIT License
25 stars 13 forks source link

Subscribe to Volume / Mute Changes #17

Closed hrueger closed 1 year ago

hrueger commented 2 years ago

Hi @m1dugh, first of all, thanks for this library. It's working great.

Do you think it is possible to add a feature to be able to subscribe to changes of Volume / Mute?

The Device class could become an EventEmitter and emit mute or volumeChanged Events.

m1dugh commented 2 years ago

I'll be working on it but you can still make a pull request.

hrueger commented 2 years ago

Thanks a lot 👌 Unfortunately, I don't know enough C++ to make that happen ;-)

m1dugh commented 1 year ago

I pushed event listening for devices on develop. For now it is undocumented, I'll document it as soon as I can, it works more or less like an EventEmitter. Therefore, it implements on and removeListener methods, and the signals emitted are mute and volume. As of now, it only works on windows and can be prone to bugs I couldn't find yet.

hrueger commented 1 year ago

Very cool 👍 Thanks for your work. I'm currently trying it out.

One thing I noticed is that when console.logging a Device, it does not show its properties anymore. Before (on master): grafik (and so on)

Now (on develop): grafik

This was done using console.log(require("native-sound-mixer").default.devices).

All the properties (e.g. devices[0].name) work fine, though. It's not a big deal, I just though I'd mention it.

Regarding the events: They're working great for me. The only strange thing I can see is that I get every event twice: grafik

Code ```JS const nsm = require("native-sound-mixer").default; console.log("Starting up"); const devices = nsm.devices; console.log("Devices: ", devices); const defaultOutput = nsm.getDefaultDevice(0); const defaultInput = nsm.getDefaultDevice(1); defaultOutput.on("volume", (volume) => { console.log("Volume changed: ", volume); }); defaultOutput.on("mute", (muted) => { console.log("Muted changed: ", muted); }); ``` However, despite this bug, it's already so much better than polling 👍👍
m1dugh commented 1 year ago

It no longer shows the property, but they can still be called, it is because in the background, the properties are updated, the attributes still exist but are now accessors.

hrueger commented 1 year ago

Ah, makes sense 👍

m1dugh commented 1 year ago

This bug is surprising, I had it, and after i recompiled it worked perferctly fine, it might be some error in the code but maybe try recompiling from develop, in which the listener has been merged.

hrueger commented 1 year ago

OK, I'll try that tomorrow.

hrueger commented 1 year ago

Hm, I still have the same issue with the duplicate events. I'm using the develop branch and ran git pull, npm run clean and npm run build. That should have fixed the bug, right?

Another strange thing I noticed: When I start the script (same code as above) and mute my default output, I get a volume event with the value true? Edit: This happens only once at the start. grafik After that, everything is working as it should (apart from the duplicate events).

m1dugh commented 1 year ago

Ok I guess there might be some overlapping identifiers in your device names the way I identify devices, I'll fix that tomorrow. It might be the same bug causing the volume callback to trigger when the mute event is emitted.

hrueger commented 1 year ago

Here's my Device List if that helps.

Code ```JS const nsm = require("native-sound-mixer").default; console.log("Starting up"); const devices = nsm.devices; console.log("Devices: ", devices); const defaultOutput = nsm.getDefaultDevice(0); const defaultInput = nsm.getDefaultDevice(1); console.table(devices.map((d) => ({name: d.name, type: ["out", "in"][d.type], isDefault: d.name === defaultOutput.name || d.name === defaultInput.name })).sort((a, b) => a.name.localeCompare(b.name))); ```
┌─────────┬──────────────────────────────────────────────────────────┬───────┬───────────┐
│ (index) │                           name                           │ type  │ isDefault │
├─────────┼──────────────────────────────────────────────────────────┼───────┼───────────┤
│    0    │            'Lautsprecher (Realtek(R) Audio)'             │ 'out' │   true    │
│    1    │             'Lautsprecher (Waves SoundGrid)'             │ 'out' │   false   │
│    2    │         'Line In /Microphone (Waves SoundGrid)'          │ 'in'  │   true    │
│    3    │ 'VoiceMeeter Aux Input (VB-Audio VoiceMeeter AUX VAIO)'  │ 'out' │   false   │
│    4    │ 'VoiceMeeter Aux Output (VB-Audio VoiceMeeter AUX VAIO)' │ 'in'  │   false   │
│    5    │     'VoiceMeeter Input (VB-Audio VoiceMeeter VAIO)'      │ 'out' │   false   │
│    6    │     'VoiceMeeter Output (VB-Audio VoiceMeeter VAIO)'     │ 'in'  │   false   │
│    7    │  'VoiceMeeter VAIO3 Input (VB-Audio VoiceMeeter VAIO3)'  │ 'out' │   false   │
│    8    │ 'VoiceMeeter VAIO3 Output (VB-Audio VoiceMeeter VAIO3)'  │ 'in'  │   false   │
│    9    │          'VP249 (NVIDIA High Definition Audio)'          │ 'out' │   false   │
│   10    │          'VP249 (NVIDIA High Definition Audio)'          │ 'out' │   false   │
└─────────┴──────────────────────────────────────────────────────────┴───────┴───────────┘
m1dugh commented 1 year ago

It should be fixed on develop

hrueger commented 1 year ago

The volume true bug is now fixed, however, all events still appear twice.

m1dugh commented 1 year ago

I finally might have spotted the problem (as I was able to reproduce it), it was a stupid thing creating duplicate events when calling getDefaultDevice. I pushed it to the linked branch this time, and opened a MR.

hrueger commented 1 year ago

Duplicate events are hone now 👍 However, I just got the volume true bug again... grafik

Code ```ts const nsm = require("native-sound-mixer").default; console.log("Starting up"); const devices = nsm.devices; console.log("Devices: ", devices); const defaultOutput = nsm.getDefaultDevice(0); const defaultInput = nsm.getDefaultDevice(1); console.table(devices.map((d) => ({name: d.name, type: ["out", "in"][d.type], isDefault: d.name === defaultOutput.name || d.name === defaultInput.name })).sort((a, b) => a.name.localeCompare(b.name))); defaultOutput.on("volume", (volume) => { console.log("Volume changed: ", volume); }); defaultOutput.on("mute", (muted) => { console.log("Muted changed: ", muted); }); ```
m1dugh commented 1 year ago

I tried to solve it on another branch fix-bad-callbacks-in-windows-events. Since I'm not able to reproduce the bug I can't tell whether it is fixed or not. However, I guess this can be triggered when a device triggers at the same time a mute and volume event in the background, leading the 2 callbacks to take the same payload.

hrueger commented 1 year ago

Interesting. Now I get this: grafik The volume value is correct, so I think we can leave it that way 👍 It also works if the volume is not at 100% when I mute the output. I think one event too much is not a big of a problem, what's your opinion on this? Thanks for the quick fix by the way.

m1dugh commented 1 year ago

I don't exactly get the problem above. The volume callback is called when volume is 100% and device is unmuted. Is that it ?

hrueger commented 1 year ago

Exactly. If the first thing I do after starting the script is to mute my audio, I also get a volume event with the current volume. Interestingly, if I change the volume first and then mute my output, everything works as expected.

All those tests were done when starting the script with not muted outputs and then muting them. If I start with a muted output and then unmute it, I only get a volume event and no mute event.

If I start muted and then change the volume (which lets windows automatically unmute the device, I get this: grafik (I only clicked at 30 % volume and then got those 3 callbacks)

m1dugh commented 1 year ago

I'll dig into it, thanks for the testing.

m1dugh commented 1 year ago

It should be fixed, thanks for the detailed explanation of how to reproduce the bug, helped me out a lot.

hrueger commented 1 year ago

Yes, now everything works great and as expected 👍

m1dugh commented 1 year ago

I merged the branch into develop, I will publish the version tomorrow on npm registries.

hrueger commented 1 year ago

Sounds great, thanks a ton 👍

m1dugh commented 1 year ago

I published the latest version to npm registry, The documentation can be found at https://m1dugh.github.io/native-sound-mixer/master/