TooTallNate / node-speaker

Output PCM audio data to the speakers
648 stars 145 forks source link

Selecting devices under windows #147

Closed Xeonzinc closed 3 years ago

Xeonzinc commented 4 years ago

Hi, can anyone assist with how to select devices under windows. I have the following device details (from a separate package), an example of two are shown below. I've attempted to use the id as described in the documentation {device: 'hw:0,6'} but the output only ever seems to come out the default device. I'm not sure how to reference my usb audio outputs via node-speaker?

  {
    id: 5,
    name: 'Realtek HD Audio 2nd output (2-',
    maxInputChannels: 0,
    maxOutputChannels: 2,
    defaultSampleRate: 44100,
    defaultLowInputLatency: 0.09,
    defaultLowOutputLatency: 0.09,
    defaultHighInputLatency: 0.18,
    defaultHighOutputLatency: 0.18,
    hostAPIName: 'MME'
  },
  {
    id: 6,
    name: 'Speakers (USB PnP Sound Device)',
    maxInputChannels: 0,
    maxOutputChannels: 2,
    defaultSampleRate: 44100,
    defaultLowInputLatency: 0.09,
    defaultLowOutputLatency: 0.09,
    defaultHighInputLatency: 0.18,
    defaultHighOutputLatency: 0.18,
    hostAPIName: 'MME'
  },
Xeonzinc commented 4 years ago

Just stumbled across this: https://sourceforge.net/p/mpg123/bugs/288/

I'm not sure if this means it's not possible to select output devices under windows with node-speaker then?

nacgarg commented 3 years ago

Just submitted a PR to fix this (https://github.com/TooTallNate/node-speaker/pull/154) since I was running into the same problem.

Xeonzinc commented 3 years ago

I've been testing your version (by forking and releasing privately), but don't seem to be having much luck. I threw in a couple of printf's to see whats going on, but it always seems to think I am not specifying a device. i.e. i always get "Test2b" not "Test2a" from the below:

    if (ao->device) {
        /* Find device id of device with the same name as ao->device */
        /* Device names from waveOutGetDevCaps are limited to 32  */ 
        /* characters, so truncate ao->device for comparison */ 
        printf("Test2a");
        ao->device[31] = '\0';
        for (UINT i = 0; i < waveOutGetNumDevs(); ++i) {
            WAVEOUTCAPS caps;
            waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS));
            if (!strcmp(ao->device, caps.szPname)) {
                dev_id = i;
                break;
            }
        }
    } else {
        printf("Test2b");
        ao->device = "WaveMapper";
    }

@nacgarg did you initialise the speaker object and define the output device differently to my code below? I'm not sure why my device is not getting passed through. Dev_n is my long device name (e.g. "Speakers (USB PnP Sound Device)"), but even if that was spelt wrong it should still try to first if branch?

this.ospeaker = require('speaker');
this.audio_devices_array[a_num].ao = new this.ospeaker({
                      channels: 2,
                      bitDepth: 16,
                      sampleRate: 48000,  
                      device: dev_n
                    });
nacgarg commented 3 years ago

Hmm, that's strange. I'm initializing the speaker object pretty much the same way as you. Can you check to see if ao->device is defined here (maybe add a printf("device: %s", ao->device))? https://github.com/TooTallNate/node-speaker/blob/master/src/binding.c#L60

nacgarg commented 3 years ago

Also, if you want to test my fork without going through the hassle of privately releasing, you can just add "speaker": "https://github.com/nacgarg/node-speaker" to your package.json IIRC.

Xeonzinc commented 3 years ago

It seems that " if (is_string(env, args[3])) {" is not resolving true, so line 60 never gets called. Not sure why right now, I'm learning C++ as we go! I'll see if I can get any more details out later.

Thanks on the second point, I thought my way seemed a bit excessive, I'm still getting to grips with Github

nacgarg commented 3 years ago

Interesting, do you want to try just passing the string in directly? Maybe there's something strange with your dev_n string? So try something like

new this.ospeaker({
    channels: 2,
    bitDepth: 16,
    sampleRate: 48000,  
    device: "Speakers (USB PnP Sound Device)"
});
Xeonzinc commented 3 years ago

I've managed to get the output selection working, the correct device name was being passed to the audio object constructor in index.js, but when the open event was called this has been replaced by another 'device' object which I was defining elsewhere. I must have some bad 'this' scoping somewhere, but it was resolved by a quick rename of my other device variable.