Advertisement
Guest User

mfaudioendpointcontrol_fixed.cpp

a guest
Feb 11th, 2015
1,375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.77 KB | None | 0 0
  1. #include "mfaudioendpointcontrol_fixed.h"
  2.  
  3. #include <Functiondiscoverykeys_devpkey.h>
  4. #include <VersionHelpers.h>
  5. #include <cstdint>
  6.  
  7. #include <QDebug>
  8.  
  9. MFAudioEndpointControl_Fixed::MFAudioEndpointControl_Fixed(QObject *parent)
  10.     : QAudioOutputSelectorControl(parent)
  11.     , m_currentActivate(0)
  12. {
  13.     //
  14. }
  15.  
  16. MFAudioEndpointControl_Fixed::~MFAudioEndpointControl_Fixed()
  17. {
  18.     clear_endpoints();
  19.     clear_active();
  20. }
  21.  
  22. void MFAudioEndpointControl_Fixed::clear_active()
  23. {
  24.     if (m_currentActivate != nullptr)
  25.     {
  26.         m_currentActivate->Release();
  27.         m_currentActivate = nullptr;
  28.     }
  29.  
  30.     m_activeEndpoint.clear();
  31.  
  32.     auto hlp = this->findChild<MFAudioEndpointControl_Fixed_Helper *>("MFAECF_HLP", Qt::FindDirectChildrenOnly);
  33.     if (hlp != nullptr) {hlp->m_activeEndpoint.clear();} // Fix due to the way I get VTable address
  34. }
  35.  
  36. void MFAudioEndpointControl_Fixed::clear_endpoints()
  37. {
  38.     foreach (LPWSTR wstrID, m_devices)
  39.          CoTaskMemFree(wstrID);
  40.  
  41.     m_devices.clear();
  42. }
  43.  
  44. QList<QString> MFAudioEndpointControl_Fixed::availableOutputs() const
  45. {
  46.     return m_devices.keys();
  47. }
  48.  
  49. QString MFAudioEndpointControl_Fixed::outputDescription(const QString &name) const
  50. {
  51.     return name.section(QLatin1Char('\\'), -1);
  52. }
  53.  
  54. QString MFAudioEndpointControl_Fixed::defaultOutput() const
  55. {
  56.     return m_defaultEndpoint;
  57. }
  58.  
  59. QString MFAudioEndpointControl_Fixed::activeOutput() const
  60. {
  61.     return this->findChild<MFAudioEndpointControl_Fixed_Helper *>("MFAECF_HLP", Qt::FindDirectChildrenOnly)->m_activeEndpoint;
  62. }
  63.  
  64. void MFAudioEndpointControl_Fixed::setActiveOutput(const QString &name)
  65. {
  66.     auto qq = this->findChild<MFAudioEndpointControl_Fixed_Helper *>("MFAECF_HLP", Qt::FindDirectChildrenOnly);
  67.     QString &activeEndpointReal = qq->m_activeEndpoint;
  68.  
  69.     if (this->m_activeEndpoint == activeEndpointReal)
  70.     {
  71.         if (m_activeEndpoint == name)
  72.             return;
  73.  
  74.         updateEndpoints();
  75.  
  76.         QMap<QString, LPWSTR>::iterator it = m_devices.find(name);
  77.         if (it == m_devices.end())
  78.             return;
  79.  
  80.         clear_active();
  81.  
  82.         LPWSTR wstrID = *it;
  83.         IMFActivate *activate = NULL;
  84.         HRESULT hr = MFCreateAudioRendererActivate(&activate);
  85.         if (FAILED(hr)) {
  86.             qWarning() << "Failed to create audio renderer activate";
  87.             return;
  88.         }
  89.  
  90.         if (wstrID) {
  91.             hr = activate->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, wstrID);
  92.         } else {
  93.             //This is the default one that has been inserted in updateEndpoints(),
  94.             //so give the activate a hint that we want to use the device for multimedia playback
  95.             //then the media foundation will choose an appropriate one.
  96.  
  97.             //from MSDN:
  98.             //The ERole enumeration defines constants that indicate the role that the system has assigned to an audio endpoint device.
  99.             //eMultimedia: Music, movies, narration, and live music recording.
  100.             hr = activate->SetUINT32(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, eMultimedia);
  101.         }
  102.  
  103.         if (FAILED(hr)) {
  104.             qWarning() << "Failed to set attribute for audio device" << name;
  105.             activate->Release();
  106.             return;
  107.         }
  108.  
  109.         m_currentActivate = activate;
  110.         m_activeEndpoint = name;
  111.  
  112.         activeEndpointReal = name;
  113.     }
  114.     else
  115.     {
  116.         QString ae_tmp = activeEndpointReal;
  117.         activeEndpointReal = "";
  118.         this->setActiveOutput(ae_tmp);
  119.     }
  120. }
  121.  
  122. IMFActivate*  MFAudioEndpointControl_Fixed::createActivate()
  123. {
  124.     setActiveOutput(m_activeEndpoint);
  125.  
  126.     return m_currentActivate;
  127. }
  128.  
  129. QMap<QString, QString> MFAudioEndpointControl_Fixed::availableOutputsFriendly()
  130. {
  131.     QMap<QString, QString> names;
  132.     names.insert("Default", "Default");
  133.  
  134.     IMMDeviceEnumerator *pEnum = NULL;
  135.     HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
  136.                           NULL, CLSCTX_ALL,
  137.                           __uuidof(IMMDeviceEnumerator),
  138.                          (void**)&pEnum);
  139.     if (SUCCEEDED(hr)) {
  140.         IMMDeviceCollection *pDevices = NULL;
  141.         hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
  142.         if (SUCCEEDED(hr)) {
  143.             UINT count;
  144.             hr = pDevices->GetCount(&count);
  145.             if (SUCCEEDED(hr)) {
  146.                 for (UINT i = 0; i < count; ++i) {
  147.                     IMMDevice *pDevice = NULL;
  148.                     hr = pDevices->Item(i, &pDevice);
  149.                     if (SUCCEEDED(hr)) {
  150.                         LPWSTR wstrID = NULL;
  151.                         hr = pDevice->GetId(&wstrID);
  152.                         if (SUCCEEDED(hr)) {
  153.                             IPropertyStore *pPropStore = NULL;
  154.                             hr = pDevice->OpenPropertyStore(STGM_READ, &pPropStore);
  155.                             if (SUCCEEDED(hr)) { // I hate this bracket style >.<
  156.                                 PROPVARIANT varName;
  157.                                 PropVariantInit(&varName);
  158.                                 hr = pPropStore->GetValue(PKEY_Device_FriendlyName, &varName);
  159.                                 if (SUCCEEDED(hr)) {
  160.                                     names.insert(QString::fromWCharArray(varName.pwszVal),
  161.                                                  QString::fromWCharArray(wstrID));
  162.                                 }
  163.                                 PropVariantClear(&varName);
  164.                                 pPropStore->Release();
  165.                             }
  166.                             CoTaskMemFree(wstrID);
  167.                         }
  168.                         pDevice->Release();
  169.                     }
  170.                 }
  171.             }
  172.             pDevices->Release();
  173.         }
  174.         pEnum->Release();
  175.     }
  176.  
  177.     return names;
  178. }
  179.  
  180. void MFAudioEndpointControl_Fixed::updateEndpoints()
  181. {
  182.     clear_endpoints();
  183.  
  184.     m_defaultEndpoint = QString::fromLatin1("Default");
  185.     m_devices.insert(m_defaultEndpoint, NULL);
  186.  
  187.     IMMDeviceEnumerator *pEnum = NULL;
  188.     HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
  189.                           NULL, CLSCTX_ALL,
  190.                           __uuidof(IMMDeviceEnumerator),
  191.                          (void**)&pEnum);
  192.     if (SUCCEEDED(hr)) {
  193.         IMMDeviceCollection *pDevices = NULL;
  194.         hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
  195.         if (SUCCEEDED(hr)) {
  196.             UINT count;
  197.             hr = pDevices->GetCount(&count);
  198.             if (SUCCEEDED(hr)) {
  199.                 for (UINT i = 0; i < count; ++i) {
  200.                     IMMDevice *pDevice = NULL;
  201.                     hr = pDevices->Item(i, &pDevice);
  202.                     if (SUCCEEDED(hr)) {
  203.                         LPWSTR wstrID = NULL;
  204.                         hr = pDevice->GetId(&wstrID);
  205.                         if (SUCCEEDED(hr)) {
  206.                             QString deviceId = QString::fromWCharArray(wstrID);
  207.                             m_devices.insert(deviceId, wstrID);
  208.                         }
  209.                         pDevice->Release();
  210.                     }
  211.                 }
  212.             }
  213.             pDevices->Release();
  214.         }
  215.         pEnum->Release();
  216.     }
  217. }
  218.  
  219.  
  220.  
  221. MFAudioEndpointControl_Fixed_Helper::MFAudioEndpointControl_Fixed_Helper(QAudioOutputSelectorControl *parent)
  222. : QObject(parent)
  223. {
  224.     if (parent != nullptr)
  225.     {
  226.         if (IsWindowsVistaOrGreater()) // Vista introduced Media Foundation
  227.         {
  228.             std::size_t *vfptr_old = reinterpret_cast<std::size_t *>(parent);
  229.             *vfptr_old = *reinterpret_cast<std::size_t *>(&MFAudioEndpointControl_Fixed()); // Local VTable hooked
  230.  
  231.             this->setObjectName("MFAECF_HLP");
  232.         }
  233.     } else {throw std::exception("MFAudioEndpointControl_Fixed_Helper: No parent.");}
  234. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement