C++ Qt5+;如何为QMediaPlayer设置默认音频设备

C++ Qt5+;如何为QMediaPlayer设置默认音频设备,c++,qt,C++,Qt,我有一个使用Qt的程序,我需要让它使用用户在首选项中选择的输出设备播放声音。我可以通过调用以下代码列出windows中的所有可用设备: QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); foreach (QAudioDeviceInfo i, devices) this->ui->comboBox->addItem(i.devi

我有一个使用Qt的程序,我需要让它使用用户在首选项中选择的输出设备播放声音。我可以通过调用以下代码列出windows中的所有可用设备:

QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
foreach (QAudioDeviceInfo i, devices)
    this->ui->comboBox->addItem(i.deviceName());
QList devices=QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
foreach(QAudioDeviceInfo i,设备)
此->用户界面->组合框->添加项(i.deviceName());
但是,我不知道如何更改作为应用程序默认设备的设备,以便
QMediaPlayer
使用该设备播放所有声音,而不是默认设备。我该怎么做?我对仅限windows的Qt5+特定解决方案很满意,尽管跨平台解决方案可能是最好的

基本上,我希望实现类似的首选项对话框,如Microsoft Lync中的此对话框:


据微软称:Windows7引入了可以实现这一点的API。但是我不知道这是如何记录的,在哪里记录的。

看起来你应该这样做(玩家是QMediaPlayer*):

您必须为创建的每个QMediaPlayer应用以下修复程序:

QMediaPlayer *player = new QMediaPlayer(this);

QMediaService *svc = player->service();
if (svc != nullptr)
{
    QAudioOutputSelectorControl *out = reinterpret_cast<QAudioOutputSelectorControl*>
                                       (svc->requestControl(QAudioOutputSelectorControl_iid));
    if (out != nullptr)
    {
        new MFAudioEndpointControl_Fixed_Helper(out); // <- the fix; notice that it's a HELPER class

        out->setActiveOutput(this->ui->comboBox->itemData(this->ui->comboBox->currentIndex()).toString()); // we have to pass deviceID, not the name
        svc->releaseControl(out);
    }
}
QMediaPlayer*player=新的QMediaPlayer(此);
QMediaService*svc=player->service();
如果(svc!=nullptr)
{
QAudioOutputSelectorControl*out=重新解释
(svc->requestControl(QAudioOutputSelectorControl_iid));
if(out!=nullptr)
{

新的MFAudioEndpointControl_Fixed_Helper(out);//我尝试了上面的解决方案,但不太成功。因此我将我的解决方案放在这里。它在win10上也可以正常工作(相同的方法-未记录的API):

  • 首先添加到.pro文件:

    QT += axcontainer
    
  • 然后添加以下修改以适应QT头(名称:PolicyConfig.h)


  • mb这将帮助你@MikeMinaev我已经读过了,它没有帮助,因为它没有说明程序员如何更改默认设备的信息。我只能在Qt4中找到如何使用声子进行此操作,但QT5中没有信息根据我认为你不能更改它,我认为这是系统设置,你不能更改,但是t这是有魔力的。是的,我在上一个稳定的Qt(5.4)中也发现了这些bug://@Petr更新了答案。现在包括一个修复程序。你使用了哪种编译器?
    QMediaPlayer *player = new QMediaPlayer(this);
    
    QMediaService *svc = player->service();
    if (svc != nullptr)
    {
        QAudioOutputSelectorControl *out = reinterpret_cast<QAudioOutputSelectorControl*>
                                           (svc->requestControl(QAudioOutputSelectorControl_iid));
        if (out != nullptr)
        {
            new MFAudioEndpointControl_Fixed_Helper(out); // <- the fix; notice that it's a HELPER class
    
            out->setActiveOutput(this->ui->comboBox->itemData(this->ui->comboBox->currentIndex()).toString()); // we have to pass deviceID, not the name
            svc->releaseControl(out);
        }
    }
    
    QT += axcontainer
    
    // ----------------------------------------------------------------------------
    // PolicyConfig.h
    // Undocumented COM-interface IPolicyConfig.
    // Use for set default audio render endpoint
    // @author EreTIk
    // ----------------------------------------------------------------------------
    
    
    #pragma once
    
    #include "winnt.h"
    //#include <QAxAggregated>
    
    class DECLSPEC_UUID("f8679f50-850a-41cf-9c72-430f290290c8") IPolicyConfig;
    class DECLSPEC_UUID("870af99c-171d-4f9e-af0d-e63df40c2bc9") CPolicyConfigClient;
    // ----------------------------------------------------------------------------
    // class CPolicyConfigClient
    // {870af99c-171d-4f9e-af0d-e63df40c2bc9}
    //  
    // interface IPolicyConfig
    // {f8679f50-850a-41cf-9c72-430f290290c8}
    //
    // Query interface:
    // CComPtr<IPolicyConfig> PolicyConfig;
    // PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigClient));
    // 
    // @compatible: Windows 7 and Later
    // ----------------------------------------------------------------------------
    class IPolicyConfig : public IUnknown
    {
    public:
    
        virtual HRESULT GetMixFormat(
            PCWSTR,
            WAVEFORMATEX **
        );
    
        virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
            PCWSTR,
            INT,
            WAVEFORMATEX **
        );
    
        virtual HRESULT STDMETHODCALLTYPE ResetDeviceFormat(
            PCWSTR
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
            PCWSTR,
            WAVEFORMATEX *,
            WAVEFORMATEX *
        );
    
        virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
            PCWSTR,
            INT,
            PINT64,
            PINT64
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
            PCWSTR,
            PINT64
        );
    
        virtual HRESULT STDMETHODCALLTYPE GetShareMode(
            PCWSTR,
            struct DeviceShareMode *
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetShareMode(
            PCWSTR,
            struct DeviceShareMode *
        );
    
        virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
            PCWSTR,
            const PROPERTYKEY &,
            PROPVARIANT *
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
            PCWSTR,
            const PROPERTYKEY &,
            PROPVARIANT *
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
            __in PCWSTR wszDeviceId,
            __in ERole eRole 
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
            PCWSTR,
            INT
        );
    };
    
    class DECLSPEC_UUID("568b9108-44bf-40b4-9006-86afe5b5a620") IPolicyConfigVista;
    class DECLSPEC_UUID("294935CE-F637-4E7C-A41B-AB255460B862") CPolicyConfigVistaClient;
    // ----------------------------------------------------------------------------
    // class CPolicyConfigVistaClient
    // {294935CE-F637-4E7C-A41B-AB255460B862}
    //  
    // interface IPolicyConfigVista
    // {568b9108-44bf-40b4-9006-86afe5b5a620}
    //
    // Query interface:
    // CComPtr<IPolicyConfigVista> PolicyConfig;
    // PolicyConfig.CoCreateInstance(__uuidof(CPolicyConfigVistaClient));
    // 
    // @compatible: Windows Vista and Later
    // ----------------------------------------------------------------------------
    class IPolicyConfigVista : public IUnknown
    {
    public:
    
        virtual HRESULT GetMixFormat(
            PCWSTR,
            WAVEFORMATEX **
        );  // not available on Windows 7, use method from IPolicyConfig
    
        virtual HRESULT STDMETHODCALLTYPE GetDeviceFormat(
            PCWSTR,
            INT,
            WAVEFORMATEX **
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetDeviceFormat(
            PCWSTR,
            WAVEFORMATEX *,
            WAVEFORMATEX *
        );
    
        virtual HRESULT STDMETHODCALLTYPE GetProcessingPeriod(
            PCWSTR,
            INT,
            PINT64,
            PINT64
        );  // not available on Windows 7, use method from IPolicyConfig
    
        virtual HRESULT STDMETHODCALLTYPE SetProcessingPeriod(
            PCWSTR,
            PINT64
        );  // not available on Windows 7, use method from IPolicyConfig
    
        virtual HRESULT STDMETHODCALLTYPE GetShareMode(
            PCWSTR,
            struct DeviceShareMode *
        );  // not available on Windows 7, use method from IPolicyConfig
    
        virtual HRESULT STDMETHODCALLTYPE SetShareMode(
            PCWSTR,
            struct DeviceShareMode *
        );  // not available on Windows 7, use method from IPolicyConfig
    
        virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(
            PCWSTR,
            const PROPERTYKEY &,
            PROPVARIANT *
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetPropertyValue(
            PCWSTR,
            const PROPERTYKEY &,
            PROPVARIANT *
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(
            __in PCWSTR wszDeviceId,
            __in ERole eRole 
        );
    
        virtual HRESULT STDMETHODCALLTYPE SetEndpointVisibility(
            PCWSTR,
            INT
        );  // not available on Windows 7, use method from IPolicyConfig
    };
    
    #ifndef DEFAULTOUTPUT_H
    #define DEFAULTOUTPUT_H
    
    #include <QString>
    #include <QHash>
    
    class DefaultOutput
    {
    public:
        static QHash<QString, QString>  enumOutputDevices();
        static bool                     changeOutputDevice( QString id );
    };
    
    #endif
    
    #include <stdio.h>
    #include <wchar.h>
    #include <tchar.h>
    #include "windows.h"
    #include "Mmdeviceapi.h"
    #include "PolicyConfig.h"
    #include "Propidl.h"
    #include "Functiondiscoverykeys_devpkey.h"
    #include "defaultoutput.h"
    
    QHash<QString, QString> DefaultOutput::enumOutputDevices()
    {
        QHash<QString, QString> list;
    
        try
        {
            HRESULT hr = CoInitialize( NULL );
            if( FAILED( hr ) )
                return list;
            IMMDeviceEnumerator *pEnum = NULL;
            // Create a multimedia device enumerator.
            hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL, CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ), (void**)&pEnum );
            if( FAILED( hr ) )
                return list;
            IMMDeviceCollection *pDevices;
            // Enumerate the output devices.
            hr = pEnum->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &pDevices );
            if( FAILED( hr ) )
                return list;
            UINT count;
            pDevices->GetCount(&count);
            if( FAILED( hr ) )
                return list;
            for( UINT i = 0; i < count; i++ )
            {
                IMMDevice *pDevice;
                hr = pDevices->Item( i, &pDevice );
                if( SUCCEEDED( hr ) )
                {
                    LPWSTR wstrID = NULL;
                    hr = pDevice->GetId( &wstrID );
                    if( SUCCEEDED( hr ) )
                    {
                        IPropertyStore* pStore;
                        hr = pDevice->OpenPropertyStore( STGM_READ, &pStore );
                        if( SUCCEEDED( hr ) )
                        {
                            PROPVARIANT friendlyName;
                            PropVariantInit( &friendlyName );
                            hr = pStore->GetValue( PKEY_Device_FriendlyName, &friendlyName );
                            if( SUCCEEDED( hr ) )
                            {
                                QString qid = QString::fromStdU16String( (char16_t*)wstrID );
                                QString qname = QString::fromStdU16String( (char16_t*)friendlyName.pwszVal );
                                list[qid] = qname;
                                PropVariantClear( &friendlyName );
                            }
    
                            pStore->Release();
                        }
                    }
    
                    pDevice->Release();
                }
            }
    
            pDevices->Release();
            pEnum->Release();
            return list;
        }
        catch( ... )
        {
            return list;
        }
    }
    
    bool DefaultOutput::changeOutputDevice( QString id )
    {
        try
        {
            IPolicyConfigVista* pPolicyConfig;
            ERole reserved = eConsole;
            HRESULT hr = CoCreateInstance( __uuidof( CPolicyConfigVistaClient ), NULL, CLSCTX_ALL, __uuidof( IPolicyConfigVista ), (LPVOID*)&pPolicyConfig );
            if( SUCCEEDED( hr ) )
            {
                hr = pPolicyConfig->SetDefaultEndpoint( (PCWSTR)id.toStdU16String().data(), reserved );
                pPolicyConfig->Release();
                return SUCCEEDED( hr );
            }
            else
                return false;
        }
        catch( ... )
        {
            return false;
        }
    }
    
    QHash<QString, QString> devices = DefaultOutput::enumOutputDevices();
    for( QHash<QString, QString>::iterator iter = devices.begin(); iter != devices.end(); iter++ )
    {
        ui->devicesComboBox->addItem( iter.value(), iter.key() );
    }
    
    int index = ui->devicesComboBox->currentIndex();
    QString deviceId = ui->devicesComboBox->itemData( index ).toString();
    DefaultOutput::changeOutputDevice( deviceId );