QAudioDeviceInfo::availableDevices() not working correctly on latest Windows 10



  • Hi all,

    first off I think this is probably an MS defect that has arrived in a recent update. Nevertheless I wonder if the Windows API code Qt is using to enumerate audio devices on Windows Desktop is perhaps not using the recommended APIs or not using them correctly.

    The problem is that the function above only lists the default input and output device. I have written a short program that uses the APIs used by Qt and I get a similar issue. Here is the main part of my code:

    // audio_devices_enumeration.cpp : Enumerate audio devices like Qt::QAudioDeviceInfo::availableDevices(mode) does.
    //
    
    #include "stdafx.h"
    
    #pragma comment (lib, "strmiids")
    #pragma comment (lib, "winmm")
    
    int enumerate () {
    	CoInitialize (nullptr);
    	ICreateDevEnum *pDevEnum = nullptr;
    	IEnumMoniker *pEnum = nullptr;
    	// Create the System device enumerator
    	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr,
    		CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
    		reinterpret_cast<void **>(&pDevEnum));
    
    	if (SUCCEEDED(hr)) {
    		// Create the enumerator for the audio input/output category
    		if (pDevEnum->CreateClassEnumerator (CLSID_AudioRendererCategory, &pEnum, 0) == S_OK) {
    			pEnum->Reset();
    			// go through and find all audio devices
    			IMoniker *pMoniker = nullptr;
    			unsigned long iNumOutDevs = waveOutGetNumDevs();
    			std::wcout << "number of wave out devices: " << iNumOutDevs << std::endl;
    			while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
    				IPropertyBag *pPropBag;
    				hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
    					reinterpret_cast<void **>(&pPropBag));
    				if (FAILED(hr)) {
    					pMoniker->Release();
    					continue; // skip this one
    				}
    				// Find if it is a wave out device
    				VARIANT var;
    				VariantInit(&var);
    				// Find the description
    				hr = pPropBag->Read(L"FriendlyName", &var, 0);
    				if (SUCCEEDED(hr)) {
    					std::wcout << "Wave out device: name: " << var.bstrVal;
    					VariantClear(&var);
    				}
    				hr = pPropBag->Read (L"WaveOutID", &var, 0);
    				if (SUCCEEDED(hr)) {
    					LONG waveID = var.lVal;
    					std::wcout << " Wave ID: " << waveID;
    				}
    				std::wcout << std::endl;
    
    				pPropBag->Release();
    				pMoniker->Release();
    			}
    
    			std::wcout << std::endl;
    
    			if (pDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnum, 0) == S_OK) {
    				pEnum->Reset();
    				// go through and find all audio devices
    				IMoniker *pMoniker = nullptr;
    				unsigned long iNumInDevs = waveInGetNumDevs();
    				std::wcout << "number of wave in devices: " << iNumInDevs << std::endl;
    				while (pEnum->Next(1, &pMoniker, nullptr) == S_OK) {
    					IPropertyBag *pPropBag;
    					hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
    						reinterpret_cast<void **>(&pPropBag));
    					if (FAILED(hr)) {
    						pMoniker->Release();
    						continue; // skip this one
    					}
    					// Find if it is a wave in device
    					VARIANT var;
    					VariantInit(&var);
    					// Find the description
    					hr = pPropBag->Read(L"FriendlyName", &var, 0);
    					if (SUCCEEDED(hr)) {
    						std::wcout << "Wave in device: name: " << var.bstrVal;
    						VariantClear(&var);
    					}
    					hr = pPropBag->Read(L"WaveInID", &var, 0);
    					if (SUCCEEDED(hr)) {
    						LONG waveID = var.lVal;
    						std::wcout << " Wave ID: " << waveID;
    					}
    					std::wcout << std::endl;
    
    					pPropBag->Release();
    					pMoniker->Release();
    				}
    				pEnum->Release();
    			}
    		}
    		pDevEnum->Release();
    	}
    	CoUninitialize();
    	return 0;
    }
    
    int main()
    {
    	return enumerate();
    }
    

    On my Windows 8.1 dev machine it works as expected with this output:

    number of wave out devices: 3
    Wave out device: name: Speakers (Realtek High Definition Audio) Wave ID: 0
    Wave out device: name: CyberLink Audio Renderer (PDVD10)
    Wave out device: name: Default DirectSound Device
    Wave out device: name: Default WaveOut Device Wave ID: -1
    Wave out device: name: DirectSound: Speakers (Realtek High Definition Audio)
    Wave out device: name: DirectSound: CABLE Input (VB-Audio Virtual Cable)
    Wave out device: name: DirectSound: Realtek Digital Output (Realtek High Definition Audio)
    Wave out device: name: CABLE Input (VB-Audio Virtual Cable) Wave ID: 1
    Wave out device: name: Realtek Digital Output (Realtek High Definition Audio) Wave ID: 2

    number of wave in devices: 3
    Wave in device: name: Microphone (Realtek High Definition Audio) Wave ID: 0
    Wave in device: name: CABLE Output (VB-Audio Virtual Cable) Wave ID: 1
    Wave in device: name: Stereo Mix (Realtek High Definition Audio) Wave ID: 2

    Note the MME devices with WaveIDs 1 and 2 are enumerated as well as the default ones with Wave ID 0.

    When it goes wrong (on a user's Windows 10 x64 version 1703 patched with latest updates KB4016871) I get output like this:

    number of wave out devices: 2
    Wave out device: name: Speakers (Realtek High Definition Audio) Wave ID: 0
    Wave out device: name: Default DirectSound Device
    Wave out device: name: Default WaveOut Device Wave ID: -1
    Wave out device: name: DirectSound: Speakers (Realtek High Definition Audio)

    number of wave in devices: 3
    Wave in device: name: Stereo Mix (Realtek High Definition Audio) Wave ID: 0

    Note that only the default Wave ID 0 MME devices are enumerated.

    Any idea if this is a Qt defect or have MS broken their APIs?

    Regards
    Bill Somerville.


  • Lifetime Qt Champion

    Hi,

    From the looks of it something has change with Windows however it's worth checking the bug report system to see if it's something known.



  • @SGaist There is QTBUG-60839 but that is one of our users reporting the same issue without much detail. The test program I list in my OP fills in the gaps.

    I am pretty sure this is an MS issue, does anyone know how a mere Open Source developer with no MSDN subscription can raise a ticket with MS on this?


  • Lifetime Qt Champion

    Then please, update the content of the bug report with your findings, that will help solve it.



  • I'll add this observation to Bill's question since I've been doing some debugging on this too.
    This does not appear to be a Windows problem...see below...

    The project ends up using qtaudio_windows.dll

    Monitoring with ProcMon I see all the devices enumerated correctly -- no doubt from the DLL.

    So the breakage is in the DLL logic not recognizing the device amongt all the if checks being done.

    Several times people have had problems with enumeration and usually uninstalling drivers fixes it.

    But we have two users who can't seem to get it to work at all. Other applications enumerate the devices correctly. But 3 different Qt applications (including the Audio Example) will not enumerate on these machines.

    I'm trying to add some qDebug to the DLL but the output isn't showing up anywhere. We've got qDebug information going to a file and the statements in the code below don't produce anything. I also tried to to just write to a file and that didnt' work either.
    How can I debug this DLL?
    This is my attempt to get debug info for qwindowsaudiodeviceinfo.cpp

    /****************************************************************************
    **
    ** Copyright (C) 2015 The Qt Company Ltd.
    ** Contact: http://www.qt.io/licensing/
    **
    ** This file is part of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:LGPL21$
    ** Commercial License Usage
    ** Licensees holding valid commercial Qt licenses may use this file in
    ** accordance with the commercial license agreement provided with the
    ** Software or, alternatively, in accordance with the terms contained in
    ** a written agreement between you and The Qt Company. For licensing terms
    ** and conditions see http://www.qt.io/terms-conditions. For further
    ** information use the contact form at http://www.qt.io/contact-us.
    **
    ** GNU Lesser General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU Lesser
    ** General Public License version 2.1 or version 3 as published by the Free
    ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
    ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
    ** following information to ensure the GNU Lesser General Public License
    ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
    ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    **
    ** As a special exception, The Qt Company gives you certain additional
    ** rights. These rights are described in The Qt Company LGPL Exception
    ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/

    //
    // W A R N I N G
    // -------------
    //
    // This file is not part of the Qt API. It exists for the convenience
    // of other Qt classes. This header file may change from version to
    // version without notice, or even be removed.
    //
    // INTERNAL USE ONLY: Do NOT use for any other purpose.
    //

    #include <QtCore/qt_windows.h>
    #include <QtCore/QDataStream>
    #include <QLoggingCategory>
    #include <QDebug>
    //#include <QFile>
    #include <mmsystem.h>
    #include "qwindowsaudiodeviceinfo.h"
    #include "qwindowsaudioutils.h"

    #if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR)
    struct IBaseFilter; // Needed for strmif.h from stock MinGW.
    struct _DDPIXELFORMAT;
    typedef struct _DDPIXELFORMAT* LPDDPIXELFORMAT;
    #endif

    #include <strmif.h>
    #if !defined(Q_CC_MINGW) || defined(__MINGW64_VERSION_MAJOR)

    include <uuids.h>

    #else

    extern GUID CLSID_AudioInputDeviceCategory;
    extern GUID CLSID_AudioRendererCategory;
    extern GUID IID_ICreateDevEnum;
    extern GUID CLSID_SystemDeviceEnum;

    #ifndef ICreateDevEnum_INTERFACE_DEFINED
    #define ICreateDevEnum_INTERFACE_DEFINED

    DECLARE_INTERFACE_(ICreateDevEnum, IUnknown)
    {
    STDMETHOD(CreateClassEnumerator)(REFCLSID clsidDeviceClass,
    IEnumMoniker **ppEnumMoniker,
    DWORD dwFlags) PURE;
    };

    #endif // ICreateDevEnum_INTERFACE_DEFINED

    #ifndef IErrorLog_INTERFACE_DEFINED
    #define IErrorLog_INTERFACE_DEFINED

    DECLARE_INTERFACE_(IErrorLog, IUnknown)
    {
    STDMETHOD(AddError)(THIS_ LPCOLESTR, EXCEPINFO *) PURE;
    };

    #endif /* IErrorLog_INTERFACE_DEFINED */

    #ifndef IPropertyBag_INTERFACE_DEFINED
    #define IPropertyBag_INTERFACE_DEFINED

    const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};

    DECLARE_INTERFACE_(IPropertyBag, IUnknown)
    {
    STDMETHOD(Read)(THIS_ LPCOLESTR, VARIANT *, IErrorLog *) PURE;
    STDMETHOD(Write)(THIS_ LPCOLESTR, VARIANT *) PURE;
    };

    #endif /* IPropertyBag_INTERFACE_DEFINED */

    #endif // defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR)

    QT_BEGIN_NAMESPACE

    // For mingw toolchain mmsystem.h only defines half the defines, so add if needed.
    #ifndef WAVE_FORMAT_44M08
    #define WAVE_FORMAT_44M08 0x00000100
    #define WAVE_FORMAT_44S08 0x00000200
    #define WAVE_FORMAT_44M16 0x00000400
    #define WAVE_FORMAT_44S16 0x00000800
    #define WAVE_FORMAT_48M08 0x00001000
    #define WAVE_FORMAT_48S08 0x00002000
    #define WAVE_FORMAT_48M16 0x00004000
    #define WAVE_FORMAT_48S16 0x00008000
    #define WAVE_FORMAT_96M08 0x00010000
    #define WAVE_FORMAT_96S08 0x00020000
    #define WAVE_FORMAT_96M16 0x00040000
    #define WAVE_FORMAT_96S16 0x00080000
    #endif

    QWindowsAudioDeviceInfo::QWindowsAudioDeviceInfo(QByteArray dev, QAudio::Mode mode)
    {
    QDataStream ds(&dev, QIODevice::ReadOnly);
    ds >> devId >> device;
    this->mode = mode;

    updateLists();
    

    }

    QWindowsAudioDeviceInfo::~QWindowsAudioDeviceInfo()
    {
    close();
    }

    bool QWindowsAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const
    {
    return testSettings(format);
    }

    QAudioFormat QWindowsAudioDeviceInfo::preferredFormat() const
    {
    QAudioFormat nearest;
    if (mode == QAudio::AudioOutput) {
    nearest.setSampleRate(44100);
    nearest.setChannelCount(2);
    nearest.setByteOrder(QAudioFormat::LittleEndian);
    nearest.setSampleType(QAudioFormat::SignedInt);
    nearest.setSampleSize(16);
    nearest.setCodec(QLatin1String("audio/pcm"));
    } else {
    nearest.setSampleRate(11025);
    nearest.setChannelCount(1);
    nearest.setByteOrder(QAudioFormat::LittleEndian);
    nearest.setSampleType(QAudioFormat::SignedInt);
    nearest.setSampleSize(8);
    nearest.setCodec(QLatin1String("audio/pcm"));
    }
    return nearest;
    }

    QString QWindowsAudioDeviceInfo::deviceName() const
    {
    return device;
    }

    QStringList QWindowsAudioDeviceInfo::supportedCodecs()
    {
    return QStringList() << QStringLiteral("audio/pcm");
    }

    QList<int> QWindowsAudioDeviceInfo::supportedSampleRates()
    {
    updateLists();
    return sampleRatez;
    }

    QList<int> QWindowsAudioDeviceInfo::supportedChannelCounts()
    {
    updateLists();
    return channelz;
    }

    QList<int> QWindowsAudioDeviceInfo::supportedSampleSizes()
    {
    updateLists();
    return sizez;
    }

    QListQAudioFormat::Endian QWindowsAudioDeviceInfo::supportedByteOrders()
    {
    return QListQAudioFormat::Endian() << QAudioFormat::LittleEndian;
    }

    QListQAudioFormat::SampleType QWindowsAudioDeviceInfo::supportedSampleTypes()
    {
    updateLists();
    return typez;
    }

    bool QWindowsAudioDeviceInfo::open()
    {
    return true;
    }

    void QWindowsAudioDeviceInfo::close()
    {
    }

    bool QWindowsAudioDeviceInfo::testSettings(const QAudioFormat& format) const
    {
    WAVEFORMATEXTENSIBLE wfx;
    if (qt_convertFormat(format, &wfx)) {
    // query only, do not open device
    if (mode == QAudio::AudioOutput) {
    return (waveOutOpen(NULL, UINT_PTR(devId), &wfx.Format, 0, 0,
    WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
    } else { // AudioInput
    return (waveInOpen(NULL, UINT_PTR(devId), &wfx.Format, 0, 0,
    WAVE_FORMAT_QUERY) == MMSYSERR_NOERROR);
    }
    }

    return false;
    

    }

    void QWindowsAudioDeviceInfo::updateLists()
    {
    if (!sizez.isEmpty())
    return;

    bool hasCaps = false;
    DWORD fmt = 0;
    
    if(mode == QAudio::AudioOutput) {
        WAVEOUTCAPS woc;
        if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) {
            hasCaps = true;
            fmt = woc.dwFormats;
        }
    } else {
        WAVEINCAPS woc;
        if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) {
            hasCaps = true;
            fmt = woc.dwFormats;
        }
    }
    
    sizez.clear();
    sampleRatez.clear();
    channelz.clear();
    typez.clear();
    
    if (hasCaps) {
        // Check sample size
        if ((fmt & WAVE_FORMAT_1M08)
            || (fmt & WAVE_FORMAT_1S08)
            || (fmt & WAVE_FORMAT_2M08)
            || (fmt & WAVE_FORMAT_2S08)
            || (fmt & WAVE_FORMAT_4M08)
            || (fmt & WAVE_FORMAT_4S08)
            || (fmt & WAVE_FORMAT_48M08)
            || (fmt & WAVE_FORMAT_48S08)
            || (fmt & WAVE_FORMAT_96M08)
            || (fmt & WAVE_FORMAT_96S08)) {
            sizez.append(8);
        }
        if ((fmt & WAVE_FORMAT_1M16)
            || (fmt & WAVE_FORMAT_1S16)
            || (fmt & WAVE_FORMAT_2M16)
            || (fmt & WAVE_FORMAT_2S16)
            || (fmt & WAVE_FORMAT_4M16)
            || (fmt & WAVE_FORMAT_4S16)
            || (fmt & WAVE_FORMAT_48M16)
            || (fmt & WAVE_FORMAT_48S16)
            || (fmt & WAVE_FORMAT_96M16)
            || (fmt & WAVE_FORMAT_96S16)) {
            sizez.append(16);
        }
    
        // Check sample rate
        if ((fmt & WAVE_FORMAT_1M08)
           || (fmt & WAVE_FORMAT_1S08)
           || (fmt & WAVE_FORMAT_1M16)
           || (fmt & WAVE_FORMAT_1S16)) {
            sampleRatez.append(11025);
        }
        if ((fmt & WAVE_FORMAT_2M08)
           || (fmt & WAVE_FORMAT_2S08)
           || (fmt & WAVE_FORMAT_2M16)
           || (fmt & WAVE_FORMAT_2S16)) {
            sampleRatez.append(22050);
        }
        if ((fmt & WAVE_FORMAT_4M08)
           || (fmt & WAVE_FORMAT_4S08)
           || (fmt & WAVE_FORMAT_4M16)
           || (fmt & WAVE_FORMAT_4S16)) {
            sampleRatez.append(44100);
        }
        if ((fmt & WAVE_FORMAT_48M08)
            || (fmt & WAVE_FORMAT_48S08)
            || (fmt & WAVE_FORMAT_48M16)
            || (fmt & WAVE_FORMAT_48S16)) {
            sampleRatez.append(48000);
        }
        if ((fmt & WAVE_FORMAT_96M08)
           || (fmt & WAVE_FORMAT_96S08)
           || (fmt & WAVE_FORMAT_96M16)
           || (fmt & WAVE_FORMAT_96S16)) {
            sampleRatez.append(96000);
        }
    
        // Check channel count
        if (fmt & WAVE_FORMAT_1M08
                || fmt & WAVE_FORMAT_1M16
                || fmt & WAVE_FORMAT_2M08
                || fmt & WAVE_FORMAT_2M16
                || fmt & WAVE_FORMAT_4M08
                || fmt & WAVE_FORMAT_4M16
                || fmt & WAVE_FORMAT_48M08
                || fmt & WAVE_FORMAT_48M16
                || fmt & WAVE_FORMAT_96M08
                || fmt & WAVE_FORMAT_96M16) {
            channelz.append(1);
        }
        if (fmt & WAVE_FORMAT_1S08
                || fmt & WAVE_FORMAT_1S16
                || fmt & WAVE_FORMAT_2S08
                || fmt & WAVE_FORMAT_2S16
                || fmt & WAVE_FORMAT_4S08
                || fmt & WAVE_FORMAT_4S16
                || fmt & WAVE_FORMAT_48S08
                || fmt & WAVE_FORMAT_48S16
                || fmt & WAVE_FORMAT_96S08
                || fmt & WAVE_FORMAT_96S16) {
            channelz.append(2);
        }
    
        typez.append(QAudioFormat::SignedInt);
        typez.append(QAudioFormat::UnSignedInt);
    
        // WAVEOUTCAPS and WAVEINCAPS contains information only for the previously tested parameters.
        // WaveOut and WaveInt might actually support more formats, the only way to know is to try
        // opening the device with it.
        QAudioFormat testFormat;
        testFormat.setCodec(QStringLiteral("audio/pcm"));
        testFormat.setByteOrder(QAudioFormat::LittleEndian);
        testFormat.setSampleType(QAudioFormat::SignedInt);
        testFormat.setChannelCount(channelz.first());
        testFormat.setSampleRate(sampleRatez.at(sampleRatez.size() / 2));
        testFormat.setSampleSize(sizez.last());
        const QAudioFormat defaultTestFormat(testFormat);
    
        // Check if float samples are supported
        testFormat.setSampleType(QAudioFormat::Float);
        testFormat.setSampleSize(32);
        if (testSettings(testFormat))
            typez.append(QAudioFormat::Float);
    
        // Check channel counts > 2
        testFormat = defaultTestFormat;
        for (int i = 3; i < 19; ++i) { // <mmreg.h> defines 18 different channels
            testFormat.setChannelCount(i);
            if (testSettings(testFormat))
                channelz.append(i);
        }
    
        // Check more sample sizes
        testFormat = defaultTestFormat;
        QList<int> testSampleSizes = QList<int>() << 24 << 32 << 48 << 64;
        Q_FOREACH (int s, testSampleSizes) {
            testFormat.setSampleSize(s);
            if (testSettings(testFormat))
                sizez.append(s);
        }
    
        // Check more sample rates
        testFormat = defaultTestFormat;
        QList<int> testSampleRates = QList<int>() << 8000 << 16000 << 32000 << 88200 << 192000;
        Q_FOREACH (int r, testSampleRates) {
            testFormat.setSampleRate(r);
            if (testSettings(testFormat))
                sampleRatez.append(r);
        }
        std::sort(sampleRatez.begin(), sampleRatez.end());
    }
    

    }

    #define QT_MESSAGELOGCONTEXT
    #undef QT_NO_DEBUG_OUTPUT
    QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode)
    {
    Q_UNUSED(mode)

    QList<QByteArray> devices;
    QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
    //QLoggingCategory::setEnabled(QtDebugMsg, true);
    //QFile myfile("C:\temp\audio.debug");
    //myfile.open(QFile::WriteOnly|QFile::Text);
    //QTextStream myfileout(&myfile);
    //myfileout << "Testing debug";
    

    //#define qDebug QCDebug
    #ifndef Q_OS_WINCE
    //enumerate device fullnames through directshow api
    CoInitialize(NULL);
    ICreateDevEnum *pDevEnum = NULL;
    IEnumMoniker *pEnum = NULL;
    // Create the System device enumerator
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
    CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
    reinterpret_cast<void **>(&pDevEnum));

    unsigned long iNumDevs = mode == QAudio::AudioOutput ? waveOutGetNumDevs() : waveInGetNumDevs();
    qDebug() << "iNumDevs=" << iNumDevs;
    if (SUCCEEDED(hr)) {
        qDebug() << "SUCCEEDED(hr)#1";
        // Create the enumerator for the audio input/output category
        if (pDevEnum->CreateClassEnumerator(
             mode == QAudio::AudioOutput ? CLSID_AudioRendererCategory : CLSID_AudioInputDeviceCategory,
             &pEnum, 0) == S_OK) {
            qDebug() << "Enumerator OK";
            pEnum->Reset();
            // go through and find all audio devices
            IMoniker *pMoniker = NULL;
            while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
                qDebug() << "pEnum->Next";
                IPropertyBag *pPropBag;
                hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag,
                     reinterpret_cast<void **>(&pPropBag));
                if (FAILED(hr)) {
                    qDebug() << "FAILED(hr)";
                    pMoniker->Release();
                    continue; // skip this one
                }
                // Find if it is a wave device
                VARIANT var;
                VariantInit(&var);
                hr = pPropBag->Read(mode == QAudio::AudioOutput ? L"WaveOutID" : L"WaveInID", &var, 0);
                if (SUCCEEDED(hr)) {
                    qDebug() << "SUCCEEDED(hr)#2";
                    LONG waveID = var.lVal;
    	    qDebug() << "waveID=" << waveID << ", " << "iNumDevs=" << LONG(iNumDevs);
                    if (waveID >= 0 && waveID < LONG(iNumDevs)) {
                    qDebug() << "waveID OK";
                        VariantClear(&var);
                        // Find the description
                        hr = pPropBag->Read(L"FriendlyName", &var, 0);
                        qDebug() << "var=" << QString::fromWCharArray(var.bstrVal);
                        if (SUCCEEDED(hr)) {
                            qDebug() << "SUCCEEDED(hr)#3";
                            QByteArray  device;
                            QDataStream ds(&device, QIODevice::WriteOnly);
                            ds << quint32(waveID) << QString::fromWCharArray(var.bstrVal);
                            devices.append(device);
                        }
                    }
                }
    
                pPropBag->Release();
                pMoniker->Release();
            }
            pEnum->Release();
        }
        pDevEnum->Release();
    }
    CoUninitialize();
    

    #else // Q_OS_WINCE
    if (mode == QAudio::AudioOutput) {
    WAVEOUTCAPS woc;
    unsigned long iNumDevs,i;
    iNumDevs = waveOutGetNumDevs();
    for (i=0;i<iNumDevs;i++) {
    if (waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))
    == MMSYSERR_NOERROR) {
    QByteArray device;
    QDataStream ds(&device, QIODevice::WriteOnly);
    ds << quint32(i) << QString::fromWCharArray(woc.szPname);
    devices.append(device);
    }
    }
    } else {
    WAVEINCAPS woc;
    unsigned long iNumDevs,i;
    iNumDevs = waveInGetNumDevs();
    for (i=0;i<iNumDevs;i++) {
    if (waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS))
    == MMSYSERR_NOERROR) {
    QByteArray device;
    QDataStream ds(&device, QIODevice::WriteOnly);
    ds << quint32(i) << QString::fromWCharArray(woc.szPname);
    devices.append(device);
    }
    }
    }
    #endif // !Q_OS_WINCE

    return devices;
    

    }

    QByteArray QWindowsAudioDeviceInfo::defaultOutputDevice()
    {
    QByteArray defaultDevice;
    QDataStream ds(&defaultDevice, QIODevice::WriteOnly);
    ds << quint32(WAVE_MAPPER) // device ID for default device
    << QStringLiteral("Default Output Device");

    return defaultDevice;
    

    }

    QByteArray QWindowsAudioDeviceInfo::defaultInputDevice()
    {
    QByteArray defaultDevice;
    QDataStream ds(&defaultDevice, QIODevice::WriteOnly);
    ds << quint32(WAVE_MAPPER) // device ID for default device
    << QStringLiteral("Default Input Device");

    return defaultDevice;
    

    }

    QT_END_NAMESPACE



  • @Mike-Black HI Mike, you are wasting your time with your test program. The program in my OP has been used to verify that the issue is a Windows API issue, it uses no Qt code but does the same as that done by the Qt audio plugin on Windows Desktop.


Log in to reply