thestk / rtaudio

A set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound, ASIO, and WASAPI) operating systems.
Other
1.49k stars 318 forks source link

Default input device for DS is not the default input device #354

Closed jontio closed 2 years ago

jontio commented 2 years ago

Windows 10 with Mingw 64 bit.

Calling getDefaultInputDevice() from the DS API returns 0. Then getting the getDeviceInfo for that device returns isDefaultInput as false.

Looking at the DS API both getDefaultInputDevice() and getDefaultOutputDevice() are hard coded to return 0.

Looking how DS devices are enumerated the output devices come before the input devices. I've also noticed that the first device with non zero input channels is called Primary Sound Capture Driver. Surely this should be returned as the default input device?

Here is some code to put into the tests folder to demonstrate...

ds_test.pro

QT += core
QT -= gui
CONFIG += c++11
TARGET = ds_test
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
    ../RtAudio.cpp
DEFINES += QT_DEPRECATED_WARNINGS
DEFINES += __WINDOWS_DS__
LIBS    += -lole32 -lwinmm -ldsound
HEADERS += \
    ../RtAudio.h

main.cpp

#include <QDebug>
#include "../RtAudio.h"

uint getActualDefaultInputDeviceForMySystemAtLeast()
{
    RtAudio audio;
    uint deviceCount=audio.getDeviceCount();
    for(uint k=0;k<deviceCount;k++)
    {
        RtAudio::DeviceInfo info=audio.getDeviceInfo(k);
        if(info.inputChannels>0)
        {
            return(k);
        }
    }
    return 0;
}

bool findDefaultInputDevice()
{
    RtAudio audio;
    uint deviceCount=audio.getDeviceCount();
    for(uint k=0;k<deviceCount;k++)
    {
        RtAudio::DeviceInfo info=audio.getDeviceInfo(k);
        if(info.isDefaultInput)
        {
            return true;
        }
    }
    return false;
}

void listDeviceNames()
{
    RtAudio audio;
    uint deviceCount=audio.getDeviceCount();
    for(uint k=0;k<deviceCount;k++)
    {
        RtAudio::DeviceInfo info=audio.getDeviceInfo(k);
        if(info.probed)
        {
            qDebug()<<k<<QString::fromStdString(info.name);
        }
    }
}

int main(int argc, char *argv[])
{
    Q_UNUSED(argc);
    Q_UNUSED(argv);
    RtAudio audio;
    RtAudio::DeviceInfo info;

    //list devices
    qDebug()<<"Device names:";
    listDeviceNames();
    qDebug()<<"";

    //correct output device and says it's the default output device
    uint defaultOutputDevice=audio.getDefaultOutputDevice();
    info=audio.getDeviceInfo(defaultOutputDevice);
    qDebug()<<"default output index:"<<defaultOutputDevice<<"name:"<<QString::fromStdString(info.name)\
           <<"input:"<<info.inputChannels<<"output:"<<info.outputChannels\
           <<"info.isDefaultOutput"<<info.isDefaultOutput;

    //wrong says it's not the default output device and has 0 input channels
    uint defaultInputDevice=audio.getDefaultInputDevice();
    info=audio.getDeviceInfo(defaultInputDevice);
    qDebug()<<"default input index:"<<defaultInputDevice<<"name:"<<QString::fromStdString(info.name)\
           <<"input:"<<info.inputChannels<<"output:"<<info.outputChannels\
           <<"info.isDefaultInput"<<info.isDefaultInput;

    //infact none of the devices says thay are the default input device
    if(findDefaultInputDevice())
    {
        qDebug()<<"found default input device";
    }
    else
    {
        qDebug()<<"failed to find default input device";
    }

    //returns the first device that has nonzero input channels.
    //this for my setup at least always returns the correct
    //device even when I change the default device in the windows
    //sound settings. I've checked this with a program I wrote.
    //So I think this is what the DS implimentation of the API
    //should return.
    uint actualDefaultInputDevice=getActualDefaultInputDeviceForMySystemAtLeast();
    info=audio.getDeviceInfo(actualDefaultInputDevice);
    qDebug()<<"actual default input index:"<<actualDefaultInputDevice<<"name:"<<QString::fromStdString(info.name)\
           <<"input:"<<info.inputChannels<<"output:"<<info.outputChannels\
           <<"info.isDefaultInput"<<info.isDefaultInput;

    return 0;
}

The output is...

