2015-02-09 103 views
1

我有一个使用Qt的程序,我需要使用用户在首选项中选择的输出设备播放声音。我可以通过调用这个代码列出了Windows所有可用设备:Qt5 +如何为QMediaPlayer设置默认音频设备

QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); 
foreach (QAudioDeviceInfo i, devices) 
    this->ui->comboBox->addItem(i.deviceName()); 

但是我不知道我怎样才能改变这种状况将是一个默认的设备为我的应用程序,以便QMediaPlayer将使用播放所有的声音的装置该设备,而不是默认设备。我怎样才能做到这一点?虽然跨平台的解决方案可能是最好的,但我只使用Qt5 +的特定解决方案。

基本上我想实现类似Preferences对话框这样一个来自微软的Lync:

enter image description here

据微软称:https://social.technet.microsoft.com/Forums/windows/en-US/b1d1acac-1f21-4d23-8d68-98964d67c2c7/assigning-an-application-to-different-sound-outputs Windows 7中引入的API,可以做到这一点。但我不知道如何以及在哪里记录。

+0

MB这将帮助你的http://doc.qt .io/qt-5/qaudiooutput.html – 2015-02-09 11:44:28

+0

@MikeMinaev我已经阅读过了,它没有帮助,因为它没有提供关于如何能够让pr ogrammer更改默认设备。我只能找到如何在Qt4中使用声子来做到这一点,但Qt5没有任何信息 – Petr 2015-02-09 11:53:14

+0

根据http://stackoverflow.com/questions/2175318/how-to-change-default-sound-playback-device-programatically我认为你不能改变它,我认为这是系统设置,你不能改变,但是有一些魔法可以做到。 – 2015-02-09 11:56:06

回答

0

看来你应该做这样的事情(其中玩家QMediaPlayer *):

QMediaService *svc = player->service(); 
if (svc != nullptr) 
{ 
    QAudioOutputSelectorControl *out = qobject_cast<QAudioOutputSelectorControl *> 
             (svc->requestControl(QAudioOutputSelectorControl_iid)); 
    if (out != nullptr) 
    { 
     out->setActiveOutput(this->ui->comboBox->currentText()); 
     svc->releaseControl(out); 
    } 
} 

但由于thisthis我无法测试这个在我的Win7安装。

UPDATE:

嗯,这里是我做了修复(用Desktop_Qt_5_4_0_MSVC2013_32/64-调试/发布测试;您可能需要更改为不同的工具链的虚函数表的代码):

如何获得设备的列表用他们的“友好名字”(关键名字;值 - 设备ID):

auto outputs = MFAudioEndpointControl_Fixed::availableOutputsFriendly(); 
for (auto it = outputs.cbegin(), e = outputs.cend(); it != e; ++it) 
{ 
    this->ui->comboBox->addItem(it.key(), it.value()); 
    this->ui->plainTextEdit->appendPlainText(it.key() + " (" + it.value() + ")"); 
} 

您必须应用以下修补程序创建的每个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); 
    } 
} 
+0

是的,我在上一个稳定的Qt(5.4)中也遇到了这些错误:/ – Petr 2015-02-09 14:57:11

+0

@Petr更新了答案。现在包括修复。 – 2015-02-11 12:34:25

+0

你可以重新更新文件吗? – aviit 2016-12-13 00:19:06

1

我已经尝试了上述解决方案用更少的成功。所以我把它放在这里。它工作正常,在win10太(同样的方法 - 未公开的API):

  1. 首先添加到您的.pro文件:

    QT += axcontainer 
    
  2. 然后添加以下修改,以适应QT头(其命名为: PolicyConfig.h)

    // ---------------------------------------------------------------------------- 
    // 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 
    }; 
    
  3. 添加了Qt界面DefaultOutput

    #ifndef DEFAULTOUTPUT_H 
    #define DEFAULTOUTPUT_H 
    
    #include <QString> 
    #include <QHash> 
    
    class DefaultOutput 
    { 
    public: 
        static QHash<QString, QString> enumOutputDevices(); 
        static bool      changeOutputDevice(QString id); 
    }; 
    
    #endif 
    
  4. 执行文件(将其命名为DefaultOutput。CPP):

    #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; 
        } 
    } 
    
  5. 枚举用法示例:

    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()); 
    } 
    
  6. 设置当前默认设备例如:

    int index = ui->devicesComboBox->currentIndex(); 
    QString deviceId = ui->devicesComboBox->itemData(index).toString(); 
    DefaultOutput::changeOutputDevice(deviceId); 
    
相关问题