From e03b89d72e1fd16c099e12e5dfaaf9906a162ebc Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Wed, 24 Jun 2020 15:38:31 +0200 Subject: Remove wasapi plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Requires WinRT support Task-number: QTBUG-74423 Change-Id: Ice9788df3e503c4c111bc6524c509e93dbf407c5 Reviewed-by: Tor Arne Vestbø --- config.tests/wasapi/main.cpp | 54 --- config.tests/wasapi/wasapi.pro | 2 - src/multimedia/configure.json | 11 - src/plugins/plugins.pro | 4 - src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp | 167 -------- src/plugins/wasapi/qwasapiaudiodeviceinfo.h | 85 ---- src/plugins/wasapi/qwasapiaudioinput.cpp | 555 ------------------------- src/plugins/wasapi/qwasapiaudioinput.h | 121 ------ src/plugins/wasapi/qwasapiaudiooutput.cpp | 568 -------------------------- src/plugins/wasapi/qwasapiaudiooutput.h | 122 ------ src/plugins/wasapi/qwasapiplugin.cpp | 85 ---- src/plugins/wasapi/qwasapiplugin.h | 76 ---- src/plugins/wasapi/qwasapiutils.cpp | 344 ---------------- src/plugins/wasapi/qwasapiutils.h | 147 ------- src/plugins/wasapi/wasapi.json | 3 - src/plugins/wasapi/wasapi.pro | 30 -- 16 files changed, 2374 deletions(-) delete mode 100644 config.tests/wasapi/main.cpp delete mode 100644 config.tests/wasapi/wasapi.pro delete mode 100644 src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp delete mode 100644 src/plugins/wasapi/qwasapiaudiodeviceinfo.h delete mode 100644 src/plugins/wasapi/qwasapiaudioinput.cpp delete mode 100644 src/plugins/wasapi/qwasapiaudioinput.h delete mode 100644 src/plugins/wasapi/qwasapiaudiooutput.cpp delete mode 100644 src/plugins/wasapi/qwasapiaudiooutput.h delete mode 100644 src/plugins/wasapi/qwasapiplugin.cpp delete mode 100644 src/plugins/wasapi/qwasapiplugin.h delete mode 100644 src/plugins/wasapi/qwasapiutils.cpp delete mode 100644 src/plugins/wasapi/qwasapiutils.h delete mode 100644 src/plugins/wasapi/wasapi.json delete mode 100644 src/plugins/wasapi/wasapi.pro diff --git a/config.tests/wasapi/main.cpp b/config.tests/wasapi/main.cpp deleted file mode 100644 index e9d847a32..000000000 --- a/config.tests/wasapi/main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtMultimedia module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** 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 General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** 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-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include // clang-cl 6.0.0 chokes on this - -class AudioInterface : public Microsoft::WRL::RuntimeClass, Microsoft::WRL::FtmBase, IActivateAudioInterfaceCompletionHandler> -{ -public: - explicit AudioInterface() { } - ~AudioInterface() { } - - virtual HRESULT STDMETHODCALLTYPE ActivateCompleted(IActivateAudioInterfaceAsyncOperation *) { } -}; - -int main(int, char**) -{ - IUnknown *aInterface = nullptr; - IAudioClient* client; - aInterface->QueryInterface(IID_PPV_ARGS(&client)); - - WAVEFORMATEX *format; - client->GetMixFormat(&format); - - return 0; -} diff --git a/config.tests/wasapi/wasapi.pro b/config.tests/wasapi/wasapi.pro deleted file mode 100644 index 4294c4775..000000000 --- a/config.tests/wasapi/wasapi.pro +++ /dev/null @@ -1,2 +0,0 @@ -SOURCES += main.cpp -CONFIG += console diff --git a/src/multimedia/configure.json b/src/multimedia/configure.json index 7f9b5d064..20201f75f 100644 --- a/src/multimedia/configure.json +++ b/src/multimedia/configure.json @@ -171,11 +171,6 @@ "type": "compile", "test": "linux_v4l" }, - "wasapi": { - "label": "Windows Audio Services", - "type": "compile", - "test": "wasapi" - }, "wmsdk": { "label": "wmsdk.h", "type": "compile", @@ -280,11 +275,6 @@ "condition": "libs.pulseaudio", "output": [ "feature", "privateFeature" ] }, - "wasapi": { - "label": "Windows Audio Services", - "condition": "config.win32 && tests.wasapi", - "output": [ "privateFeature" ] - }, "wmsdk": { "label": "wmsdk.h", "condition": "config.win32 && tests.wmsdk", @@ -318,7 +308,6 @@ "resourcepolicy", "mmrenderer", "avfoundation", - "wasapi", "directshow", "wmf" ] diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 8e67cb599..8c173cbc4 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -26,10 +26,6 @@ qnx { SUBDIRS += qnx-audio } -win32 { - qtConfig(wasapi): SUBDIRS += wasapi -} - win32:!winrt { SUBDIRS += audiocapture \ windowsaudio diff --git a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp deleted file mode 100644 index 53345dec8..000000000 --- a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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 "qwasapiaudiodeviceinfo.h" -#include "qwasapiutils.h" - -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMmDeviceInfo, "qt.multimedia.deviceinfo") - -QWasapiAudioDeviceInfo::QWasapiAudioDeviceInfo(QByteArray dev, QAudio::Mode mode) - : m_deviceName(QString::fromLocal8Bit(dev)) -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__ << dev << mode; - m_interface = QWasapiUtils::createOrGetInterface(dev, mode); - - QAudioFormat referenceFormat = m_interface->m_mixFormat; - - const int rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000}; - for (int rate : rates) { - QAudioFormat f = referenceFormat; - f.setSampleRate(rate); - if (isFormatSupported(f)) - m_sampleRates.append(rate); - } - - for (int i = 1; i <= 18; ++i) { - QAudioFormat f = referenceFormat; - f.setChannelCount(i); - if (isFormatSupported(f)) - m_channelCounts.append(i); - } - - const int sizes[] = {8, 12, 16, 20, 24, 32, 64}; - for (int s : sizes) { - QAudioFormat f = referenceFormat; - f.setSampleSize(s); - if (isFormatSupported(f)) - m_sampleSizes.append(s); - } - - referenceFormat.setSampleType(QAudioFormat::SignedInt); - if (isFormatSupported(referenceFormat)) - m_sampleTypes.append(QAudioFormat::SignedInt); - - referenceFormat.setSampleType(QAudioFormat::Float); - if (isFormatSupported(referenceFormat)) - m_sampleTypes.append(QAudioFormat::Float); -} - -QWasapiAudioDeviceInfo::~QWasapiAudioDeviceInfo() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; -} - -bool QWasapiAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__ << format; - - WAVEFORMATEX nfmt; - if (!QWasapiUtils::convertToNativeFormat(format, &nfmt)) - return false; - - WAVEFORMATEX closest; - WAVEFORMATEX *pClosest = &closest; - HRESULT hr; - hr = m_interface->m_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &nfmt, &pClosest); - - if (hr == S_OK) // S_FALSE is inside SUCCEEDED() - return true; - - if (lcMmDeviceInfo().isDebugEnabled()) { - QAudioFormat f; - QWasapiUtils::convertFromNativeFormat(pClosest, &f); - qCDebug(lcMmDeviceInfo) << __FUNCTION__ << hr << "Closest match is:" << f; - } - - return false; -} - -QAudioFormat QWasapiAudioDeviceInfo::preferredFormat() const -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_interface->m_mixFormat; -} - -QString QWasapiAudioDeviceInfo::deviceName() const -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_deviceName; -} - -QStringList QWasapiAudioDeviceInfo::supportedCodecs() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return QStringList() << QStringLiteral("audio/pcm"); -} - -QList QWasapiAudioDeviceInfo::supportedSampleRates() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_sampleRates; -} - -QList QWasapiAudioDeviceInfo::supportedChannelCounts() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_channelCounts; -} - -QList QWasapiAudioDeviceInfo::supportedSampleSizes() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_sampleSizes; -} - -QList QWasapiAudioDeviceInfo::supportedByteOrders() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return QList() << m_interface->m_mixFormat.byteOrder(); -} - -QList QWasapiAudioDeviceInfo::supportedSampleTypes() -{ - qCDebug(lcMmDeviceInfo) << __FUNCTION__; - return m_sampleTypes; -} - -QT_END_NAMESPACE diff --git a/src/plugins/wasapi/qwasapiaudiodeviceinfo.h b/src/plugins/wasapi/qwasapiaudiodeviceinfo.h deleted file mode 100644 index 878d0273a..000000000 --- a/src/plugins/wasapi/qwasapiaudiodeviceinfo.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QWASAPIAUDIODEVICEINFO_H -#define QWASAPIAUDIODEVICEINFO_H - -#include -#include -#include -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcMmDeviceInfo) - -class AudioInterface; -class QWasapiAudioDeviceInfo : public QAbstractAudioDeviceInfo -{ - Q_OBJECT -public: - explicit QWasapiAudioDeviceInfo(QByteArray dev,QAudio::Mode mode); - ~QWasapiAudioDeviceInfo(); - - QAudioFormat preferredFormat() const override; - bool isFormatSupported(const QAudioFormat& format) const override; - QString deviceName() const override; - QStringList supportedCodecs() override; - QList supportedSampleRates() override; - QList supportedChannelCounts() override; - QList supportedSampleSizes() override; - QList supportedByteOrders() override; - QList supportedSampleTypes() override; - -private: - Microsoft::WRL::ComPtr m_interface; - QString m_deviceName; - QList m_sampleRates; - QList m_channelCounts; - QList m_sampleSizes; - QList m_sampleTypes; -}; - -QT_END_NAMESPACE - -#endif // QWASAPIAUDIODEVICEINFO_H diff --git a/src/plugins/wasapi/qwasapiaudioinput.cpp b/src/plugins/wasapi/qwasapiaudioinput.cpp deleted file mode 100644 index 561584e83..000000000 --- a/src/plugins/wasapi/qwasapiaudioinput.cpp +++ /dev/null @@ -1,555 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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 "qwasapiaudioinput.h" -#include "qwasapiutils.h" - -#include -#include -#include - -#include - -using namespace Microsoft::WRL; - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMmAudioInput, "qt.multimedia.audioinput") - -class WasapiInputDevicePrivate : public QIODevice -{ - Q_OBJECT -public: - WasapiInputDevicePrivate(QWasapiAudioInput* input); - ~WasapiInputDevicePrivate(); - - qint64 readData(char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - -private: - QWasapiAudioInput *m_input; -}; - -WasapiInputDevicePrivate::WasapiInputDevicePrivate(QWasapiAudioInput* input) - : m_input(input) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; -} - -WasapiInputDevicePrivate::~WasapiInputDevicePrivate() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; -} - -qint64 WasapiInputDevicePrivate::readData(char* data, qint64 len) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - - const quint32 channelCount = m_input->m_currentFormat.channelCount(); - const quint32 sampleBytes = m_input->m_currentFormat.sampleSize() / 8; - - const quint32 requestedFrames = len / channelCount / sampleBytes; - quint32 availableFrames = 0; - HRESULT hr = m_input->m_capture->GetNextPacketSize(&availableFrames); - - quint32 readFrames = qMin(requestedFrames, availableFrames); - const qint64 readBytes = readFrames * channelCount * sampleBytes; - - BYTE* buffer; - DWORD flags; - - QMutexLocker locker(&m_input->m_mutex); - - quint64 devicePosition; - hr = m_input->m_capture->GetBuffer(&buffer, &readFrames, &flags, &devicePosition, NULL); - if (hr != S_OK) { - m_input->m_currentError = QAudio::FatalError; - emit m_input->errorChanged(m_input->m_currentError); - hr = m_input->m_capture->ReleaseBuffer(readFrames); - qCDebug(lcMmAudioInput) << __FUNCTION__ << "Could not acquire input buffer."; - return 0; - } - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { - // In case this flag is set, user is supposed to ignore the content - // of the buffer and manually write silence - qCDebug(lcMmAudioInput) << __FUNCTION__ << "AUDCLNT_BUFFERFLAGS_SILENT: " - << "Ignoring buffer and writing silence."; - memset(data, 0, readBytes); - } else { - memcpy(data, buffer, readBytes); - } - - hr = m_input->m_capture->ReleaseBuffer(readFrames); - if (hr != S_OK) - qFatal("Could not release buffer"); - - if (m_input->m_interval && m_input->m_openTime.elapsed() - m_input->m_openTimeOffset > m_input->m_interval) { - emit m_input->notify(); - m_input->m_openTimeOffset = m_input->m_openTime.elapsed(); - } - - m_input->m_bytesProcessed += readBytes; - - if (m_input->m_currentState != QAudio::ActiveState) { - m_input->m_currentState = QAudio::ActiveState; - emit m_input->stateChanged(m_input->m_currentState); - } - return readBytes; -} - -qint64 WasapiInputDevicePrivate::writeData(const char* data, qint64 len) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - Q_UNUSED(data) - Q_UNUSED(len) - return 0; -} - -QWasapiAudioInput::QWasapiAudioInput(const QByteArray &device) - : m_deviceName(device) - , m_volumeCache(qreal(1.)) - , m_currentState(QAudio::StoppedState) - , m_currentError(QAudio::NoError) - , m_bufferFrames(0) - , m_bufferBytes(4096) - , m_eventThread(0) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << device; - Q_UNUSED(device) -} - -QWasapiAudioInput::~QWasapiAudioInput() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - stop(); -} - -void QWasapiAudioInput::setVolume(qreal vol) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << vol; - m_volumeCache = vol; - if (m_volumeControl) { - quint32 channelCount; - HRESULT hr = m_volumeControl->GetChannelCount(&channelCount); - for (quint32 i = 0; i < channelCount; ++i) { - hr = m_volumeControl->SetChannelVolume(i, vol); - RETURN_VOID_IF_FAILED("Could not set audio volume."); - } - } -} - -qreal QWasapiAudioInput::volume() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - return m_volumeCache; -} - -void QWasapiAudioInput::process() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - DWORD waitRet; - - m_processing = true; - do { - waitRet = WaitForSingleObjectEx(m_event, 2000, FALSE); - if (waitRet != WAIT_OBJECT_0) { - qFatal("Returned while waiting for event."); - return; - } - - QMutexLocker locker(&m_mutex); - - if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) - break; - QMetaObject::invokeMethod(this, "processBuffer", Qt::QueuedConnection); - } while (m_processing); -} - -void QWasapiAudioInput::processBuffer() -{ - if (!m_pullMode) { - emit m_eventDevice->readyRead(); - ResetEvent(m_event); - return; - } - - QMutexLocker locker(&m_mutex); - const quint32 channelCount = m_currentFormat.channelCount(); - const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; - BYTE* buffer; - HRESULT hr; - - quint32 packetFrames; - hr = m_capture->GetNextPacketSize(&packetFrames); - - while (packetFrames != 0 && m_currentState == QAudio::ActiveState) { - DWORD flags; - quint64 devicePosition; - hr = m_capture->GetBuffer(&buffer, &packetFrames, &flags, &devicePosition, NULL); - if (hr != S_OK) { - m_currentError = QAudio::FatalError; - emit errorChanged(m_currentError); - // Also Error Buffers need to be released - hr = m_capture->ReleaseBuffer(packetFrames); - qCDebug(lcMmAudioInput) << __FUNCTION__ << "Could not acquire input buffer."; - return; - } - const quint32 writeBytes = packetFrames * channelCount * sampleBytes; - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) { - // In case this flag is set, user is supposed to ignore the content - // of the buffer and manually write silence - qCDebug(lcMmAudioInput) << __FUNCTION__ << "AUDCLNT_BUFFERFLAGS_SILENT: " - << "Ignoring buffer and writing silence."; - buffer = new BYTE[writeBytes]; - memset(buffer, 0, writeBytes); - } - - const qint64 written = m_eventDevice->write(reinterpret_cast(buffer), writeBytes); - - if (Q_UNLIKELY(flags & AUDCLNT_BUFFERFLAGS_SILENT)) - delete [] buffer; - - if (written < static_cast(writeBytes)) { - if (m_currentError != QAudio::UnderrunError) { - m_currentError = QAudio::UnderrunError; - emit errorChanged(m_currentError); - } - } - hr = m_capture->ReleaseBuffer(packetFrames); - if (hr != S_OK) - qFatal("Could not release buffer"); - - m_bytesProcessed += writeBytes; - - hr = m_capture->GetNextPacketSize(&packetFrames); - } - ResetEvent(m_event); - - if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { - emit notify(); - m_openTimeOffset = m_openTime.elapsed(); - } - m_processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; -} - -bool QWasapiAudioInput::initStart(bool pull) -{ - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - stop(); - - QMutexLocker locker(&m_mutex); - - m_interface = QWasapiUtils::createOrGetInterface(m_deviceName, QAudio::AudioInput); - Q_ASSERT(m_interface); - - m_pullMode = pull; - WAVEFORMATEX nFmt; - WAVEFORMATEX closest; - WAVEFORMATEX *pClose = &closest; - - if (!m_currentFormat.isValid() || !QWasapiUtils::convertToNativeFormat(m_currentFormat, &nFmt)) { - m_currentError = QAudio::OpenError; - emit errorChanged(m_currentError); - return false; - } - - HRESULT hr; - - hr = m_interface->m_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &nFmt, &pClose); - if (hr != S_OK) { - m_currentError = QAudio::OpenError; - emit errorChanged(m_currentError); - return false; - } - - REFERENCE_TIME t = ((10000.0 * 10000 / nFmt.nSamplesPerSec * 1024) + 0.5); - if (m_bufferBytes) - t = m_currentFormat.durationForBytes(m_bufferBytes) * 10; - - const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; - hr = m_interface->m_client->Initialize(AUDCLNT_SHAREMODE_SHARED, flags, t, 0, &nFmt, NULL); - EMIT_RETURN_FALSE_IF_FAILED("Could not initialize audio client.", QAudio::OpenError) - - hr = m_interface->m_client->GetService(IID_PPV_ARGS(&m_capture)); - EMIT_RETURN_FALSE_IF_FAILED("Could not acquire render service.", QAudio::OpenError) - - hr = m_interface->m_client->GetService(IID_PPV_ARGS(&m_volumeControl)); - if (FAILED(hr)) - qCDebug(lcMmAudioInput) << "Could not acquire volume control."; - - hr = m_interface->m_client->GetBufferSize(&m_bufferFrames); - EMIT_RETURN_FALSE_IF_FAILED("Could not access buffer size.", QAudio::OpenError) - - m_event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS); - m_eventThread = new QWasapiProcessThread(this, false); - m_eventThread->m_event = m_event; - hr = m_interface->m_client->SetEventHandle(m_event); - EMIT_RETURN_FALSE_IF_FAILED("Could not set event handle.", QAudio::OpenError) - - if (!m_pullMode) { - m_eventDevice = new WasapiInputDevicePrivate(this); - m_eventDevice->open(QIODevice::ReadOnly|QIODevice::Unbuffered); - } - - hr = m_interface->m_client->Start(); - EMIT_RETURN_FALSE_IF_FAILED("Could not start audio render client.", QAudio::OpenError) - - m_openTime.restart(); - m_openTimeOffset = 0; - m_bytesProcessed = 0; - - return true; -} - -QAudio::Error QWasapiAudioInput::error() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << m_currentError; - return m_currentError; -} - -QAudio::State QWasapiAudioInput::state() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - return m_currentState; -} - -void QWasapiAudioInput::start(QIODevice* device) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << device; - if (!initStart(true)) { - qCDebug(lcMmAudioInput) << __FUNCTION__ << "failed"; - return; - } - m_eventDevice = device; - - m_mutex.lock(); - m_currentState = QAudio::ActiveState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - m_eventThread->start(); -} - -QIODevice *QWasapiAudioInput::start() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (!initStart(false)) { - qCDebug(lcMmAudioInput) << __FUNCTION__ << "failed"; - return nullptr; - } - - m_mutex.lock(); - m_currentState = QAudio::IdleState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - m_eventThread->start(); - return m_eventDevice; -} - -void QWasapiAudioInput::stop() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return; - - m_mutex.lock(); - m_currentState = QAudio::StoppedState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - - if (m_currentError != QAudio::NoError) { - m_mutex.lock(); - m_currentError = QAudio::NoError; - m_mutex.unlock(); - emit errorChanged(m_currentError); - } - - HRESULT hr = m_interface->m_client->Stop(); - hr = m_interface->m_client->Reset(); - - if (m_eventThread) { - SetEvent(m_eventThread->m_event); - while (m_eventThread->isRunning()) - QThread::yieldCurrentThread(); - m_eventThread->deleteLater(); - m_eventThread = 0; - } -} - -void QWasapiAudioInput::setFormat(const QAudioFormat& fmt) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << fmt; - if (m_currentState != QAudio::StoppedState) - return; - m_currentFormat = fmt; -} - -QAudioFormat QWasapiAudioInput::format() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - return m_currentFormat; -} - -int QWasapiAudioInput::bytesReady() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState != QAudio::IdleState && m_currentState != QAudio::ActiveState) - return 0; - - const quint32 channelCount = m_currentFormat.channelCount(); - const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; - - quint32 packetFrames; - HRESULT hr = m_capture->GetNextPacketSize(&packetFrames); - - if (FAILED(hr)) - return 0; - const quint32 writeBytes = packetFrames * channelCount * sampleBytes; - - return writeBytes; -} - -void QWasapiAudioInput::resume() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState != QAudio::SuspendedState) - return; - - HRESULT hr = m_interface->m_client->Start(); - EMIT_RETURN_VOID_IF_FAILED("Could not start audio render client.", QAudio::FatalError) - - m_mutex.lock(); - m_currentError = QAudio::NoError; - m_currentState = QAudio::ActiveState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - m_eventThread->start(); -} - -void QWasapiAudioInput::setBufferSize(int value) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << value; - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - return; - m_bufferBytes = value; -} - -int QWasapiAudioInput::bufferSize() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - return m_bufferFrames * m_currentFormat.channelCount()* m_currentFormat.sampleSize() / 8; - - return m_bufferBytes; -} - -int QWasapiAudioInput::periodSize() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - REFERENCE_TIME defaultDevicePeriod; - REFERENCE_TIME minimumPeriod; - HRESULT hr = m_interface->m_client->GetDevicePeriod(&defaultDevicePeriod, &minimumPeriod); - if (FAILED(hr)) - return 0; - const int res = m_currentFormat.bytesForDuration(minimumPeriod / 10); - return res; -} - -void QWasapiAudioInput::setNotifyInterval(int ms) -{ - qCDebug(lcMmAudioInput) << __FUNCTION__ << ms; - m_interval = qMax(0, ms); -} - -int QWasapiAudioInput::notifyInterval() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - return m_interval; -} - -qint64 QWasapiAudioInput::processedUSecs() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return 0; - qint64 res = qint64(1000000) * m_bytesProcessed / - (m_currentFormat.channelCount() * (m_currentFormat.sampleSize() / 8)) / - m_currentFormat.sampleRate(); - - return res; -} - -void QWasapiAudioInput::suspend() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState != QAudio::ActiveState) - return; - - m_mutex.lock(); - m_currentState = QAudio::SuspendedState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - - HRESULT hr = m_interface->m_client->Stop(); - EMIT_RETURN_VOID_IF_FAILED("Could not suspend audio render client.", QAudio::FatalError); - - if (m_eventThread) { - SetEvent(m_eventThread->m_event); - while (m_eventThread->isRunning()) - QThread::yieldCurrentThread(); - } - qCDebug(lcMmAudioInput) << __FUNCTION__ << "Thread has stopped"; -} - -qint64 QWasapiAudioInput::elapsedUSecs() const -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return 0; - return m_openTime.elapsed() * qint64(1000); -} - -void QWasapiAudioInput::reset() -{ - qCDebug(lcMmAudioInput) << __FUNCTION__; - stop(); -} - -QT_END_NAMESPACE - -#include "qwasapiaudioinput.moc" diff --git a/src/plugins/wasapi/qwasapiaudioinput.h b/src/plugins/wasapi/qwasapiaudioinput.h deleted file mode 100644 index 6e9775490..000000000 --- a/src/plugins/wasapi/qwasapiaudioinput.h +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QAUDIOINPUTWASAPI_H -#define QAUDIOINPUTWASAPI_H - -#include -#include -#include -#include -#include - -#include - -struct IAudioCaptureClient; -struct IAudioStreamVolume; - -QT_BEGIN_NAMESPACE - -class AudioInterface; -class WasapiInputDevicePrivate; -class QWasapiProcessThread; - -Q_DECLARE_LOGGING_CATEGORY(lcMmAudioInput) - -class QWasapiAudioInput : public QAbstractAudioInput -{ - Q_OBJECT -public: - explicit QWasapiAudioInput(const QByteArray &device); - ~QWasapiAudioInput(); - - void start(QIODevice* device) override; - QIODevice* start() override; - void stop() override; - void reset() override; - void suspend() override; - void resume() override; - int bytesReady() const override; - int periodSize() const override; - void setBufferSize(int value) override; - int bufferSize() const override; - void setNotifyInterval(int milliSeconds) override; - int notifyInterval() const override; - qint64 processedUSecs() const override; - qint64 elapsedUSecs() const override; - QAudio::Error error() const override; - QAudio::State state() const override; - void setFormat(const QAudioFormat& fmt) override; - QAudioFormat format() const override; - void setVolume(qreal) override; - qreal volume() const override; - - void process(); -public slots: - void processBuffer(); -private: - bool initStart(bool pull); - friend class WasapiInputDevicePrivate; - friend class WasapiInputPrivate; - QByteArray m_deviceName; - Microsoft::WRL::ComPtr m_interface; - Microsoft::WRL::ComPtr m_capture; - Microsoft::WRL::ComPtr m_volumeControl; - qreal m_volumeCache; - QMutex m_mutex; - QAudio::State m_currentState; - QAudio::Error m_currentError; - QAudioFormat m_currentFormat; - qint64 m_bytesProcessed; - QElapsedTimer m_openTime; - int m_openTimeOffset; - int m_interval; - bool m_pullMode; - quint32 m_bufferFrames; - quint32 m_bufferBytes; - HANDLE m_event; - QWasapiProcessThread *m_eventThread; - QAtomicInt m_processing; - QIODevice *m_eventDevice; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/wasapi/qwasapiaudiooutput.cpp b/src/plugins/wasapi/qwasapiaudiooutput.cpp deleted file mode 100644 index 79548011c..000000000 --- a/src/plugins/wasapi/qwasapiaudiooutput.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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 "qwasapiaudiooutput.h" -#include "qwasapiutils.h" -#include -#include -#include -#include - -#include -#include - -using namespace Microsoft::WRL; - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMmAudioOutput, "qt.multimedia.audiooutput") - -class WasapiOutputDevicePrivate : public QIODevice -{ - Q_OBJECT -public: - WasapiOutputDevicePrivate(QWasapiAudioOutput* output); - ~WasapiOutputDevicePrivate(); - - qint64 readData(char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - -private: - QWasapiAudioOutput *m_output; - QTimer m_timer; -}; - -WasapiOutputDevicePrivate::WasapiOutputDevicePrivate(QWasapiAudioOutput* output) - : m_output(output) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - - m_timer.setSingleShot(true); - connect(&m_timer, &QTimer::timeout, [=](){ - if (m_output->m_currentState == QAudio::ActiveState) { - m_output->m_currentState = QAudio::IdleState; - emit m_output->stateChanged(m_output->m_currentState); - m_output->m_currentError = QAudio::UnderrunError; - emit m_output->errorChanged(m_output->m_currentError); - } - }); -} - -WasapiOutputDevicePrivate::~WasapiOutputDevicePrivate() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; -} - -qint64 WasapiOutputDevicePrivate::readData(char* data, qint64 len) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - Q_UNUSED(data) - Q_UNUSED(len) - - return 0; -} - -qint64 WasapiOutputDevicePrivate::writeData(const char* data, qint64 len) -{ - if (m_output->state() != QAudio::ActiveState && m_output->state() != QAudio::IdleState) - return 0; - - QMutexLocker locker(&m_output->m_mutex); - m_timer.stop(); - - const quint32 channelCount = m_output->m_currentFormat.channelCount(); - const quint32 sampleBytes = m_output->m_currentFormat.sampleSize() / 8; - const quint32 freeBytes = static_cast(m_output->bytesFree()); - const quint32 bytesToWrite = qMin(freeBytes, static_cast(len)); - const quint32 framesToWrite = bytesToWrite / (channelCount * sampleBytes); - - BYTE *buffer; - HRESULT hr; - hr = m_output->m_renderer->GetBuffer(framesToWrite, &buffer); - if (hr != S_OK) { - m_output->m_currentError = QAudio::UnderrunError; - QMetaObject::invokeMethod(m_output, "errorChanged", Qt::QueuedConnection, - Q_ARG(QAudio::Error, QAudio::UnderrunError)); - // Also Error Buffers need to be released - hr = m_output->m_renderer->ReleaseBuffer(framesToWrite, 0); - return 0; - } - - memcpy_s(buffer, bytesToWrite, data, bytesToWrite); - - hr = m_output->m_renderer->ReleaseBuffer(framesToWrite, 0); - if (hr != S_OK) - qFatal("Could not release buffer"); - - if (m_output->m_interval && m_output->m_openTime.elapsed() - m_output->m_openTimeOffset > m_output->m_interval) { - QMetaObject::invokeMethod(m_output, "notify", Qt::QueuedConnection); - m_output->m_openTimeOffset = m_output->m_openTime.elapsed(); - } - - m_output->m_bytesProcessed += bytesToWrite; - - if (m_output->m_currentState != QAudio::ActiveState) { - m_output->m_currentState = QAudio::ActiveState; - emit m_output->stateChanged(m_output->m_currentState); - } - if (m_output->m_currentError != QAudio::NoError) { - m_output->m_currentError = QAudio::NoError; - emit m_output->errorChanged(m_output->m_currentError); - } - - quint32 paddingFrames; - hr = m_output->m_interface->m_client->GetCurrentPadding(&paddingFrames); - const quint32 paddingBytes = paddingFrames * m_output->m_currentFormat.channelCount() * m_output->m_currentFormat.sampleSize() / 8; - - m_timer.setInterval(m_output->m_currentFormat.durationForBytes(paddingBytes) / 1000); - m_timer.start(); - return bytesToWrite; -} - -QWasapiAudioOutput::QWasapiAudioOutput(const QByteArray &device) - : m_deviceName(device) - , m_volumeCache(qreal(1.)) - , m_currentState(QAudio::StoppedState) - , m_currentError(QAudio::NoError) - , m_interval(1000) - , m_pullMode(true) - , m_bufferFrames(0) - , m_bufferBytes(4096) - , m_eventThread(0) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << device; -} - -QWasapiAudioOutput::~QWasapiAudioOutput() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - stop(); -} - -void QWasapiAudioOutput::setVolume(qreal vol) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << vol; - m_volumeCache = vol; - if (m_volumeControl) { - quint32 channelCount; - HRESULT hr = m_volumeControl->GetChannelCount(&channelCount); - for (quint32 i = 0; i < channelCount; ++i) { - hr = m_volumeControl->SetChannelVolume(i, vol); - RETURN_VOID_IF_FAILED("Could not set audio volume."); - } - } -} - -qreal QWasapiAudioOutput::volume() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - return m_volumeCache; -} - -void QWasapiAudioOutput::process() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - DWORD waitRet; - - m_processing = true; - do { - waitRet = WaitForSingleObjectEx(m_event, 2000, FALSE); - if (waitRet != WAIT_OBJECT_0) { - qFatal("Returned while waiting for event."); - return; - } - - QMutexLocker locker(&m_mutex); - - if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) - break; - QMetaObject::invokeMethod(this, "processBuffer", Qt::QueuedConnection); - } while (m_processing); -} - -void QWasapiAudioOutput::processBuffer() -{ - QMutexLocker locker(&m_mutex); - - const quint32 channelCount = m_currentFormat.channelCount(); - const quint32 sampleBytes = m_currentFormat.sampleSize() / 8; - BYTE* buffer; - HRESULT hr; - - quint32 paddingFrames; - hr = m_interface->m_client->GetCurrentPadding(&paddingFrames); - - const quint32 availableFrames = m_bufferFrames - paddingFrames; - hr = m_renderer->GetBuffer(availableFrames, &buffer); - if (hr != S_OK) { - m_currentError = QAudio::UnderrunError; - emit errorChanged(m_currentError); - // Also Error Buffers need to be released - hr = m_renderer->ReleaseBuffer(availableFrames, 0); - ResetEvent(m_event); - return; - } - - const quint32 readBytes = availableFrames * channelCount * sampleBytes; - const qint64 read = m_eventDevice->read((char*)buffer, readBytes); - if (read < static_cast(readBytes)) { - // Fill the rest of the buffer with zero to avoid audio glitches - if (m_currentError != QAudio::UnderrunError) { - m_currentError = QAudio::UnderrunError; - emit errorChanged(m_currentError); - } - if (m_currentState != QAudio::IdleState) { - m_currentState = QAudio::IdleState; - emit stateChanged(m_currentState); - } - } - - hr = m_renderer->ReleaseBuffer(availableFrames, 0); - if (hr != S_OK) - qFatal("Could not release buffer"); - ResetEvent(m_event); - - if (m_interval && m_openTime.elapsed() - m_openTimeOffset > m_interval) { - emit notify(); - m_openTimeOffset = m_openTime.elapsed(); - } - - m_bytesProcessed += read; - m_processing = m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState; -} - -bool QWasapiAudioOutput::initStart(bool pull) -{ - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - stop(); - - QMutexLocker locker(&m_mutex); - - m_interface = QWasapiUtils::createOrGetInterface(m_deviceName, QAudio::AudioOutput); - Q_ASSERT(m_interface); - - m_pullMode = pull; - WAVEFORMATEX nFmt; - WAVEFORMATEX closest; - WAVEFORMATEX *pClose = &closest; - - if (!m_currentFormat.isValid() || !QWasapiUtils::convertToNativeFormat(m_currentFormat, &nFmt)) { - m_currentError = QAudio::OpenError; - emit errorChanged(m_currentError); - return false; - } - - HRESULT hr; - - hr = m_interface->m_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, &nFmt, &pClose); - if (hr != S_OK) { - m_currentError = QAudio::OpenError; - emit errorChanged(m_currentError); - return false; - } - - REFERENCE_TIME t = ((10000.0 * 10000 / nFmt.nSamplesPerSec * 1024) + 0.5); - if (m_bufferBytes) - t = m_currentFormat.durationForBytes(m_bufferBytes) * 100; - - DWORD flags = pull ? AUDCLNT_STREAMFLAGS_EVENTCALLBACK : 0; - hr = m_interface->m_client->Initialize(AUDCLNT_SHAREMODE_SHARED, flags, t, 0, &nFmt, NULL); - EMIT_RETURN_FALSE_IF_FAILED("Could not initialize audio client.", QAudio::OpenError) - - hr = m_interface->m_client->GetService(IID_PPV_ARGS(&m_renderer)); - EMIT_RETURN_FALSE_IF_FAILED("Could not acquire render service.", QAudio::OpenError) - - hr = m_interface->m_client->GetService(IID_PPV_ARGS(&m_volumeControl)); - if (FAILED(hr)) - qCDebug(lcMmAudioOutput) << "Could not acquire volume control."; - - hr = m_interface->m_client->GetBufferSize(&m_bufferFrames); - EMIT_RETURN_FALSE_IF_FAILED("Could not access buffer size.", QAudio::OpenError) - - if (m_pullMode) { - m_eventThread = new QWasapiProcessThread(this); - m_event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS); - m_eventThread->m_event = m_event; - - hr = m_interface->m_client->SetEventHandle(m_event); - EMIT_RETURN_FALSE_IF_FAILED("Could not set event handle.", QAudio::OpenError) - } else { - m_eventDevice = new WasapiOutputDevicePrivate(this); - m_eventDevice->open(QIODevice::WriteOnly|QIODevice::Unbuffered); - } - // Send some initial data, do not exit on failure, latest in process - // those an error will be caught - BYTE *pdata = nullptr; - hr = m_renderer->GetBuffer(m_bufferFrames, &pdata); - hr = m_renderer->ReleaseBuffer(m_bufferFrames, AUDCLNT_BUFFERFLAGS_SILENT); - - hr = m_interface->m_client->Start(); - EMIT_RETURN_FALSE_IF_FAILED("Could not start audio render client.", QAudio::OpenError) - - m_openTime.restart(); - m_openTimeOffset = 0; - m_bytesProcessed = 0; - return true; -} - -QAudio::Error QWasapiAudioOutput::error() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << m_currentError; - return m_currentError; -} - -QAudio::State QWasapiAudioOutput::state() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - return m_currentState; -} - -void QWasapiAudioOutput::start(QIODevice *device) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << device; - if (!initStart(true)) { - qCDebug(lcMmAudioOutput) << __FUNCTION__ << "failed"; - return; - } - m_eventDevice = device; - - m_mutex.lock(); - m_currentState = QAudio::ActiveState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - m_eventThread->start(); -} - -QIODevice *QWasapiAudioOutput::start() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - - if (!initStart(false)) { - qCDebug(lcMmAudioOutput) << __FUNCTION__ << "failed"; - return nullptr; - } - - m_mutex.lock(); - m_currentState = QAudio::IdleState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - - return m_eventDevice; -} - -void QWasapiAudioOutput::stop() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return; - - if (!m_pullMode) { - HRESULT hr; - hr = m_interface->m_client->Stop(); - hr = m_interface->m_client->Reset(); - } - - m_mutex.lock(); - m_currentState = QAudio::StoppedState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - if (m_currentError != QAudio::NoError) { - m_mutex.lock(); - m_currentError = QAudio::NoError; - m_mutex.unlock(); - emit errorChanged(m_currentError); - } - - HRESULT hr = m_interface->m_client->Stop(); - if (m_currentState == QAudio::StoppedState) { - hr = m_interface->m_client->Reset(); - } - - if (m_eventThread) { - SetEvent(m_eventThread->m_event); - while (m_eventThread->isRunning()) - QThread::yieldCurrentThread(); - m_eventThread->deleteLater(); - m_eventThread = 0; - } -} - -int QWasapiAudioOutput::bytesFree() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) - return 0; - - quint32 paddingFrames; - HRESULT hr = m_interface->m_client->GetCurrentPadding(&paddingFrames); - if (FAILED(hr)) { - qCDebug(lcMmAudioOutput) << __FUNCTION__ << "Could not query padding frames."; - return bufferSize(); - } - - const quint32 availableFrames = m_bufferFrames - paddingFrames; - const quint32 res = availableFrames * m_currentFormat.channelCount() * m_currentFormat.sampleSize() / 8; - return res; -} - -int QWasapiAudioOutput::periodSize() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - REFERENCE_TIME defaultDevicePeriod; - HRESULT hr = m_interface->m_client->GetDevicePeriod(&defaultDevicePeriod, NULL); - if (FAILED(hr)) - return 0; - const QAudioFormat f = m_currentFormat.isValid() ? m_currentFormat : m_interface->m_mixFormat; - const int res = m_currentFormat.bytesForDuration(defaultDevicePeriod / 10); - return res; -} - -void QWasapiAudioOutput::setBufferSize(int value) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << value; - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - return; - m_bufferBytes = value; -} - -int QWasapiAudioOutput::bufferSize() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - if (m_currentState == QAudio::ActiveState || m_currentState == QAudio::IdleState) - return m_bufferFrames * m_currentFormat.channelCount()* m_currentFormat.sampleSize() / 8; - - return m_bufferBytes; -} - -void QWasapiAudioOutput::setNotifyInterval(int ms) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << ms; - m_interval = qMax(0, ms); -} - -int QWasapiAudioOutput::notifyInterval() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - return m_interval; -} - -qint64 QWasapiAudioOutput::processedUSecs() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return 0; - qint64 res = qint64(1000000) * m_bytesProcessed / - (m_currentFormat.channelCount() * (m_currentFormat.sampleSize() / 8)) / - m_currentFormat.sampleRate(); - - return res; -} - -void QWasapiAudioOutput::resume() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - - if (m_currentState != QAudio::SuspendedState) - return; - - HRESULT hr = m_interface->m_client->Start(); - EMIT_RETURN_VOID_IF_FAILED("Could not start audio render client.", QAudio::FatalError) - - m_mutex.lock(); - m_currentError = QAudio::NoError; - m_currentState = m_pullMode ? QAudio::ActiveState : QAudio::IdleState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - if (m_eventThread) - m_eventThread->start(); -} - -void QWasapiAudioOutput::setFormat(const QAudioFormat& fmt) -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__ << fmt; - if (m_currentState != QAudio::StoppedState) - return; - m_currentFormat = fmt; -} - -QAudioFormat QWasapiAudioOutput::format() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - return m_currentFormat; -} - -void QWasapiAudioOutput::suspend() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - - if (m_currentState != QAudio::ActiveState && m_currentState != QAudio::IdleState) - return; - - m_mutex.lock(); - m_currentState = QAudio::SuspendedState; - m_mutex.unlock(); - emit stateChanged(m_currentState); - - HRESULT hr = m_interface->m_client->Stop(); - EMIT_RETURN_VOID_IF_FAILED("Could not suspend audio render client.", QAudio::FatalError); - if (m_eventThread) { - SetEvent(m_eventThread->m_event); - while (m_eventThread->isRunning()) - QThread::yieldCurrentThread(); - qCDebug(lcMmAudioOutput) << __FUNCTION__ << "Thread has stopped"; - } -} - -qint64 QWasapiAudioOutput::elapsedUSecs() const -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - if (m_currentState == QAudio::StoppedState) - return 0; - return m_openTime.elapsed() * qint64(1000); -} - -void QWasapiAudioOutput::reset() -{ - qCDebug(lcMmAudioOutput) << __FUNCTION__; - stop(); -} - -QT_END_NAMESPACE - -#include "qwasapiaudiooutput.moc" diff --git a/src/plugins/wasapi/qwasapiaudiooutput.h b/src/plugins/wasapi/qwasapiaudiooutput.h deleted file mode 100644 index e5d5bc5b1..000000000 --- a/src/plugins/wasapi/qwasapiaudiooutput.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QAUDIOOUTPUTWASAPI_H -#define QAUDIOOUTPUTWASAPI_H - -#include -#include -#include -#include -#include - -#include -#include - -struct IAudioRenderClient; -struct IAudioStreamVolume; - -QT_BEGIN_NAMESPACE - -class AudioInterface; -class WasapiOutputDevicePrivate; -class QWasapiProcessThread; - -Q_DECLARE_LOGGING_CATEGORY(lcMmAudioOutput) - -class QWasapiAudioOutput : public QAbstractAudioOutput -{ - Q_OBJECT -public: - explicit QWasapiAudioOutput(const QByteArray &device); - ~QWasapiAudioOutput(); - - void start(QIODevice* device) override; - QIODevice* start() override; - void stop() override; - void reset() override; - void suspend() override; - void resume() override; - int bytesFree() const override; - int periodSize() const override; - void setBufferSize(int value) override; - int bufferSize() const override; - void setNotifyInterval(int milliSeconds) override; - int notifyInterval() const override; - qint64 processedUSecs() const override; - qint64 elapsedUSecs() const override; - QAudio::Error error() const override; - QAudio::State state() const override; - void setFormat(const QAudioFormat& fmt) override; - QAudioFormat format() const override; - void setVolume(qreal) override; - qreal volume() const override; - - void process(); -public slots: - void processBuffer(); -private: - bool initStart(bool pull); - friend class WasapiOutputDevicePrivate; - friend class WasapiOutputPrivate; - QByteArray m_deviceName; - Microsoft::WRL::ComPtr m_interface; - Microsoft::WRL::ComPtr m_renderer; - Microsoft::WRL::ComPtr m_volumeControl; - qreal m_volumeCache; - QMutex m_mutex; - QAudio::State m_currentState; - QAudio::Error m_currentError; - QAudioFormat m_currentFormat; - qint64 m_bytesProcessed; - QElapsedTimer m_openTime; - int m_openTimeOffset; - int m_interval; - bool m_pullMode; - quint32 m_bufferFrames; - quint32 m_bufferBytes; - HANDLE m_event; - QWasapiProcessThread *m_eventThread; - QAtomicInt m_processing; - QIODevice *m_eventDevice; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/wasapi/qwasapiplugin.cpp b/src/plugins/wasapi/qwasapiplugin.cpp deleted file mode 100644 index 9325dc400..000000000 --- a/src/plugins/wasapi/qwasapiplugin.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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 "qwasapiplugin.h" -#include "qwasapiaudiodeviceinfo.h" -#include "qwasapiaudioinput.h" -#include "qwasapiaudiooutput.h" -#include "qwasapiutils.h" - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMmPlugin, "qt.multimedia.plugin") - -QWasapiPlugin::QWasapiPlugin(QObject *parent) - : QAudioSystemPlugin(parent) -{ - qCDebug(lcMmPlugin) << __FUNCTION__; -} - -QByteArray QWasapiPlugin::defaultDevice(QAudio::Mode mode) const -{ - return QWasapiUtils::defaultDevice(mode); -} - -QList QWasapiPlugin::availableDevices(QAudio::Mode mode) const -{ - qCDebug(lcMmPlugin) << __FUNCTION__ << mode; - return QWasapiUtils::availableDevices(mode); -} - -QAbstractAudioInput *QWasapiPlugin::createInput(const QByteArray &device) -{ - qCDebug(lcMmPlugin) << __FUNCTION__ << device; - return new QWasapiAudioInput(device); -} - -QAbstractAudioOutput *QWasapiPlugin::createOutput(const QByteArray &device) -{ - qCDebug(lcMmPlugin) << __FUNCTION__ << device; - return new QWasapiAudioOutput(device); -} - -QAbstractAudioDeviceInfo *QWasapiPlugin::createDeviceInfo(const QByteArray &device, QAudio::Mode mode) -{ - qCDebug(lcMmPlugin) << __FUNCTION__ << device << mode; - return new QWasapiAudioDeviceInfo(device, mode); -} - -QT_END_NAMESPACE diff --git a/src/plugins/wasapi/qwasapiplugin.h b/src/plugins/wasapi/qwasapiplugin.h deleted file mode 100644 index 7b20676f6..000000000 --- a/src/plugins/wasapi/qwasapiplugin.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QWASAPIPLUGIN_H -#define QWASAPIPLUGIN_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcMmPlugin) - -class QWasapiPlugin : public QAudioSystemPlugin, public QAudioSystemPluginExtension -{ - Q_OBJECT - - Q_PLUGIN_METADATA(IID "org.qt-project.qt.audiosystemfactory/5.0" FILE "wasapi.json") - Q_INTERFACES(QAudioSystemPluginExtension) - -public: - explicit QWasapiPlugin(QObject *parent = 0); - ~QWasapiPlugin() {} - - QByteArray defaultDevice(QAudio::Mode mode) const override; - QList availableDevices(QAudio::Mode mode) const override; - QAbstractAudioInput *createInput(const QByteArray &device) override; - QAbstractAudioOutput *createOutput(const QByteArray &device) override; - QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode) override; - -private: - QList m_deviceNames; - QList m_deviceIds; -}; - -QT_END_NAMESPACE - -#endif // QWASAPIPLUGIN_H diff --git a/src/plugins/wasapi/qwasapiutils.cpp b/src/plugins/wasapi/qwasapiutils.cpp deleted file mode 100644 index 497e5fa6e..000000000 --- a/src/plugins/wasapi/qwasapiutils.cpp +++ /dev/null @@ -1,344 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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 "qwasapiutils.h" - -#include -#include - -// For Desktop Win32 support -#ifdef CLASSIC_APP_BUILD -#define Q_OS_WINRT -#endif -#include - -#include -#include -#include -#include -#include - -#include - -using namespace ABI::Windows::Devices::Enumeration; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Foundation::Collections; -using namespace ABI::Windows::Media::Devices; -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -#define RETURN_EMPTY_LIST_IF_FAILED(msg) RETURN_IF_FAILED(msg, return QList()) - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMmAudioInterface, "qt.multimedia.audiointerface") -Q_LOGGING_CATEGORY(lcMmUtils, "qt.multimedia.utils") - -#ifdef CLASSIC_APP_BUILD -// Opening bracket has to be in the same line as MSVC2013 and 2015 complain on -// different lines otherwise -#pragma warning (suppress: 4273) -HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function &delegate, bool waitForRun) { - Q_UNUSED(waitForRun) - return delegate(); -} -#endif - -namespace QWasapiUtils { -struct DeviceMapping { - QList outputDeviceNames; - QList outputDeviceIds; - QList inputDeviceNames; - QList inputDeviceIds; -}; -Q_GLOBAL_STATIC(DeviceMapping, gMapping) -} - -struct CoInitializer -{ - CoInitializer() - { - CoInitializeEx(NULL, COINIT_MULTITHREADED); - } - - ~CoInitializer() - { - CoUninitialize(); - } -}; - -static void CoInitIfNeeded() -{ - static CoInitializer initializer; -} - -AudioInterface::AudioInterface() -{ - qCDebug(lcMmAudioInterface) << __FUNCTION__; - m_currentState = Initialized; -} - -AudioInterface::~AudioInterface() -{ - qCDebug(lcMmAudioInterface) << __FUNCTION__; -} - -HRESULT AudioInterface::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *op) -{ - qCDebug(lcMmAudioInterface) << __FUNCTION__; - - IUnknown *aInterface; - HRESULT hr; - HRESULT hrActivate; - hr = op->GetActivateResult(&hrActivate, &aInterface); - if (FAILED(hr) || FAILED(hrActivate)) { - qCDebug(lcMmAudioInterface) << __FUNCTION__ << "Could not query activate results."; - m_currentState = Error; - return hr; - } - - hr = aInterface->QueryInterface(IID_PPV_ARGS(&m_client)); - if (FAILED(hr)) { - qCDebug(lcMmAudioInterface) << __FUNCTION__ << "Could not access AudioClient interface."; - m_currentState = Error; - return hr; - } - - WAVEFORMATEX *format; - hr = m_client->GetMixFormat(&format); - if (FAILED(hr)) { - qCDebug(lcMmAudioInterface) << __FUNCTION__ << "Could not get mix format."; - m_currentState = Error; - return hr; - } - - QWasapiUtils::convertFromNativeFormat(format, &m_mixFormat); - - m_currentState = Activated; - return S_OK; -} - -bool QWasapiUtils::convertToNativeFormat(const QAudioFormat &qt, WAVEFORMATEX *native) -{ - if (!native - || !qt.isValid() - || qt.codec() != QStringLiteral("audio/pcm") - || qt.sampleRate() <= 0 - || qt.channelCount() <= 0 - || qt.sampleSize() <= 0 - || qt.byteOrder() != QAudioFormat::LittleEndian) { - return false; - } - - native->nSamplesPerSec = qt.sampleRate(); - native->wBitsPerSample = qt.sampleSize(); - native->nChannels = qt.channelCount(); - native->nBlockAlign = (native->wBitsPerSample * native->nChannels) / 8; - native->nAvgBytesPerSec = native->nBlockAlign * native->nSamplesPerSec; - native->cbSize = 0; - - if (qt.sampleType() == QAudioFormat::Float) - native->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - else - native->wFormatTag = WAVE_FORMAT_PCM; - - return true; -} - -bool QWasapiUtils::convertFromNativeFormat(const WAVEFORMATEX *native, QAudioFormat *qt) -{ - if (!native || !qt) - return false; - - qt->setByteOrder(QAudioFormat::LittleEndian); - qt->setChannelCount(native->nChannels); - qt->setCodec(QStringLiteral("audio/pcm")); - qt->setSampleRate(native->nSamplesPerSec); - qt->setSampleSize(native->wBitsPerSample); - qt->setSampleType(native->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ? QAudioFormat::Float : QAudioFormat::SignedInt); - - return true; -} - -QByteArray QWasapiUtils::defaultDevice(QAudio::Mode mode) -{ - qCDebug(lcMmUtils) << __FUNCTION__ << mode; - - CoInitIfNeeded(); - QList &deviceNames = mode == QAudio::AudioInput ? gMapping->inputDeviceNames : gMapping->outputDeviceNames; - QList &deviceIds = mode == QAudio::AudioInput ? gMapping->inputDeviceIds : gMapping->outputDeviceIds; - if (deviceNames.isEmpty() || deviceIds.isEmpty()) // Initialize - availableDevices(mode); - if (deviceNames.isEmpty() || deviceIds.isEmpty()) // No audio devices at all - return QByteArray(); - - ComPtr mediaDeviceStatics; - HRESULT hr; - - hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Media_Devices_MediaDevice).Get(), &mediaDeviceStatics); - Q_ASSERT_SUCCEEDED(hr); - - HString defaultAudioDevice; - quint32 dADSize = 0; - - if (mode == QAudio::AudioOutput) - hr = mediaDeviceStatics->GetDefaultAudioRenderId(AudioDeviceRole_Default, defaultAudioDevice.GetAddressOf()); - else - hr = mediaDeviceStatics->GetDefaultAudioCaptureId(AudioDeviceRole_Default, defaultAudioDevice.GetAddressOf()); - - const wchar_t *dadWStr = defaultAudioDevice.GetRawBuffer(&dADSize); - const QString defaultAudioDeviceId = QString::fromWCharArray(dadWStr, dADSize); - Q_ASSERT(deviceIds.indexOf(defaultAudioDeviceId) != -1); - - return deviceNames.at(deviceIds.indexOf(defaultAudioDeviceId)); -} - -QList QWasapiUtils::availableDevices(QAudio::Mode mode) -{ - qCDebug(lcMmUtils) << __FUNCTION__ << mode; - - CoInitIfNeeded(); - ComPtr statics; - HRESULT hr; - - hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), - &statics); - Q_ASSERT_SUCCEEDED(hr); - - DeviceClass dc = mode == QAudio::AudioInput ? DeviceClass_AudioCapture : DeviceClass_AudioRender; - - QList &deviceNames = mode == QAudio::AudioInput ? gMapping->inputDeviceNames : gMapping->outputDeviceNames; - QList &deviceIds = mode == QAudio::AudioInput ? gMapping->inputDeviceIds : gMapping->outputDeviceIds; - - // We need to refresh due to plugable devices (ie USB) - deviceNames.clear(); - deviceIds.clear(); - - ComPtr> op; - hr = statics->FindAllAsyncDeviceClass(dc, &op ); - RETURN_EMPTY_LIST_IF_FAILED("Could not query audio devices."); - - ComPtr> resultVector; - hr = QWinRTFunctions::await(op, resultVector.GetAddressOf()); - RETURN_EMPTY_LIST_IF_FAILED("Could not receive audio device list."); - - quint32 deviceCount; - hr = resultVector->get_Size(&deviceCount); - RETURN_EMPTY_LIST_IF_FAILED("Could not access audio device count."); - qCDebug(lcMmUtils) << "Found " << deviceCount << " audio devices for" << mode; - - for (quint32 i = 0; i < deviceCount; ++i) { - ComPtr item; - hr = resultVector->GetAt(i, &item); - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not access audio device item."); - continue; - } - - HString hString; - quint32 size; - - hr = item->get_Name(hString.GetAddressOf()); - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not access audio device name."); - continue; - } - const wchar_t *nameWStr = hString.GetRawBuffer(&size); - const QString deviceName = QString::fromWCharArray(nameWStr, size); - - hr = item->get_Id(hString.GetAddressOf()); - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not access audio device id."); - continue; - } - const wchar_t *idWStr = hString.GetRawBuffer(&size); - const QString deviceId = QString::fromWCharArray(idWStr, size); - - boolean enabled; - hr = item->get_IsEnabled(&enabled); - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not access audio device enabled."); - continue; - } - - qCDebug(lcMmUtils) << "Audio Device:" << deviceName << " ID:" << deviceId - << " Enabled:" << enabled; - - deviceNames.append(deviceName.toLocal8Bit()); - deviceIds.append(deviceId); - } - return deviceNames; -} - -Microsoft::WRL::ComPtr QWasapiUtils::createOrGetInterface(const QByteArray &dev, QAudio::Mode mode) -{ - qCDebug(lcMmUtils) << __FUNCTION__ << dev << mode; - Q_ASSERT((mode == QAudio::AudioInput ? gMapping->inputDeviceNames.indexOf(dev) : gMapping->outputDeviceNames.indexOf(dev)) != -1); - CoInitIfNeeded(); - - Microsoft::WRL::ComPtr result; - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([dev, mode, &result]() { - HRESULT hr; - QString id = mode == QAudio::AudioInput ? gMapping->inputDeviceIds.at(gMapping->inputDeviceNames.indexOf(dev)) : - gMapping->outputDeviceIds.at(gMapping->outputDeviceNames.indexOf(dev)); - - result = Make(); - - ComPtr op; - - // We cannot use QWinRTFunctions::await here as that will return - // E_NO_INTERFACE. Instead we leave the lambda and wait for the - // status to get out of Activating - result->setState(AudioInterface::Activating); - hr = ActivateAudioInterfaceAsync(reinterpret_cast(id.utf16()), __uuidof(IAudioClient), NULL, result.Get(), op.GetAddressOf()); - if (FAILED(hr)) { - qErrnoWarning(hr, "Could not invoke audio interface activation."); - result->setState(AudioInterface::Error); - } - return hr; - }); - qCDebug(lcMmUtils) << "Activation stated:" << hr; - while (result->state() == AudioInterface::Activating) { - QThread::yieldCurrentThread(); - } - qCDebug(lcMmUtils) << "Activation done:" << hr; - return result; -} - -QT_END_NAMESPACE diff --git a/src/plugins/wasapi/qwasapiutils.h b/src/plugins/wasapi/qwasapiutils.h deleted file mode 100644 index 7cfdd3cda..000000000 --- a/src/plugins/wasapi/qwasapiutils.h +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $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$ -** -****************************************************************************/ - -#ifndef QWASAPIUTILS_H -#define QWASAPIUTILS_H -#include "qwasapiaudiodeviceinfo.h" -#include "qwasapiaudioinput.h" -#include "qwasapiaudiooutput.h" -#include -#include -#include -#include - -#include -#include -#include - -struct IAudioClient; - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcMmAudioInterface) -Q_DECLARE_LOGGING_CATEGORY(lcMmUtils) - -#define EMIT_RETURN_FALSE_IF_FAILED(msg, err) \ - if (FAILED(hr)) { \ - m_currentError = err; \ - emit errorChanged(m_currentError); \ - } \ - RETURN_FALSE_IF_FAILED(msg) - -#define EMIT_RETURN_VOID_IF_FAILED(msg, err) \ - if (FAILED(hr)) { \ - m_currentError = err; \ - emit errorChanged(m_currentError); \ - } \ - RETURN_VOID_IF_FAILED(msg) - -class AudioInterface : public Microsoft::WRL::RuntimeClass, Microsoft::WRL::FtmBase, IActivateAudioInterfaceCompletionHandler> -{ -public: - enum State { - Initialized = 0, - Activating, - Activated, - Error - } ; - - explicit AudioInterface(); - - ~AudioInterface(); - - virtual HRESULT STDMETHODCALLTYPE ActivateCompleted(IActivateAudioInterfaceAsyncOperation *op); - - inline State state() const { return m_currentState; } - void setState(State s) { m_currentState = s; } - - Microsoft::WRL::ComPtr m_client; - QWasapiAudioDeviceInfo *m_parent; - State m_currentState; - QAudioFormat m_mixFormat; -}; - -class QWasapiProcessThread : public QThread -{ -public: - explicit QWasapiProcessThread(QObject *item, bool output = true) : QThread(), - m_endpoint(item), - m_output(output) - { - qCDebug(lcMmUtils) << __FUNCTION__ << item; - } - - ~QWasapiProcessThread() - { - qCDebug(lcMmUtils) << __FUNCTION__; - CloseHandle(m_event); - } - - void run() - { - qCDebug(lcMmUtils) << __FUNCTION__ << m_endpoint; - if (m_output) { - QWasapiAudioOutput *output = static_cast(m_endpoint); - output->process(); - } else { - QWasapiAudioInput *input = static_cast(m_endpoint); - input->process(); - } - } - - HANDLE m_event; -private: - QObject *m_endpoint; - bool m_output; -}; - -namespace QWasapiUtils -{ - bool convertToNativeFormat(const QAudioFormat &qt, WAVEFORMATEX *native); - bool convertFromNativeFormat(const WAVEFORMATEX *native, QAudioFormat *qt); - - QByteArray defaultDevice(QAudio::Mode mode); - QList availableDevices(QAudio::Mode mode); - Microsoft::WRL::ComPtr createOrGetInterface(const QByteArray &dev, QAudio::Mode mode); -} - -QT_END_NAMESPACE - -#endif // QWASAPIUTILS_H diff --git a/src/plugins/wasapi/wasapi.json b/src/plugins/wasapi/wasapi.json deleted file mode 100644 index 8d6876490..000000000 --- a/src/plugins/wasapi/wasapi.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": ["wasapi"] -} diff --git a/src/plugins/wasapi/wasapi.pro b/src/plugins/wasapi/wasapi.pro deleted file mode 100644 index 11dfd8abe..000000000 --- a/src/plugins/wasapi/wasapi.pro +++ /dev/null @@ -1,30 +0,0 @@ -TARGET = qtaudio_wasapi -QT += core-private multimedia-private - -HEADERS += \ - qwasapiplugin.h \ - qwasapiaudiodeviceinfo.h \ - qwasapiaudioinput.h \ - qwasapiaudiooutput.h \ - qwasapiutils.h - -SOURCES += \ - qwasapiplugin.cpp \ - qwasapiaudiodeviceinfo.cpp \ - qwasapiaudioinput.cpp \ - qwasapiaudiooutput.cpp \ - qwasapiutils.cpp - -OTHER_FILES += \ - wasapi.json - -LIBS += Mmdevapi.lib - -win32-* { - DEFINES += CLASSIC_APP_BUILD - LIBS += runtimeobject.lib -} - -PLUGIN_TYPE = audio -PLUGIN_CLASS_NAME = QWasapiPlugin -load(qt_plugin) -- cgit v1.2.3