blob: 3b86c52b7eb5d4a7b02fc71c65146a68536a0252 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "QtCore/qdebug.h"
#include "mfaudioendpointcontrol.h"
#include <mmdeviceapi.h>
MFAudioEndpointControl::MFAudioEndpointControl(QObject *parent)
: QAudioOutputSelectorControl(parent)
, m_currentActivate(0)
{
}
MFAudioEndpointControl::~MFAudioEndpointControl()
{
clear();
}
void MFAudioEndpointControl::clear()
{
m_activeEndpoint.clear();
for (auto it = m_devices.cbegin(), end = m_devices.cend(); it != end; ++it)
CoTaskMemFree(it.value());
m_devices.clear();
if (m_currentActivate)
m_currentActivate->Release();
m_currentActivate = NULL;
}
QList<QString> MFAudioEndpointControl::availableOutputs() const
{
return m_devices.keys();
}
QString MFAudioEndpointControl::outputDescription(const QString &name) const
{
return name.section(QLatin1Char('\\'), -1);
}
QString MFAudioEndpointControl::defaultOutput() const
{
return m_defaultEndpoint;
}
QString MFAudioEndpointControl::activeOutput() const
{
return m_activeEndpoint;
}
void MFAudioEndpointControl::setActiveOutput(const QString &name)
{
if (m_activeEndpoint == name)
return;
QMap<QString, LPWSTR>::iterator it = m_devices.find(name);
if (it == m_devices.end())
return;
LPWSTR wstrID = *it;
IMFActivate *activate = NULL;
HRESULT hr = MFCreateAudioRendererActivate(&activate);
if (FAILED(hr)) {
qWarning() << "Failed to create audio renderer activate";
return;
}
if (wstrID) {
hr = activate->SetString(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ID, wstrID);
} else {
//This is the default one that has been inserted in updateEndpoints(),
//so give the activate a hint that we want to use the device for multimedia playback
//then the media foundation will choose an appropriate one.
//from MSDN:
//The ERole enumeration defines constants that indicate the role that the system has assigned to an audio endpoint device.
//eMultimedia: Music, movies, narration, and live music recording.
hr = activate->SetUINT32(MF_AUDIO_RENDERER_ATTRIBUTE_ENDPOINT_ROLE, eMultimedia);
}
if (FAILED(hr)) {
qWarning() << "Failed to set attribute for audio device" << name;
return;
}
if (m_currentActivate)
m_currentActivate->Release();
m_currentActivate = activate;
m_activeEndpoint = name;
}
IMFActivate* MFAudioEndpointControl::createActivate()
{
clear();
updateEndpoints();
// Check if an endpoint is available ("Default" is always inserted)
if (m_devices.count() <= 1)
return NULL;
setActiveOutput(m_defaultEndpoint);
return m_currentActivate;
}
void MFAudioEndpointControl::updateEndpoints()
{
m_defaultEndpoint = QString::fromLatin1("Default");
m_devices.insert(m_defaultEndpoint, NULL);
IMMDeviceEnumerator *pEnum = NULL;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnum);
if (SUCCEEDED(hr)) {
IMMDeviceCollection *pDevices = NULL;
hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
if (SUCCEEDED(hr)) {
UINT count;
hr = pDevices->GetCount(&count);
if (SUCCEEDED(hr)) {
for (UINT i = 0; i < count; ++i) {
IMMDevice *pDevice = NULL;
hr = pDevices->Item(i, &pDevice);
if (SUCCEEDED(hr)) {
LPWSTR wstrID = NULL;
hr = pDevice->GetId(&wstrID);
if (SUCCEEDED(hr)) {
QString deviceId = QString::fromWCharArray(wstrID);
m_devices.insert(deviceId, wstrID);
}
pDevice->Release();
}
}
}
pDevices->Release();
}
pEnum->Release();
}
}