Device names:
0 "Primary Sound Driver"
1 "Hi-Fi Cable Input (VB-Audio Hi-Fi Cable)"
2 "Digital Audio (S/PDIF) (2- High Definition Audio Device)"
3 "Digital Audio (HDMI) (High Definition Audio Device)"
4 "Speakers (3- USB Advanced Audio Device)"
5 "CABLE Input (VB-Audio Virtual Cable)"
6 "Primary Sound Capture Driver"
7 "Microphone (3- USB Advanced Audio Device)"
8 "CABLE Output (VB-Audio Virtual Cable)"
9 "Hi-Fi Cable Output (VB-Audio Hi-Fi Cable)"

default output index: 0 name: "Primary Sound Driver" input: 0 output: 2 info.isDefaultOutput true
default input index: 0 name: "Primary Sound Driver" input: 0 output: 2 info.isDefaultInput false
failed to find default input device
actual default input index: 6 name: "Primary Sound Capture Driver" input: 2 output: 0 info.isDefaultInput false

(qmake && mingw32-make to build BTW)

I have another program that uses the input (a modem) and changing the default input of the windows settings does indeed change the device that device index 6 points to. So I think the DS API for getDefaultInputDevice() should be changed to something like...

unsigned int RtApiDs :: getDefaultInputDevice( void )
{
  unsigned int nDevices = getDeviceCount();
  for ( unsigned int i = 0; i < nDevices; i++ ) {
    if ( getDeviceInfo( i ).inputChannels > 0 ) {
      return i;
    }
  }
  return 0;
}

Does anyone have any thoughts on the matter?

garyscavone commented 2 years ago

The default input and output devices for DS are always identified with a device ID = 0 and the names of "Primary Sound ... Driver". And the devices that are currently the defaults will also appear in the list under their manufacturer names. That's just the way that the crappy DS system works. That said, the index for the "Primary Sound ... Driver" should always indicate itself as being the default. I reworked some of the device querying in the "newdeviceselection" branch and that is hopefully cleaned up to some extent. I'll merge that branch into master at some point in the coming months.

jontio commented 2 years ago

Ah thanks. I checked out newdeviceselection branch ( commit 84c9928 ) and that branch returns Primary Sound Capture Driver as the default input. So that looks good.

Using the following code...

#include <QDebug>
#include "../RtAudio.h"

void listDeviceNames()
{
    RtAudio audio;
    std::vector<unsigned int> ids=audio.getDeviceIds();
    foreach(unsigned int id,ids)
    {
        qDebug()<<id<<":"<<QString::fromStdString(audio.getDeviceInfo(id).name);
    }
}

int main(int argc, char *argv[])
{
    Q_UNUSED(argc);
    Q_UNUSED(argv);
    RtAudio audio;
    RtAudio::DeviceInfo info;

    //list devices
    qDebug()<<"Device names:";
    listDeviceNames();
    qDebug()<<"";

    //correct output device and says it's the default output device
    uint defaultOutputDevice=audio.getDefaultOutputDevice();
    info=audio.getDeviceInfo(defaultOutputDevice);
    qDebug()<<"default output ID:"<<info.ID<<"name:"<<QString::fromStdString(info.name)\
           <<"input:"<<info.inputChannels<<"output:"<<info.outputChannels\
           <<"info.isDefaultOutput"<<info.isDefaultOutput;

    //correct input device and and says it's the default input device
    uint defaultInputDevice=audio.getDefaultInputDevice();
    info=audio.getDeviceInfo(defaultInputDevice);
    qDebug()<<"default input ID:"<<info.ID<<"name:"<<QString::fromStdString(info.name)\
           <<"input:"<<info.inputChannels<<"output:"<<info.outputChannels\
           <<"info.isDefaultInput"<<info.isDefaultInput;

    return 0;
}

I get...

Device names:
129 : "Primary Sound Driver"
130 : "Hi-Fi Cable Input (VB-Audio Hi-Fi Cable)"
131 : "Digital Audio (S/PDIF) (2- High Definition Audio Device)"
132 : "Digital Audio (HDMI) (High Definition Audio Device)"
133 : "Speakers (3- USB Advanced Audio Device)"
134 : "CABLE Input (VB-Audio Virtual Cable)"
135 : "Primary Sound Capture Driver"
136 : "Hi-Fi Cable Output (VB-Audio Hi-Fi Cable)"
137 : "CABLE Output (VB-Audio Virtual Cable)"
138 : "Microphone (3- USB Advanced Audio Device)"

default output ID: 129 name: "Primary Sound Driver" input: 0 output: 2 info.isDefaultOutput true
default input ID: 135 name: "Primary Sound Capture Driver" input: 2 output: 0 info.isDefaultInput true

Cheers, Jonti