diff options
author | Christian Strømme <christian.stromme@digia.com> | 2013-11-23 00:14:15 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-01-30 18:15:36 +0100 |
commit | 2d54da2d39217e7b21ccafa9594513d554352a24 (patch) | |
tree | b9a620c05741fc81875c11fa351ea25713b1583c /src/multimedia | |
parent | 0ab81ef59f35d103ec8174834c4fc2a4dcced453 (diff) |
Move win32 and Alsa audio backends into plugins.
Change-Id: I9835cf5ee97900569f26421a19543b485e933051
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
Diffstat (limited to 'src/multimedia')
-rw-r--r-- | src/multimedia/audio/audio.pri | 18 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiodevicefactory.cpp | 55 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp | 464 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiodeviceinfo_alsa_p.h | 123 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp | 490 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiodeviceinfo_win32_p.h | 114 | ||||
-rw-r--r-- | src/multimedia/audio/qaudioinput_alsa_p.cpp | 882 | ||||
-rw-r--r-- | src/multimedia/audio/qaudioinput_alsa_p.h | 188 | ||||
-rw-r--r-- | src/multimedia/audio/qaudioinput_win32_p.cpp | 753 | ||||
-rw-r--r-- | src/multimedia/audio/qaudioinput_win32_p.h | 180 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiooutput_alsa_p.cpp | 860 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiooutput_alsa_p.h | 173 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiooutput_win32_p.cpp | 762 | ||||
-rw-r--r-- | src/multimedia/audio/qaudiooutput_win32_p.h | 172 |
14 files changed, 1 insertions, 5233 deletions
diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri index 6fad6604c..96cfb1ce4 100644 --- a/src/multimedia/audio/audio.pri +++ b/src/multimedia/audio/audio.pri @@ -39,17 +39,8 @@ SOURCES += \ audio/qaudiodecoder.cpp \ audio/qaudiohelpers.cpp -win32 { - PRIVATE_HEADERS += audio/qaudioinput_win32_p.h audio/qaudiooutput_win32_p.h audio/qaudiodeviceinfo_win32_p.h - SOURCES += audio/qaudiodeviceinfo_win32_p.cpp \ - audio/qaudiooutput_win32_p.cpp \ - audio/qaudioinput_win32_p.cpp - LIBS_PRIVATE += -lwinmm -lstrmiids -lole32 -loleaut32 -} - unix:!mac { config_pulseaudio { - DEFINES += QT_NO_AUDIO_BACKEND CONFIG += link_pkgconfig PKGCONFIG_PRIVATE += libpulse @@ -61,15 +52,6 @@ unix:!mac { DEFINES += QT_MULTIMEDIA_QAUDIO PRIVATE_HEADERS += audio/qsoundeffect_qaudio_p.h SOURCES += audio/qsoundeffect_qaudio_p.cpp - - config_alsa { - DEFINES += HAS_ALSA - PRIVATE_HEADERS += audio/qaudiooutput_alsa_p.h audio/qaudioinput_alsa_p.h audio/qaudiodeviceinfo_alsa_p.h - SOURCES += audio/qaudiodeviceinfo_alsa_p.cpp \ - audio/qaudiooutput_alsa_p.cpp \ - audio/qaudioinput_alsa_p.cpp - LIBS_PRIVATE += -lasound - } } } else { DEFINES += QT_MULTIMEDIA_QAUDIO diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp index e2d4ec3e8..a36ab3932 100644 --- a/src/multimedia/audio/qaudiodevicefactory.cpp +++ b/src/multimedia/audio/qaudiodevicefactory.cpp @@ -47,18 +47,6 @@ #include "qmediapluginloader_p.h" #include "qaudiodevicefactory_p.h" -#ifndef QT_NO_AUDIO_BACKEND -#if defined(Q_OS_WIN) -#include "qaudiodeviceinfo_win32_p.h" -#include "qaudiooutput_win32_p.h" -#include "qaudioinput_win32_p.h" -#elif defined(HAS_ALSA) -#include "qaudiodeviceinfo_alsa_p.h" -#include "qaudiooutput_alsa_p.h" -#include "qaudioinput_alsa_p.h" -#endif -#endif - QT_BEGIN_NAMESPACE #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) @@ -132,13 +120,6 @@ public: QList<QAudioDeviceInfo> QAudioDeviceFactory::availableDevices(QAudio::Mode mode) { QList<QAudioDeviceInfo> devices; -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - foreach (const QByteArray &handle, QAudioDeviceInfoInternal::availableDevices(mode)) - devices << QAudioDeviceInfo(QLatin1String("builtin"), handle, mode); -#endif -#endif - #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QMediaPluginLoader* l = audioLoader(); foreach (const QString& key, l->keys()) { @@ -165,11 +146,6 @@ QAudioDeviceInfo QAudioDeviceFactory::defaultInputDevice() } #endif -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultInputDevice(), QAudio::AudioInput); -#endif -#endif return QAudioDeviceInfo(); } @@ -185,11 +161,6 @@ QAudioDeviceInfo QAudioDeviceFactory::defaultOutputDevice() } #endif -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - return QAudioDeviceInfo(QLatin1String("builtin"), QAudioDeviceInfoInternal::defaultOutputDevice(), QAudio::AudioOutput); -#endif -#endif return QAudioDeviceInfo(); } @@ -197,13 +168,6 @@ QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(const QString &re { QAbstractAudioDeviceInfo *rc = 0; -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - if (realm == QLatin1String("builtin")) - return new QAudioDeviceInfoInternal(handle, mode); -#endif -#endif - #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(realm)); @@ -229,15 +193,7 @@ QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceInfo con { if (deviceInfo.isNull()) return new QNullInputDevice(); -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - if (deviceInfo.realm() == QLatin1String("builtin")) { - QAbstractAudioInput* p = new QAudioInputPrivate(deviceInfo.handle()); - if (p) p->setFormat(format); - return p; - } -#endif -#endif + #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QAudioSystemFactoryInterface* plugin = qobject_cast<QAudioSystemFactoryInterface*>(audioLoader()->instance(deviceInfo.realm())); @@ -256,15 +212,6 @@ QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceInfo c { if (deviceInfo.isNull()) return new QNullOutputDevice(); -#ifndef QT_NO_AUDIO_BACKEND -#if (defined(Q_OS_WIN) || defined(HAS_ALSA)) - if (deviceInfo.realm() == QLatin1String("builtin")) { - QAbstractAudioOutput* p = new QAudioOutputPrivate(deviceInfo.handle()); - if (p) p->setFormat(format); - return p; - } -#endif -#endif #if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QAudioSystemFactoryInterface* plugin = diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp deleted file mode 100644 index bd8fa8949..000000000 --- a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - -#include "qaudiodeviceinfo_alsa_p.h" - -#include <alsa/version.h> - -QT_BEGIN_NAMESPACE - -QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) -{ - handle = 0; - - device = QLatin1String(dev); - this->mode = mode; - - checkSurround(); -} - -QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() -{ - close(); -} - -bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const -{ - return testSettings(format); -} - -QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const -{ - QAudioFormat nearest; - if(mode == QAudio::AudioOutput) { - nearest.setSampleRate(44100); - nearest.setChannelCount(2); - nearest.setByteOrder(QAudioFormat::LittleEndian); - nearest.setSampleType(QAudioFormat::SignedInt); - nearest.setSampleSize(16); - nearest.setCodec(QLatin1String("audio/pcm")); - } else { - nearest.setSampleRate(8000); - nearest.setChannelCount(1); - nearest.setSampleType(QAudioFormat::UnSignedInt); - nearest.setSampleSize(8); - nearest.setCodec(QLatin1String("audio/pcm")); - if(!testSettings(nearest)) { - nearest.setChannelCount(2); - nearest.setSampleSize(16); - nearest.setSampleType(QAudioFormat::SignedInt); - } - } - return nearest; -} - -QString QAudioDeviceInfoInternal::deviceName() const -{ - return device; -} - -QStringList QAudioDeviceInfoInternal::supportedCodecs() -{ - updateLists(); - return codecz; -} - -QList<int> QAudioDeviceInfoInternal::supportedSampleRates() -{ - updateLists(); - return sampleRatez; -} - -QList<int> QAudioDeviceInfoInternal::supportedChannelCounts() -{ - updateLists(); - return channelz; -} - -QList<int> QAudioDeviceInfoInternal::supportedSampleSizes() -{ - updateLists(); - return sizez; -} - -QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders() -{ - updateLists(); - return byteOrderz; -} - -QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes() -{ - updateLists(); - return typez; -} - -bool QAudioDeviceInfoInternal::open() -{ - int err = 0; - QString dev = device; - QList<QByteArray> devices = availableDevices(mode); - - if(dev.compare(QLatin1String("default")) == 0) { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - if (devices.size() > 0) - dev = QLatin1String(devices.first().constData()); - else - return false; -#else - dev = QLatin1String("hw:0,0"); -#endif - } else { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - dev = device; -#else - int idx = 0; - char *name; - - QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); - - while (snd_card_get_name(idx,&name) == 0) { - if(dev.contains(QLatin1String(name))) - break; - idx++; - } - dev = QString(QLatin1String("hw:%1,0")).arg(idx); -#endif - } - if(mode == QAudio::AudioOutput) { - err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); - } else { - err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); - } - if(err < 0) { - handle = 0; - return false; - } - return true; -} - -void QAudioDeviceInfoInternal::close() -{ - if(handle) - snd_pcm_close(handle); - handle = 0; -} - -bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const -{ - // Set nearest to closest settings that do work. - // See if what is in settings will work (return value). - int err = -1; - snd_pcm_t* pcmHandle; - snd_pcm_hw_params_t *params; - QString dev; - -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - dev = device; - if (dev.compare(QLatin1String("default")) == 0) { - QList<QByteArray> devices = availableDevices(QAudio::AudioOutput); - if (!devices.isEmpty()) - dev = QLatin1String(devices.first().constData()); - } -#else - if (dev.compare(QLatin1String("default")) == 0) { - dev = QLatin1String("hw:0,0"); - } else { - int idx = 0; - char *name; - - QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1); - - while(snd_card_get_name(idx,&name) == 0) { - if(shortName.compare(QLatin1String(name)) == 0) - break; - idx++; - } - dev = QString(QLatin1String("hw:%1,0")).arg(idx); - } -#endif - - snd_pcm_stream_t stream = mode == QAudio::AudioOutput - ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; - - if (snd_pcm_open(&pcmHandle, dev.toLocal8Bit().constData(), stream, 0) < 0) - return false; - - snd_pcm_nonblock(pcmHandle, 0); - snd_pcm_hw_params_alloca(¶ms); - snd_pcm_hw_params_any(pcmHandle, params); - - // set the values! - snd_pcm_hw_params_set_channels(pcmHandle, params, format.channelCount()); - snd_pcm_hw_params_set_rate(pcmHandle, params, format.sampleRate(), 0); - - snd_pcm_format_t pcmFormat = SND_PCM_FORMAT_UNKNOWN; - switch (format.sampleSize()) { - case 8: - if (format.sampleType() == QAudioFormat::SignedInt) - pcmFormat = SND_PCM_FORMAT_S8; - else if (format.sampleType() == QAudioFormat::UnSignedInt) - pcmFormat = SND_PCM_FORMAT_U8; - break; - case 16: - if (format.sampleType() == QAudioFormat::SignedInt) { - pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian - ? SND_PCM_FORMAT_S16_LE : SND_PCM_FORMAT_S16_BE; - } else if (format.sampleType() == QAudioFormat::UnSignedInt) { - pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian - ? SND_PCM_FORMAT_U16_LE : SND_PCM_FORMAT_U16_BE; - } - break; - case 32: - if (format.sampleType() == QAudioFormat::SignedInt) { - pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian - ? SND_PCM_FORMAT_S32_LE : SND_PCM_FORMAT_S32_BE; - } else if (format.sampleType() == QAudioFormat::UnSignedInt) { - pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian - ? SND_PCM_FORMAT_U32_LE : SND_PCM_FORMAT_U32_BE; - } else if (format.sampleType() == QAudioFormat::Float) { - pcmFormat = format.byteOrder() == QAudioFormat::LittleEndian - ? SND_PCM_FORMAT_FLOAT_LE : SND_PCM_FORMAT_FLOAT_BE; - } - } - - if (pcmFormat != SND_PCM_FORMAT_UNKNOWN) - err = snd_pcm_hw_params_set_format(pcmHandle, params, pcmFormat); - - // For now, just accept only audio/pcm codec - if (!format.codec().startsWith(QLatin1String("audio/pcm"))) - err = -1; - - if (err >= 0 && format.channelCount() != -1) { - err = snd_pcm_hw_params_test_channels(pcmHandle, params, format.channelCount()); - if (err >= 0) - err = snd_pcm_hw_params_set_channels(pcmHandle, params, format.channelCount()); - } - - if (err >= 0 && format.sampleRate() != -1) { - err = snd_pcm_hw_params_test_rate(pcmHandle, params, format.sampleRate(), 0); - if (err >= 0) - err = snd_pcm_hw_params_set_rate(pcmHandle, params, format.sampleRate(), 0); - } - - if (err >= 0 && pcmFormat != SND_PCM_FORMAT_UNKNOWN) - err = snd_pcm_hw_params_set_format(pcmHandle, params, pcmFormat); - - if (err >= 0) - err = snd_pcm_hw_params(pcmHandle, params); - - snd_pcm_close(pcmHandle); - - return (err == 0); -} - -void QAudioDeviceInfoInternal::updateLists() -{ - // redo all lists based on current settings - sampleRatez.clear(); - channelz.clear(); - sizez.clear(); - byteOrderz.clear(); - typez.clear(); - codecz.clear(); - - if(!handle) - open(); - - if(!handle) - return; - - for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) { - //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) - sampleRatez.append(SAMPLE_RATES[i]); - } - channelz.append(1); - channelz.append(2); - if (surround40) channelz.append(4); - if (surround51) channelz.append(6); - if (surround71) channelz.append(8); - sizez.append(8); - sizez.append(16); - sizez.append(32); - byteOrderz.append(QAudioFormat::LittleEndian); - byteOrderz.append(QAudioFormat::BigEndian); - typez.append(QAudioFormat::SignedInt); - typez.append(QAudioFormat::UnSignedInt); - typez.append(QAudioFormat::Float); - codecz.append(QLatin1String("audio/pcm")); - close(); -} - -QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) -{ - QList<QByteArray> devices; - QByteArray filter; - -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - // Create a list of all current audio devices that support mode - void **hints; - char *name, *descr, *io; - int card = -1; - - if(mode == QAudio::AudioInput) { - filter = "Input"; - } else { - filter = "Output"; - } - - while (snd_card_next(&card) == 0 && card >= 0) { - if (snd_device_name_hint(card, "pcm", &hints) < 0) - continue; - - void **n = hints; - while (*n != NULL) { - name = snd_device_name_get_hint(*n, "NAME"); - if (name != 0 && qstrcmp(name, "null") != 0) { - descr = snd_device_name_get_hint(*n, "DESC"); - io = snd_device_name_get_hint(*n, "IOID"); - - if ((descr != NULL) && ((io == NULL) || (io == filter))) { - QString deviceName = QLatin1String(name); - QString deviceDescription = QLatin1String(descr); - if (deviceDescription.contains(QLatin1String("Default Audio Device"))) - devices.prepend(deviceName.toLocal8Bit().constData()); - else - devices.append(deviceName.toLocal8Bit().constData()); - } - - free(descr); - free(io); - } - free(name); - ++n; - } - - snd_device_name_free_hint(hints); - } -#else - int idx = 0; - char* name; - - while(snd_card_get_name(idx,&name) == 0) { - devices.append(name); - idx++; - } -#endif - - if (devices.size() > 0) - devices.append("default"); - - return devices; -} - -QByteArray QAudioDeviceInfoInternal::defaultInputDevice() -{ - QList<QByteArray> devices = availableDevices(QAudio::AudioInput); - if(devices.size() == 0) - return QByteArray(); - - return devices.first(); -} - -QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() -{ - QList<QByteArray> devices = availableDevices(QAudio::AudioOutput); - if(devices.size() == 0) - return QByteArray(); - - return devices.first(); -} - -void QAudioDeviceInfoInternal::checkSurround() -{ - surround40 = false; - surround51 = false; - surround71 = false; - - void **hints; - char *name, *descr, *io; - int card = -1; - - while (snd_card_next(&card) == 0 && card >= 0) { - if (snd_device_name_hint(card, "pcm", &hints) < 0) - continue; - - void **n = hints; - while (*n != NULL) { - name = snd_device_name_get_hint(*n, "NAME"); - descr = snd_device_name_get_hint(*n, "DESC"); - io = snd_device_name_get_hint(*n, "IOID"); - if((name != NULL) && (descr != NULL)) { - QString deviceName = QLatin1String(name); - if (mode == QAudio::AudioOutput) { - if(deviceName.contains(QLatin1String("surround40"))) - surround40 = true; - if(deviceName.contains(QLatin1String("surround51"))) - surround51 = true; - if(deviceName.contains(QLatin1String("surround71"))) - surround71 = true; - } - } - if(name != NULL) - free(name); - if(descr != NULL) - free(descr); - if(io != NULL) - free(io); - ++n; - } - - snd_device_name_free_hint(hints); - } -} - -QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h deleted file mode 100644 index 466bcdece..000000000 --- a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#ifndef QAUDIODEVICEINFOALSA_H -#define QAUDIODEVICEINFOALSA_H - -#include <alsa/asoundlib.h> - -#include <QtCore/qbytearray.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qlist.h> -#include <QtCore/qdebug.h> - -#include "qaudio.h" -#include "qaudiodeviceinfo.h" -#include "qaudiosystem.h" - -QT_BEGIN_NAMESPACE - - -const unsigned int MAX_SAMPLE_RATES = 5; -const unsigned int SAMPLE_RATES[] = - { 8000, 11025, 22050, 44100, 48000 }; - -class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo -{ - Q_OBJECT -public: - QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); - ~QAudioDeviceInfoInternal(); - - bool testSettings(const QAudioFormat& format) const; - void updateLists(); - QAudioFormat preferredFormat() const; - bool isFormatSupported(const QAudioFormat& format) const; - QString deviceName() const; - QStringList supportedCodecs(); - QList<int> supportedSampleRates(); - QList<int> supportedChannelCounts(); - QList<int> supportedSampleSizes(); - QList<QAudioFormat::Endian> supportedByteOrders(); - QList<QAudioFormat::SampleType> supportedSampleTypes(); - static QByteArray defaultInputDevice(); - static QByteArray defaultOutputDevice(); - static QList<QByteArray> availableDevices(QAudio::Mode); - -private: - bool open(); - void close(); - - void checkSurround(); - bool surround40; - bool surround51; - bool surround71; - - QString device; - QAudio::Mode mode; - QAudioFormat nearest; - QList<int> sampleRatez; - QList<int> channelz; - QList<int> sizez; - QList<QAudioFormat::Endian> byteOrderz; - QStringList codecz; - QList<QAudioFormat::SampleType> typez; - snd_pcm_t* handle; - snd_pcm_hw_params_t *params; -}; - -QT_END_NAMESPACE - - -#endif - diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp deleted file mode 100644 index 548a0e9eb..000000000 --- a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - - -#include <QtCore/qt_windows.h> -#include <mmsystem.h> -#include "qaudiodeviceinfo_win32_p.h" - -#if defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR) -struct IBaseFilter; // Needed for strmif.h from stock MinGW. -struct _DDPIXELFORMAT; -typedef struct _DDPIXELFORMAT* LPDDPIXELFORMAT; -#endif - -#include <strmif.h> -#if !defined(Q_CC_MINGW) || defined(__MINGW64_VERSION_MAJOR) -# include <uuids.h> -#else - -extern GUID CLSID_AudioInputDeviceCategory; -extern GUID CLSID_AudioRendererCategory; -extern GUID IID_ICreateDevEnum; -extern GUID CLSID_SystemDeviceEnum; - -#ifndef __ICreateDevEnum_INTERFACE_DEFINED__ -#define __ICreateDevEnum_INTERFACE_DEFINED__ - -DECLARE_INTERFACE_(ICreateDevEnum, IUnknown) -{ - STDMETHOD(CreateClassEnumerator)(REFCLSID clsidDeviceClass, - IEnumMoniker **ppEnumMoniker, - DWORD dwFlags) PURE; -}; - -#endif // __ICreateDevEnum_INTERFACE_DEFINED__ - -#ifndef __IErrorLog_INTERFACE_DEFINED__ -#define __IErrorLog_INTERFACE_DEFINED__ - -DECLARE_INTERFACE_(IErrorLog, IUnknown) -{ - STDMETHOD(AddError)(THIS_ LPCOLESTR, EXCEPINFO *) PURE; -}; - -#endif /* __IErrorLog_INTERFACE_DEFINED__ */ - -#ifndef __IPropertyBag_INTERFACE_DEFINED__ -#define __IPropertyBag_INTERFACE_DEFINED__ - -const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}}; - -DECLARE_INTERFACE_(IPropertyBag, IUnknown) -{ - STDMETHOD(Read)(THIS_ LPCOLESTR, VARIANT *, IErrorLog *) PURE; - STDMETHOD(Write)(THIS_ LPCOLESTR, VARIANT *) PURE; -}; - -#endif /* __IPropertyBag_INTERFACE_DEFINED__ */ - -#endif // defined(Q_CC_MINGW) && !defined(__MINGW64_VERSION_MAJOR) - -QT_BEGIN_NAMESPACE - -// For mingw toolchain mmsystem.h only defines half the defines, so add if needed. -#ifndef WAVE_FORMAT_44M08 -#define WAVE_FORMAT_44M08 0x00000100 -#define WAVE_FORMAT_44S08 0x00000200 -#define WAVE_FORMAT_44M16 0x00000400 -#define WAVE_FORMAT_44S16 0x00000800 -#define WAVE_FORMAT_48M08 0x00001000 -#define WAVE_FORMAT_48S08 0x00002000 -#define WAVE_FORMAT_48M16 0x00004000 -#define WAVE_FORMAT_48S16 0x00008000 -#define WAVE_FORMAT_96M08 0x00010000 -#define WAVE_FORMAT_96S08 0x00020000 -#define WAVE_FORMAT_96M16 0x00040000 -#define WAVE_FORMAT_96S16 0x00080000 -#endif - - -QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode) -{ - QDataStream ds(&dev, QIODevice::ReadOnly); - ds >> devId >> device; - this->mode = mode; - - updateLists(); -} - -QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal() -{ - close(); -} - -bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const -{ - return testSettings(format); -} - -QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const -{ - QAudioFormat nearest; - if (mode == QAudio::AudioOutput) { - nearest.setSampleRate(44100); - nearest.setChannelCount(2); - nearest.setByteOrder(QAudioFormat::LittleEndian); - nearest.setSampleType(QAudioFormat::SignedInt); - nearest.setSampleSize(16); - nearest.setCodec(QLatin1String("audio/pcm")); - } else { - nearest.setSampleRate(11025); - nearest.setChannelCount(1); - nearest.setByteOrder(QAudioFormat::LittleEndian); - nearest.setSampleType(QAudioFormat::SignedInt); - nearest.setSampleSize(8); - nearest.setCodec(QLatin1String("audio/pcm")); - } - return nearest; -} - -QString QAudioDeviceInfoInternal::deviceName() const -{ - return device; -} - -QStringList QAudioDeviceInfoInternal::supportedCodecs() -{ - updateLists(); - return codecz; -} - -QList<int> QAudioDeviceInfoInternal::supportedSampleRates() -{ - updateLists(); - return sampleRatez; -} - -QList<int> QAudioDeviceInfoInternal::supportedChannelCounts() -{ - updateLists(); - return channelz; -} - -QList<int> QAudioDeviceInfoInternal::supportedSampleSizes() -{ - updateLists(); - return sizez; -} - -QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders() -{ - updateLists(); - return byteOrderz; -} - -QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes() -{ - updateLists(); - return typez; -} - - -bool QAudioDeviceInfoInternal::open() -{ - return true; -} - -void QAudioDeviceInfoInternal::close() -{ -} - -bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const -{ - // Set nearest to closest settings that do work. - // See if what is in settings will work (return value). - - bool failed = false; - bool match = false; - - // check codec - for( int i = 0; i < codecz.count(); i++) { - if (format.codec() == codecz.at(i)) - match = true; - } - if (!match) failed = true; - - // check channel - match = false; - if (!failed) { - for (int i = 0; i < channelz.count(); i++) { - if (format.channelCount() == channelz.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sampleRate - match = false; - if (!failed) { - for (int i = 0; i < sampleRatez.count(); i++) { - if (format.sampleRate() == sampleRatez.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sample size - match = false; - if (!failed) { - for( int i = 0; i < sizez.count(); i++) { - if (format.sampleSize() == sizez.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check byte order - match = false; - if (!failed) { - for( int i = 0; i < byteOrderz.count(); i++) { - if (format.byteOrder() == byteOrderz.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - // check sample type - match = false; - if (!failed) { - for( int i = 0; i < typez.count(); i++) { - if (format.sampleType() == typez.at(i)) { - match = true; - break; - } - } - if (!match) - failed = true; - } - - if(!failed) { - // settings work - return true; - } - return false; -} - -void QAudioDeviceInfoInternal::updateLists() -{ - // redo all lists based on current settings - bool match = false; - DWORD fmt = 0; - - if(mode == QAudio::AudioOutput) { - WAVEOUTCAPS woc; - if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { - match = true; - fmt = woc.dwFormats; - } - } else { - WAVEINCAPS woc; - if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { - match = true; - fmt = woc.dwFormats; - } - } - sizez.clear(); - sampleRatez.clear(); - channelz.clear(); - byteOrderz.clear(); - typez.clear(); - codecz.clear(); - - if(match) { - if ((fmt & WAVE_FORMAT_1M08) - || (fmt & WAVE_FORMAT_1S08) - || (fmt & WAVE_FORMAT_2M08) - || (fmt & WAVE_FORMAT_2S08) - || (fmt & WAVE_FORMAT_4M08) - || (fmt & WAVE_FORMAT_4S08) - || (fmt & WAVE_FORMAT_48M08) - || (fmt & WAVE_FORMAT_48S08) - || (fmt & WAVE_FORMAT_96M08) - || (fmt & WAVE_FORMAT_96S08) - ) { - sizez.append(8); - } - if ((fmt & WAVE_FORMAT_1M16) - || (fmt & WAVE_FORMAT_1S16) - || (fmt & WAVE_FORMAT_2M16) - || (fmt & WAVE_FORMAT_2S16) - || (fmt & WAVE_FORMAT_4M16) - || (fmt & WAVE_FORMAT_4S16) - || (fmt & WAVE_FORMAT_48M16) - || (fmt & WAVE_FORMAT_48S16) - || (fmt & WAVE_FORMAT_96M16) - || (fmt & WAVE_FORMAT_96S16) - ) { - sizez.append(16); - } - if ((fmt & WAVE_FORMAT_1M08) - || (fmt & WAVE_FORMAT_1S08) - || (fmt & WAVE_FORMAT_1M16) - || (fmt & WAVE_FORMAT_1S16)) { - sampleRatez.append(11025); - } - if ((fmt & WAVE_FORMAT_2M08) - || (fmt & WAVE_FORMAT_2S08) - || (fmt & WAVE_FORMAT_2M16) - || (fmt & WAVE_FORMAT_2S16)) { - sampleRatez.append(22050); - } - if ((fmt & WAVE_FORMAT_4M08) - || (fmt & WAVE_FORMAT_4S08) - || (fmt & WAVE_FORMAT_4M16) - || (fmt & WAVE_FORMAT_4S16)) { - sampleRatez.append(44100); - } - if ((fmt & WAVE_FORMAT_48M08) - || (fmt & WAVE_FORMAT_48S08) - || (fmt & WAVE_FORMAT_48M16) - || (fmt & WAVE_FORMAT_48S16)) { - sampleRatez.append(48000); - } - if ((fmt & WAVE_FORMAT_96M08) - || (fmt & WAVE_FORMAT_96S08) - || (fmt & WAVE_FORMAT_96M16) - || (fmt & WAVE_FORMAT_96S16)) { - sampleRatez.append(96000); - } - channelz.append(1); - channelz.append(2); - if (mode == QAudio::AudioOutput) { - channelz.append(4); - channelz.append(6); - channelz.append(8); - } - - byteOrderz.append(QAudioFormat::LittleEndian); - - typez.append(QAudioFormat::SignedInt); - typez.append(QAudioFormat::UnSignedInt); - - codecz.append(QLatin1String("audio/pcm")); - } - if (sampleRatez.count() > 0) - sampleRatez.prepend(8000); -} - -QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) -{ - Q_UNUSED(mode) - - QList<QByteArray> devices; - //enumerate device fullnames through directshow api - CoInitialize(NULL); - ICreateDevEnum *pDevEnum = NULL; - IEnumMoniker *pEnum = NULL; - // Create the System device enumerator - HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, - CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, - reinterpret_cast<void **>(&pDevEnum)); - - unsigned long iNumDevs = mode == QAudio::AudioOutput ? waveOutGetNumDevs() : waveInGetNumDevs(); - if (SUCCEEDED(hr)) { - // Create the enumerator for the audio input/output category - if (pDevEnum->CreateClassEnumerator( - mode == QAudio::AudioOutput ? CLSID_AudioRendererCategory : CLSID_AudioInputDeviceCategory, - &pEnum, 0) == S_OK) { - pEnum->Reset(); - // go through and find all audio devices - IMoniker *pMoniker = NULL; - while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { - IPropertyBag *pPropBag; - hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag, - reinterpret_cast<void **>(&pPropBag)); - if (FAILED(hr)) { - pMoniker->Release(); - continue; // skip this one - } - // Find if it is a wave device - VARIANT var; - VariantInit(&var); - hr = pPropBag->Read(mode == QAudio::AudioOutput ? L"WaveOutID" : L"WaveInID", &var, 0); - if (SUCCEEDED(hr)) { - LONG waveID = var.lVal; - if (waveID >= 0 && waveID < LONG(iNumDevs)) { - VariantClear(&var); - // Find the description - hr = pPropBag->Read(L"FriendlyName", &var, 0); - if (SUCCEEDED(hr)) { - QByteArray device; - QDataStream ds(&device, QIODevice::WriteOnly); - ds << quint32(waveID) << QString::fromWCharArray(var.bstrVal); - devices.append(device); - } - } - } - - pPropBag->Release(); - pMoniker->Release(); - } - } - } - CoUninitialize(); - - return devices; -} - -QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() -{ - QByteArray defaultDevice; - QDataStream ds(&defaultDevice, QIODevice::WriteOnly); - ds << quint32(WAVE_MAPPER) // device ID for default device - << QStringLiteral("Default Output Device"); - - return defaultDevice; -} - -QByteArray QAudioDeviceInfoInternal::defaultInputDevice() -{ - QByteArray defaultDevice; - QDataStream ds(&defaultDevice, QIODevice::WriteOnly); - ds << quint32(WAVE_MAPPER) // device ID for default device - << QStringLiteral("Default Input Device"); - - return defaultDevice; -} - -QT_END_NAMESPACE diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.h b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h deleted file mode 100644 index 6744518c3..000000000 --- a/src/multimedia/audio/qaudiodeviceinfo_win32_p.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#ifndef QAUDIODEVICEINFOWIN_H -#define QAUDIODEVICEINFOWIN_H - -#include <QtCore/qbytearray.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qlist.h> -#include <QtCore/qdebug.h> - -#include <qaudiodeviceinfo.h> -#include <qaudiosystem.h> - - -QT_BEGIN_NAMESPACE - - -const unsigned int MAX_SAMPLE_RATES = 5; -const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 }; - -class QAudioDeviceInfoInternal : public QAbstractAudioDeviceInfo -{ - Q_OBJECT - -public: - QAudioDeviceInfoInternal(QByteArray dev,QAudio::Mode mode); - ~QAudioDeviceInfoInternal(); - - bool open(); - void close(); - - bool testSettings(const QAudioFormat& format) const; - void updateLists(); - QAudioFormat preferredFormat() const; - bool isFormatSupported(const QAudioFormat& format) const; - QString deviceName() const; - QStringList supportedCodecs(); - QList<int> supportedSampleRates(); - QList<int> supportedChannelCounts(); - QList<int> supportedSampleSizes(); - QList<QAudioFormat::Endian> supportedByteOrders(); - QList<QAudioFormat::SampleType> supportedSampleTypes(); - static QByteArray defaultInputDevice(); - static QByteArray defaultOutputDevice(); - static QList<QByteArray> availableDevices(QAudio::Mode); - -private: - QAudio::Mode mode; - QString device; - quint32 devId; - QAudioFormat nearest; - QList<int> sampleRatez; - QList<int> channelz; - QList<int> sizez; - QList<QAudioFormat::Endian> byteOrderz; - QStringList codecz; - QList<QAudioFormat::SampleType> typez; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp deleted file mode 100644 index 41180309e..000000000 --- a/src/multimedia/audio/qaudioinput_alsa_p.cpp +++ /dev/null @@ -1,882 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - -#include <QtCore/qcoreapplication.h> -#include "qaudioinput_alsa_p.h" -#include "qaudiodeviceinfo_alsa_p.h" -#include "qaudiohelpers_p.h" - -QT_BEGIN_NAMESPACE - -//#define DEBUG_AUDIO 1 - -QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) -{ - bytesAvailable = 0; - handle = 0; - ahandler = 0; - access = SND_PCM_ACCESS_RW_INTERLEAVED; - pcmformat = SND_PCM_FORMAT_S16; - buffer_size = 0; - period_size = 0; - buffer_time = 100000; - period_time = 20000; - totalTimeValue = 0; - intervalTime = 1000; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - audioSource = 0; - pullMode = true; - resuming = false; - - m_volume = 1.0f; - - m_device = device; - - timer = new QTimer(this); - connect(timer,SIGNAL(timeout()),SLOT(userFeed())); -} - -QAudioInputPrivate::~QAudioInputPrivate() -{ - close(); - disconnect(timer, SIGNAL(timeout())); - QCoreApplication::processEvents(); - delete timer; -} - -void QAudioInputPrivate::setVolume(qreal vol) -{ - m_volume = vol; -} - -qreal QAudioInputPrivate::volume() const -{ - return m_volume; -} - -QAudio::Error QAudioInputPrivate::error() const -{ - return errorState; -} - -QAudio::State QAudioInputPrivate::state() const -{ - return deviceState; -} - -void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -QAudioFormat QAudioInputPrivate::format() const -{ - return settings; -} - -int QAudioInputPrivate::xrun_recovery(int err) -{ - int count = 0; - bool reset = false; - - if(err == -EPIPE) { - errorState = QAudio::UnderrunError; - err = snd_pcm_prepare(handle); - if(err < 0) - reset = true; - else { - bytesAvailable = checkBytesReady(); - if (bytesAvailable <= 0) - reset = true; - } - - } else if((err == -ESTRPIPE)||(err == -EIO)) { - errorState = QAudio::IOError; - while((err = snd_pcm_resume(handle)) == -EAGAIN){ - usleep(100); - count++; - if(count > 5) { - reset = true; - break; - } - } - if(err < 0) { - err = snd_pcm_prepare(handle); - if(err < 0) - reset = true; - } - } - if(reset) { - close(); - open(); - snd_pcm_prepare(handle); - return 0; - } - return err; -} - -int QAudioInputPrivate::setFormat() -{ - snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; - - if(settings.sampleSize() == 8) { - format = SND_PCM_FORMAT_U8; - } else if(settings.sampleSize() == 16) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_S16_LE; - else - format = SND_PCM_FORMAT_S16_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_U16_LE; - else - format = SND_PCM_FORMAT_U16_BE; - } - } else if(settings.sampleSize() == 24) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_S24_LE; - else - format = SND_PCM_FORMAT_S24_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_U24_LE; - else - format = SND_PCM_FORMAT_U24_BE; - } - } else if(settings.sampleSize() == 32) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_S32_LE; - else - format = SND_PCM_FORMAT_S32_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_U32_LE; - else - format = SND_PCM_FORMAT_U32_BE; - } else if(settings.sampleType() == QAudioFormat::Float) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_FLOAT_LE; - else - format = SND_PCM_FORMAT_FLOAT_BE; - } - } else if(settings.sampleSize() == 64) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - format = SND_PCM_FORMAT_FLOAT64_LE; - else - format = SND_PCM_FORMAT_FLOAT64_BE; - } - - return format != SND_PCM_FORMAT_UNKNOWN - ? snd_pcm_hw_params_set_format( handle, hwparams, format) - : -1; -} - -void QAudioInputPrivate::start(QIODevice* device) -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = true; - audioSource = device; - - deviceState = QAudio::ActiveState; - - if( !open() ) - return; - - emit stateChanged(deviceState); -} - -QIODevice* QAudioInputPrivate::start() -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = false; - audioSource = new InputPrivate(this); - audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); - - deviceState = QAudio::IdleState; - - if( !open() ) - return 0; - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAudioInputPrivate::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - - deviceState = QAudio::StoppedState; - - close(); - emit stateChanged(deviceState); -} - -bool QAudioInputPrivate::open() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; -#endif - clockStamp.restart(); - timeStamp.restart(); - elapsedTimeOffset = 0; - - int dir; - int err = 0; - int count=0; - unsigned int sampleRate=settings.sampleRate(); - - if (!settings.isValid()) { - qWarning("QAudioInput: open error, invalid format."); - } else if (settings.sampleRate() <= 0) { - qWarning("QAudioInput: open error, invalid sample rate (%d).", - settings.sampleRate()); - } else { - err = -1; - } - - if (err == 0) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit errorChanged(errorState); - return false; - } - - - QString dev = QString(QLatin1String(m_device.constData())); - QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput); - if(dev.compare(QLatin1String("default")) == 0) { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - if (devices.size() > 0) - dev = QLatin1String(devices.first()); - else - return false; -#else - dev = QLatin1String("hw:0,0"); -#endif - } else { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - dev = QLatin1String(m_device); -#else - int idx = 0; - char *name; - - QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); - - while(snd_card_get_name(idx,&name) == 0) { - if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) - break; - idx++; - } - dev = QString(QLatin1String("hw:%1,0")).arg(idx); -#endif - } - - // Step 1: try and open the device - while((count < 5) && (err < 0)) { - err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0); - if(err < 0) - count++; - } - if (( err < 0)||(handle == 0)) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - snd_pcm_nonblock( handle, 0 ); - - // Step 2: Set the desired HW parameters. - snd_pcm_hw_params_alloca( &hwparams ); - - bool fatal = false; - QString errMessage; - unsigned int chunks = 8; - - err = snd_pcm_hw_params_any( handle, hwparams ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_any: err = %1").arg(err); - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_access( handle, hwparams, access ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err); - } - } - if ( !fatal ) { - err = setFormat(); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_format: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channelCount() ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_channels: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &sampleRate, 0 ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params(handle, hwparams); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioInput: snd_pcm_hw_params: err = %1").arg(err); - } - } - if( err < 0) { - qWarning()<<errMessage; - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); - buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); - snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); - period_size = snd_pcm_frames_to_bytes(handle,period_frames); - snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); - snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); - - // Step 3: Set the desired SW parameters. - snd_pcm_sw_params_t *swparams; - snd_pcm_sw_params_alloca(&swparams); - snd_pcm_sw_params_current(handle, swparams); - snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); - snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); - snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); - snd_pcm_sw_params(handle, swparams); - - // Step 4: Prepare audio - ringBuffer.resize(buffer_size); - snd_pcm_prepare( handle ); - snd_pcm_start(handle); - - // Step 5: Setup timer - bytesAvailable = checkBytesReady(); - - if(pullMode) - connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed())); - - // Step 6: Start audio processing - chunks = buffer_size/period_size; - timer->start(period_time*chunks/2000); - - errorState = QAudio::NoError; - - totalTimeValue = 0; - - return true; -} - -void QAudioInputPrivate::close() -{ - timer->stop(); - - if ( handle ) { - snd_pcm_drop( handle ); - snd_pcm_close( handle ); - handle = 0; - } -} - -int QAudioInputPrivate::checkBytesReady() -{ - if(resuming) - bytesAvailable = period_size; - else if(deviceState != QAudio::ActiveState - && deviceState != QAudio::IdleState) - bytesAvailable = 0; - else { - int frames = snd_pcm_avail_update(handle); - if (frames < 0) { - bytesAvailable = frames; - } else { - if((int)frames > (int)buffer_frames) - frames = buffer_frames; - bytesAvailable = snd_pcm_frames_to_bytes(handle, frames); - } - } - return bytesAvailable; -} - -int QAudioInputPrivate::bytesReady() const -{ - return qMax(bytesAvailable, 0); -} - -qint64 QAudioInputPrivate::read(char* data, qint64 len) -{ - // Read in some audio data and write it to QIODevice, pull mode - if ( !handle ) - return 0; - - int bytesRead = 0; - int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer(); - - if (ringBuffer.bytesOfDataInBuffer() < len) { - - // bytesAvaiable is saved as a side effect of checkBytesReady(). - int bytesToRead = checkBytesReady(); - - if (bytesToRead < 0) { - // bytesAvailable as negative is error code, try to recover from it. - xrun_recovery(bytesToRead); - bytesToRead = checkBytesReady(); - if (bytesToRead < 0) { - // recovery failed must stop and set error. - close(); - errorState = QAudio::IOError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return 0; - } - } - - bytesToRead = qMin<qint64>(len, bytesToRead); - bytesToRead = qMin<qint64>(ringBuffer.freeBytes(), bytesToRead); - bytesToRead -= bytesToRead % period_size; - - int count=0; - int err = 0; - while(count < 5 && bytesToRead > 0) { - char buffer[bytesToRead]; - int chunks = bytesToRead / period_size; - int frames = chunks * period_frames; - if (frames > (int)buffer_frames) - frames = buffer_frames; - - int readFrames = snd_pcm_readi(handle, buffer, frames); - bytesRead = snd_pcm_frames_to_bytes(handle, readFrames); - if (m_volume < 1.0f) - QAudioHelperInternal::qMultiplySamples(m_volume, settings, buffer, buffer, bytesRead); - - if (readFrames >= 0) { - ringBuffer.write(buffer, bytesRead); -#ifdef DEBUG_AUDIO - qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData(); -#endif - break; - } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) { - errorState = QAudio::IOError; - err = 0; - break; - } else { - if(readFrames == -EPIPE) { - errorState = QAudio::UnderrunError; - err = snd_pcm_prepare(handle); - } else if(readFrames == -ESTRPIPE) { - err = snd_pcm_prepare(handle); - } - if(err != 0) break; - } - count++; - } - - } - - bytesRead += bytesInRingbufferBeforeRead; - - if (bytesRead > 0) { - // got some send it onward -#ifdef DEBUG_AUDIO - qDebug() << "frames to write to QIODevice = " << - snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes"; -#endif - if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) - return 0; - - if (pullMode) { - qint64 l = 0; - qint64 bytesWritten = 0; - while (ringBuffer.bytesOfDataInBuffer() > 0) { - l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize()); - if (l > 0) { - ringBuffer.readBytes(l); - bytesWritten += l; - } else { - break; - } - } - - if (l < 0) { - close(); - errorState = QAudio::IOError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - } else if (l == 0 && bytesWritten == 0) { - if (deviceState != QAudio::IdleState) { - errorState = QAudio::NoError; - deviceState = QAudio::IdleState; - emit stateChanged(deviceState); - } - } else { - bytesAvailable -= bytesWritten; - totalTimeValue += bytesWritten; - resuming = false; - if (deviceState != QAudio::ActiveState) { - errorState = QAudio::NoError; - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - } - - return bytesWritten; - } else { - while (ringBuffer.bytesOfDataInBuffer() > 0) { - int size = ringBuffer.availableDataBlockSize(); - memcpy(data, ringBuffer.availableData(), size); - data += size; - ringBuffer.readBytes(size); - } - - bytesAvailable -= bytesRead; - totalTimeValue += bytesRead; - resuming = false; - if (deviceState != QAudio::ActiveState) { - errorState = QAudio::NoError; - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - - return bytesRead; - } - } - - return 0; -} - -void QAudioInputPrivate::resume() -{ - if(deviceState == QAudio::SuspendedState) { - int err = 0; - - if(handle) { - err = snd_pcm_prepare( handle ); - if(err < 0) - xrun_recovery(err); - - err = snd_pcm_start(handle); - if(err < 0) - xrun_recovery(err); - - bytesAvailable = buffer_size; - } - resuming = true; - deviceState = QAudio::ActiveState; - int chunks = buffer_size/period_size; - timer->start(period_time*chunks/2000); - emit stateChanged(deviceState); - } -} - -void QAudioInputPrivate::setBufferSize(int value) -{ - buffer_size = value; -} - -int QAudioInputPrivate::bufferSize() const -{ - return buffer_size; -} - -int QAudioInputPrivate::periodSize() const -{ - return period_size; -} - -void QAudioInputPrivate::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAudioInputPrivate::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAudioInputPrivate::processedUSecs() const -{ - qint64 result = qint64(1000000) * totalTimeValue / - (settings.channelCount()*(settings.sampleSize()/8)) / - settings.sampleRate(); - - return result; -} - -void QAudioInputPrivate::suspend() -{ - if(deviceState == QAudio::ActiveState||resuming) { - timer->stop(); - deviceState = QAudio::SuspendedState; - emit stateChanged(deviceState); - } -} - -void QAudioInputPrivate::userFeed() -{ - if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) - return; -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() IN"; -#endif - deviceReady(); -} - -bool QAudioInputPrivate::deviceReady() -{ - if(pullMode) { - // reads some audio data and writes it to QIODevice - read(0, buffer_size); - } else { - // emits readyRead() so user will call read() on QIODevice to get some audio data - InputPrivate* a = qobject_cast<InputPrivate*>(audioSource); - a->trigger(); - } - bytesAvailable = checkBytesReady(); - - if(deviceState != QAudio::ActiveState) - return true; - - if (bytesAvailable < 0) { - // bytesAvailable as negative is error code, try to recover from it. - xrun_recovery(bytesAvailable); - bytesAvailable = checkBytesReady(); - if (bytesAvailable < 0) { - // recovery failed must stop and set error. - close(); - errorState = QAudio::IOError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return 0; - } - } - - if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { - emit notify(); - elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; - timeStamp.restart(); - } - return true; -} - -qint64 QAudioInputPrivate::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return clockStamp.elapsed()*1000; -} - -void QAudioInputPrivate::reset() -{ - if(handle) - snd_pcm_reset(handle); - stop(); - bytesAvailable = 0; -} - -void QAudioInputPrivate::drain() -{ - if(handle) - snd_pcm_drain(handle); -} - -InputPrivate::InputPrivate(QAudioInputPrivate* audio) -{ - audioDevice = qobject_cast<QAudioInputPrivate*>(audio); -} - -InputPrivate::~InputPrivate() -{ -} - -qint64 InputPrivate::readData( char* data, qint64 len) -{ - return audioDevice->read(data,len); -} - -qint64 InputPrivate::writeData(const char* data, qint64 len) -{ - Q_UNUSED(data) - Q_UNUSED(len) - return 0; -} - -void InputPrivate::trigger() -{ - emit readyRead(); -} - -RingBuffer::RingBuffer() : - m_head(0), - m_tail(0) -{ -} - -void RingBuffer::resize(int size) -{ - m_data.resize(size); -} - -int RingBuffer::bytesOfDataInBuffer() const -{ - if (m_head < m_tail) - return m_tail - m_head; - else if (m_tail < m_head) - return m_data.size() + m_tail - m_head; - else - return 0; -} - -int RingBuffer::freeBytes() const -{ - if (m_head > m_tail) - return m_head - m_tail - 1; - else if (m_tail > m_head) - return m_data.size() - m_tail + m_head - 1; - else - return m_data.size() - 1; -} - -const char *RingBuffer::availableData() const -{ - return (m_data.constData() + m_head); -} - -int RingBuffer::availableDataBlockSize() const -{ - if (m_head > m_tail) - return m_data.size() - m_head; - else if (m_tail > m_head) - return m_tail - m_head; - else - return 0; -} - -void RingBuffer::readBytes(int bytes) -{ - m_head = (m_head + bytes) % m_data.size(); -} - -void RingBuffer::write(char *data, int len) -{ - if (m_tail + len < m_data.size()) { - memcpy(m_data.data() + m_tail, data, len); - m_tail += len; - } else { - int bytesUntilEnd = m_data.size() - m_tail; - memcpy(m_data.data() + m_tail, data, bytesUntilEnd); - if (len - bytesUntilEnd > 0) - memcpy(m_data.data(), data + bytesUntilEnd, len - bytesUntilEnd); - m_tail = len - bytesUntilEnd; - } -} - -QT_END_NAMESPACE - -#include "moc_qaudioinput_alsa_p.cpp" diff --git a/src/multimedia/audio/qaudioinput_alsa_p.h b/src/multimedia/audio/qaudioinput_alsa_p.h deleted file mode 100644 index 0455ba903..000000000 --- a/src/multimedia/audio/qaudioinput_alsa_p.h +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#ifndef QAUDIOINPUTALSA_H -#define QAUDIOINPUTALSA_H - -#include <alsa/asoundlib.h> - -#include <QtCore/qfile.h> -#include <QtCore/qdebug.h> -#include <QtCore/qtimer.h> -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qdatetime.h> - -#include "qaudio.h" -#include "qaudiodeviceinfo.h" -#include "qaudiosystem.h" - -QT_BEGIN_NAMESPACE - - -class InputPrivate; - -class RingBuffer -{ -public: - RingBuffer(); - - void resize(int size); - - int bytesOfDataInBuffer() const; - int freeBytes() const; - - const char *availableData() const; - int availableDataBlockSize() const; - void readBytes(int bytes); - - void write(char *data, int len); - -private: - int m_head; - int m_tail; - - QByteArray m_data; -}; - -class QAudioInputPrivate : public QAbstractAudioInput -{ - Q_OBJECT -public: - QAudioInputPrivate(const QByteArray &device); - ~QAudioInputPrivate(); - - qint64 read(char* data, qint64 len); - - void start(QIODevice* device); - QIODevice* start(); - void stop(); - void reset(); - void suspend(); - void resume(); - int bytesReady() const; - int periodSize() const; - void setBufferSize(int value); - int bufferSize() const; - void setNotifyInterval(int milliSeconds); - int notifyInterval() const; - qint64 processedUSecs() const; - qint64 elapsedUSecs() const; - QAudio::Error error() const; - QAudio::State state() const; - void setFormat(const QAudioFormat& fmt); - QAudioFormat format() const; - void setVolume(qreal); - qreal volume() const; - bool resuming; - snd_pcm_t* handle; - qint64 totalTimeValue; - QIODevice* audioSource; - QAudioFormat settings; - QAudio::Error errorState; - QAudio::State deviceState; - -private slots: - void userFeed(); - bool deviceReady(); - -private: - int checkBytesReady(); - int xrun_recovery(int err); - int setFormat(); - bool open(); - void close(); - void drain(); - - QTimer* timer; - QTime timeStamp; - QTime clockStamp; - qint64 elapsedTimeOffset; - int intervalTime; - RingBuffer ringBuffer; - int bytesAvailable; - QByteArray m_device; - bool pullMode; - int buffer_size; - int period_size; - unsigned int buffer_time; - unsigned int period_time; - snd_pcm_uframes_t buffer_frames; - snd_pcm_uframes_t period_frames; - snd_async_handler_t* ahandler; - snd_pcm_access_t access; - snd_pcm_format_t pcmformat; - snd_timestamp_t* timestamp; - snd_pcm_hw_params_t *hwparams; - qreal m_volume; -}; - -class InputPrivate : public QIODevice -{ - Q_OBJECT -public: - InputPrivate(QAudioInputPrivate* audio); - ~InputPrivate(); - - qint64 readData( char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - - void trigger(); -private: - QAudioInputPrivate *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp deleted file mode 100644 index 47818f285..000000000 --- a/src/multimedia/audio/qaudioinput_win32_p.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - - -#include "qaudioinput_win32_p.h" - -QT_BEGIN_NAMESPACE - -//#define DEBUG_AUDIO 1 - -QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device) -{ - bytesAvailable = 0; - buffer_size = 0; - period_size = 0; - m_device = device; - totalTimeValue = 0; - intervalTime = 1000; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - audioSource = 0; - pullMode = true; - resuming = false; - finished = false; - waveBlockOffset = 0; - - mixerID = 0; - memset(&mixerLineControls, 0, sizeof(mixerLineControls)); - initMixer(); -} - -QAudioInputPrivate::~QAudioInputPrivate() -{ - stop(); - closeMixer(); -} - -void QT_WIN_CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg, - DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) -{ - Q_UNUSED(dwParam1) - Q_UNUSED(dwParam2) - Q_UNUSED(hWaveIn) - - QAudioInputPrivate* qAudio; - qAudio = (QAudioInputPrivate*)(dwInstance); - if(!qAudio) - return; - - QMutexLocker(&qAudio->mutex); - - switch(uMsg) { - case WIM_OPEN: - break; - case WIM_DATA: - if(qAudio->waveFreeBlockCount > 0) - qAudio->waveFreeBlockCount--; - qAudio->feedback(); - break; - case WIM_CLOSE: - qAudio->finished = true; - break; - default: - return; - } -} - -WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count) -{ - int i; - unsigned char* buffer; - WAVEHDR* blocks; - DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; - - if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - totalBufferSize)) == 0) { - qWarning("QAudioInput: Memory allocation error"); - return 0; - } - blocks = (WAVEHDR*)buffer; - buffer += sizeof(WAVEHDR)*count; - for(i = 0; i < count; i++) { - blocks[i].dwBufferLength = size; - blocks[i].lpData = (LPSTR)buffer; - blocks[i].dwBytesRecorded=0; - blocks[i].dwUser = 0L; - blocks[i].dwFlags = 0L; - blocks[i].dwLoops = 0L; - result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR)); - if(result != MMSYSERR_NOERROR) { - qWarning("QAudioInput: Can't prepare block %d",i); - return 0; - } - buffer += size; - } - return blocks; -} - -void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray) -{ - WAVEHDR* blocks = blockArray; - - int count = buffer_size/period_size; - - for(int i = 0; i < count; i++) { - waveInUnprepareHeader(hWaveIn,blocks, sizeof(WAVEHDR)); - blocks++; - } - HeapFree(GetProcessHeap(), 0, blockArray); -} - -QAudio::Error QAudioInputPrivate::error() const -{ - return errorState; -} - -QAudio::State QAudioInputPrivate::state() const -{ - return deviceState; -} - -#ifndef DRVM_MAPPER_CONSOLEVOICECOM_GET - #ifndef DRVM_MAPPER - #define DRVM_MAPPER 0x2000 - #endif - #ifndef DRVM_MAPPER_STATUS - #define DRVM_MAPPER_STATUS (DRVM_MAPPER+0) - #endif - #define DRVM_USER 0x4000 - #define DRVM_MAPPER_RECONFIGURE (DRVM_MAPPER+1) - #define DRVM_MAPPER_PREFERRED_GET (DRVM_MAPPER+21) - #define DRVM_MAPPER_CONSOLEVOICECOM_GET (DRVM_MAPPER+23) -#endif - -void QAudioInputPrivate::setVolume(qreal volume) -{ - for (DWORD i = 0; i < mixerLineControls.cControls; i++) { - - MIXERCONTROLDETAILS controlDetails; - controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); - controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID; - controlDetails.cChannels = 1; - - if ((mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_FADER) || - (mixerLineControls.pamxctrl[i].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)) { - MIXERCONTROLDETAILS_UNSIGNED controlDetailsUnsigned; - controlDetailsUnsigned.dwValue = qBound(DWORD(0), DWORD(65535.0 * volume + 0.5), DWORD(65535)); - controlDetails.cMultipleItems = 0; - controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); - controlDetails.paDetails = &controlDetailsUnsigned; - mixerSetControlDetails(mixerID, &controlDetails, MIXER_SETCONTROLDETAILSF_VALUE); - } - } -} - -qreal QAudioInputPrivate::volume() const -{ - DWORD volume = 0; - for (DWORD i = 0; i < mixerLineControls.cControls; i++) { - if ((mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_FADER) && - (mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_VOLUME)) { - continue; - } - - MIXERCONTROLDETAILS controlDetails; - controlDetails.cbStruct = sizeof(controlDetails); - controlDetails.dwControlID = mixerLineControls.pamxctrl[i].dwControlID; - controlDetails.cChannels = 1; - controlDetails.cMultipleItems = 0; - controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); - MIXERCONTROLDETAILS_UNSIGNED detailsUnsigned; - controlDetails.paDetails = &detailsUnsigned; - memset(controlDetails.paDetails, 0, controlDetails.cbDetails); - - MMRESULT result = mixerGetControlDetails(mixerID, &controlDetails, MIXER_GETCONTROLDETAILSF_VALUE); - if (result != MMSYSERR_NOERROR) - continue; - if (controlDetails.cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED)) - continue; - volume = detailsUnsigned.dwValue; - break; - } - - return volume / 65535.0; -} - -void QAudioInputPrivate::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -QAudioFormat QAudioInputPrivate::format() const -{ - return settings; -} - -void QAudioInputPrivate::start(QIODevice* device) -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = true; - audioSource = device; - - deviceState = QAudio::ActiveState; - - if(!open()) - return; - - emit stateChanged(deviceState); -} - -QIODevice* QAudioInputPrivate::start() -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = false; - audioSource = new InputPrivate(this); - audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); - - deviceState = QAudio::IdleState; - - if(!open()) - return 0; - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAudioInputPrivate::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - - close(); - emit stateChanged(deviceState); -} - -bool QAudioInputPrivate::open() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; -#endif - header = 0; - - period_size = 0; - - if (!settings.isValid()) { - qWarning("QAudioInput: open error, invalid format."); - } else if (settings.channelCount() <= 0) { - qWarning("QAudioInput: open error, invalid number of channels (%d).", - settings.channelCount()); - } else if (settings.sampleSize() <= 0) { - qWarning("QAudioInput: open error, invalid sample size (%d).", - settings.sampleSize()); - } else if (settings.sampleRate() < 8000 || settings.sampleRate() > 96000) { - qWarning("QAudioInput: open error, sample rate out of range (%d).", settings.sampleRate()); - } else if (buffer_size == 0) { - - buffer_size - = (settings.sampleRate() - * settings.channelCount() - * settings.sampleSize() - + 39) / 40; - period_size = buffer_size / 5; - } else { - period_size = buffer_size / 5; - } - - if (period_size == 0) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - - timeStamp.restart(); - elapsedTimeOffset = 0; - wfx.nSamplesPerSec = settings.sampleRate(); - wfx.wBitsPerSample = settings.sampleSize(); - wfx.nChannels = settings.channelCount(); - wfx.cbSize = 0; - - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; - wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; - - QDataStream ds(&m_device, QIODevice::ReadOnly); - quint32 deviceId; - ds >> deviceId; - - if (waveInOpen(&hWaveIn, UINT_PTR(deviceId), &wfx, - (DWORD_PTR)&waveInProc, - (DWORD_PTR) this, - CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - qWarning("QAudioInput: failed to open audio device"); - return false; - } - waveBlocks = allocateBlocks(period_size, buffer_size/period_size); - waveBlockOffset = 0; - - if(waveBlocks == 0) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - qWarning("QAudioInput: failed to allocate blocks. open failed"); - return false; - } - - mutex.lock(); - waveFreeBlockCount = buffer_size/period_size; - mutex.unlock(); - - for(int i=0; i<buffer_size/period_size; i++) { - result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR)); - if(result != MMSYSERR_NOERROR) { - qWarning("QAudioInput: failed to setup block %d,err=%d",i,result); - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - } - result = waveInStart(hWaveIn); - if(result) { - qWarning("QAudioInput: failed to start audio input"); - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - timeStampOpened.restart(); - elapsedTimeOffset = 0; - totalTimeValue = 0; - errorState = QAudio::NoError; - return true; -} - -void QAudioInputPrivate::close() -{ - if(deviceState == QAudio::StoppedState) - return; - - deviceState = QAudio::StoppedState; - waveInReset(hWaveIn); - - mutex.lock(); - for (int i=0; i<waveFreeBlockCount; i++) - waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR)); - freeBlocks(waveBlocks); - mutex.unlock(); - - waveInClose(hWaveIn); - - int count = 0; - while(!finished && count < 500) { - count++; - Sleep(10); - } -} - -void QAudioInputPrivate::initMixer() -{ - QDataStream ds(&m_device, QIODevice::ReadOnly); - quint32 inputDevice; - ds >> inputDevice; - - if (int(inputDevice) < 0) - return; - - // Get the Mixer ID from the Sound Device ID - UINT mixerIntID = 0; - if (mixerGetID((HMIXEROBJ)(quintptr(inputDevice)), &mixerIntID, MIXER_OBJECTF_WAVEIN) != MMSYSERR_NOERROR) - return; - mixerID = (HMIXEROBJ)mixerIntID; - - // Get the Destination (Recording) Line Infomation - MIXERLINE mixerLine; - mixerLine.cbStruct = sizeof(MIXERLINE); - mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; - if (mixerGetLineInfo(mixerID, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR) - return; - - // Set all the Destination (Recording) Line Controls - if (mixerLine.cControls > 0) { - mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS); - mixerLineControls.dwLineID = mixerLine.dwLineID; - mixerLineControls.cControls = mixerLine.cControls; - mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL); - mixerLineControls.pamxctrl = new MIXERCONTROL[mixerLineControls.cControls]; - if (mixerGetLineControls(mixerID, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL) != MMSYSERR_NOERROR) - closeMixer(); - } -} - -void QAudioInputPrivate::closeMixer() -{ - delete[] mixerLineControls.pamxctrl; - memset(&mixerLineControls, 0, sizeof(mixerLineControls)); -} - -int QAudioInputPrivate::bytesReady() const -{ - if(period_size == 0 || buffer_size == 0) - return 0; - - int buf = ((buffer_size/period_size)-waveFreeBlockCount)*period_size; - if(buf < 0) - buf = 0; - return buf; -} - -qint64 QAudioInputPrivate::read(char* data, qint64 len) -{ - bool done = false; - - char* p = data; - qint64 l = 0; - qint64 written = 0; - while(!done) { - // Read in some audio data - if(waveBlocks[header].dwBytesRecorded > 0 && waveBlocks[header].dwFlags & WHDR_DONE) { - if(pullMode) { - l = audioSource->write(waveBlocks[header].lpData + waveBlockOffset, - waveBlocks[header].dwBytesRecorded - waveBlockOffset); -#ifdef DEBUG_AUDIO - qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l; -#endif - if(l < 0) { - // error - qWarning("QAudioInput: IOError"); - errorState = QAudio::IOError; - - } else if(l == 0) { - // cant write to IODevice - qWarning("QAudioInput: IOError, can't write to QIODevice"); - errorState = QAudio::IOError; - - } else { - totalTimeValue += l; - errorState = QAudio::NoError; - if (deviceState != QAudio::ActiveState) { - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - resuming = false; - } - } else { - l = qMin<qint64>(len, waveBlocks[header].dwBytesRecorded - waveBlockOffset); - // push mode - memcpy(p, waveBlocks[header].lpData + waveBlockOffset, l); - - len -= l; - -#ifdef DEBUG_AUDIO - qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l; -#endif - totalTimeValue += l; - errorState = QAudio::NoError; - if (deviceState != QAudio::ActiveState) { - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - resuming = false; - } - } else { - //no data, not ready yet, next time - break; - } - - if (l < waveBlocks[header].dwBytesRecorded - waveBlockOffset) { - waveBlockOffset += l; - done = true; - } else { - waveBlockOffset = 0; - - waveInUnprepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); - - mutex.lock(); - waveFreeBlockCount++; - mutex.unlock(); - - waveBlocks[header].dwBytesRecorded=0; - waveBlocks[header].dwFlags = 0L; - result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); - if(result != MMSYSERR_NOERROR) { - result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR)); - qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result); - errorState = QAudio::IOError; - - mutex.lock(); - waveFreeBlockCount--; - mutex.unlock(); - - return 0; - } - result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR)); - if(result != MMSYSERR_NOERROR) { - qWarning("QAudioInput: failed to setup block %d,err=%d",header,result); - errorState = QAudio::IOError; - - mutex.lock(); - waveFreeBlockCount--; - mutex.unlock(); - - return 0; - } - header++; - if(header >= buffer_size/period_size) - header = 0; - p+=l; - - mutex.lock(); - if(!pullMode) { - if(len < period_size || waveFreeBlockCount == buffer_size/period_size) - done = true; - } else { - if(waveFreeBlockCount == buffer_size/period_size) - done = true; - } - mutex.unlock(); - } - - written+=l; - } -#ifdef DEBUG_AUDIO - qDebug()<<"read in len="<<written; -#endif - return written; -} - -void QAudioInputPrivate::resume() -{ - if(deviceState == QAudio::SuspendedState) { - deviceState = QAudio::ActiveState; - for(int i=0; i<buffer_size/period_size; i++) { - result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR)); - if(result != MMSYSERR_NOERROR) { - qWarning("QAudioInput: failed to setup block %d,err=%d",i,result); - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return; - } - } - - mutex.lock(); - waveFreeBlockCount = buffer_size/period_size; - mutex.unlock(); - - header = 0; - resuming = true; - waveBlockOffset = 0; - waveInStart(hWaveIn); - QTimer::singleShot(20,this,SLOT(feedback())); - emit stateChanged(deviceState); - } -} - -void QAudioInputPrivate::setBufferSize(int value) -{ - buffer_size = value; -} - -int QAudioInputPrivate::bufferSize() const -{ - return buffer_size; -} - -int QAudioInputPrivate::periodSize() const -{ - return period_size; -} - -void QAudioInputPrivate::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAudioInputPrivate::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAudioInputPrivate::processedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - qint64 result = qint64(1000000) * totalTimeValue / - (settings.channelCount()*(settings.sampleSize()/8)) / - settings.sampleRate(); - - return result; -} - -void QAudioInputPrivate::suspend() -{ - if(deviceState == QAudio::ActiveState) { - waveInReset(hWaveIn); - deviceState = QAudio::SuspendedState; - emit stateChanged(deviceState); - } -} - -void QAudioInputPrivate::feedback() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT "<<this; -#endif - if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState)) - QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); -} - -bool QAudioInputPrivate::deviceReady() -{ - bytesAvailable = bytesReady(); -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT"; -#endif - if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) - return true; - - if(pullMode) { - // reads some audio data and writes it to QIODevice - read(0, buffer_size); - } else { - // emits readyRead() so user will call read() on QIODevice to get some audio data - InputPrivate* a = qobject_cast<InputPrivate*>(audioSource); - a->trigger(); - } - - if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { - emit notify(); - elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; - timeStamp.restart(); - } - return true; -} - -qint64 QAudioInputPrivate::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return timeStampOpened.elapsed()*1000; -} - -void QAudioInputPrivate::reset() -{ - stop(); - if (period_size > 0) - waveFreeBlockCount = buffer_size / period_size; -} - -InputPrivate::InputPrivate(QAudioInputPrivate* audio) -{ - audioDevice = qobject_cast<QAudioInputPrivate*>(audio); -} - -InputPrivate::~InputPrivate() {} - -qint64 InputPrivate::readData( char* data, qint64 len) -{ - // push mode, user read() called - if(audioDevice->deviceState != QAudio::ActiveState && - audioDevice->deviceState != QAudio::IdleState) - return 0; - // Read in some audio data - return audioDevice->read(data,len); -} - -qint64 InputPrivate::writeData(const char* data, qint64 len) -{ - Q_UNUSED(data) - Q_UNUSED(len) - - emit readyRead(); - return 0; -} - -void InputPrivate::trigger() -{ - emit readyRead(); -} - -QT_END_NAMESPACE - -#include "moc_qaudioinput_win32_p.cpp" - diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h deleted file mode 100644 index a51d1bbe7..000000000 --- a/src/multimedia/audio/qaudioinput_win32_p.h +++ /dev/null @@ -1,180 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QAUDIOINPUTWIN_H -#define QAUDIOINPUTWIN_H - -#include <QtCore/qt_windows.h> -#include <mmsystem.h> - -#include <QtCore/qfile.h> -#include <QtCore/qdebug.h> -#include <QtCore/qtimer.h> -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qmutex.h> - -#include <qaudio.h> -#include <qaudiodeviceinfo.h> -#include <qaudiosystem.h> - - -QT_BEGIN_NAMESPACE - - -// For compat with 4.6 -#if !defined(QT_WIN_CALLBACK) -# if defined(Q_CC_MINGW) -# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) -# else -# define QT_WIN_CALLBACK CALLBACK -# endif -#endif - -class QAudioInputPrivate : public QAbstractAudioInput -{ - Q_OBJECT -public: - QAudioInputPrivate(const QByteArray &device); - ~QAudioInputPrivate(); - - qint64 read(char* data, qint64 len); - - void setFormat(const QAudioFormat& fmt); - QAudioFormat format() const; - QIODevice* start(); - void start(QIODevice* device); - void stop(); - void reset(); - void suspend(); - void resume(); - int bytesReady() const; - int periodSize() const; - void setBufferSize(int value); - int bufferSize() const; - void setNotifyInterval(int milliSeconds); - int notifyInterval() const; - qint64 processedUSecs() const; - qint64 elapsedUSecs() const; - QAudio::Error error() const; - QAudio::State state() const; - void setVolume(qreal volume); - qreal volume() const; - - QIODevice* audioSource; - QAudioFormat settings; - QAudio::Error errorState; - QAudio::State deviceState; - -private: - qint32 buffer_size; - qint32 period_size; - qint32 header; - QByteArray m_device; - int bytesAvailable; - int intervalTime; - QTime timeStamp; - qint64 elapsedTimeOffset; - QTime timeStampOpened; - qint64 totalTimeValue; - bool pullMode; - bool resuming; - WAVEFORMATEX wfx; - HWAVEIN hWaveIn; - MMRESULT result; - WAVEHDR* waveBlocks; - volatile bool finished; - volatile int waveFreeBlockCount; - int waveBlockOffset; - - QMutex mutex; - static void QT_WIN_CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg, - DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ); - - WAVEHDR* allocateBlocks(int size, int count); - void freeBlocks(WAVEHDR* blockArray); - bool open(); - void close(); - - void initMixer(); - void closeMixer(); - HMIXEROBJ mixerID; - MIXERLINECONTROLS mixerLineControls; - -private slots: - void feedback(); - bool deviceReady(); - -signals: - void processMore(); -}; - -class InputPrivate : public QIODevice -{ - Q_OBJECT -public: - InputPrivate(QAudioInputPrivate* audio); - ~InputPrivate(); - - qint64 readData( char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - - void trigger(); -private: - QAudioInputPrivate *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp deleted file mode 100644 index c1eeaec4f..000000000 --- a/src/multimedia/audio/qaudiooutput_alsa_p.cpp +++ /dev/null @@ -1,860 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - -#include <QtCore/qcoreapplication.h> -#include "qaudiooutput_alsa_p.h" -#include "qaudiodeviceinfo_alsa_p.h" -#include "qaudiohelpers_p.h" - -QT_BEGIN_NAMESPACE - -//#define DEBUG_AUDIO 1 - -QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) -{ - bytesAvailable = 0; - handle = 0; - ahandler = 0; - access = SND_PCM_ACCESS_RW_INTERLEAVED; - pcmformat = SND_PCM_FORMAT_S16; - buffer_frames = 0; - period_frames = 0; - buffer_size = 0; - period_size = 0; - buffer_time = 100000; - period_time = 20000; - totalTimeValue = 0; - intervalTime = 1000; - audioBuffer = 0; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - audioSource = 0; - pullMode = true; - resuming = false; - opened = false; - - m_volume = 1.0f; - - m_device = device; - - timer = new QTimer(this); - connect(timer,SIGNAL(timeout()),SLOT(userFeed())); -} - -QAudioOutputPrivate::~QAudioOutputPrivate() -{ - close(); - disconnect(timer, SIGNAL(timeout())); - QCoreApplication::processEvents(); - delete timer; -} - -void QAudioOutputPrivate::setVolume(qreal vol) -{ - m_volume = vol; -} - -qreal QAudioOutputPrivate::volume() const -{ - return m_volume; -} - -QAudio::Error QAudioOutputPrivate::error() const -{ - return errorState; -} - -QAudio::State QAudioOutputPrivate::state() const -{ - return deviceState; -} - -void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler) -{ - QAudioOutputPrivate* audioOut; - - audioOut = static_cast<QAudioOutputPrivate*> - (snd_async_handler_get_callback_private(ahandler)); - - if (audioOut && (audioOut->deviceState == QAudio::ActiveState || audioOut->resuming)) - audioOut->feedback(); -} - -int QAudioOutputPrivate::xrun_recovery(int err) -{ - int count = 0; - bool reset = false; - - if(err == -EPIPE) { - errorState = QAudio::UnderrunError; - emit errorChanged(errorState); - err = snd_pcm_prepare(handle); - if(err < 0) - reset = true; - - } else if((err == -ESTRPIPE)||(err == -EIO)) { - errorState = QAudio::IOError; - emit errorChanged(errorState); - while((err = snd_pcm_resume(handle)) == -EAGAIN){ - usleep(100); - count++; - if(count > 5) { - reset = true; - break; - } - } - if(err < 0) { - err = snd_pcm_prepare(handle); - if(err < 0) - reset = true; - } - } - if(reset) { - close(); - open(); - snd_pcm_prepare(handle); - return 0; - } - return err; -} - -int QAudioOutputPrivate::setFormat() -{ - snd_pcm_format_t pcmformat = SND_PCM_FORMAT_UNKNOWN; - - if(settings.sampleSize() == 8) { - pcmformat = SND_PCM_FORMAT_U8; - - } else if(settings.sampleSize() == 16) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_S16_LE; - else - pcmformat = SND_PCM_FORMAT_S16_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_U16_LE; - else - pcmformat = SND_PCM_FORMAT_U16_BE; - } - } else if(settings.sampleSize() == 24) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_S24_LE; - else - pcmformat = SND_PCM_FORMAT_S24_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_U24_LE; - else - pcmformat = SND_PCM_FORMAT_U24_BE; - } - } else if(settings.sampleSize() == 32) { - if(settings.sampleType() == QAudioFormat::SignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_S32_LE; - else - pcmformat = SND_PCM_FORMAT_S32_BE; - } else if(settings.sampleType() == QAudioFormat::UnSignedInt) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_U32_LE; - else - pcmformat = SND_PCM_FORMAT_U32_BE; - } else if(settings.sampleType() == QAudioFormat::Float) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_FLOAT_LE; - else - pcmformat = SND_PCM_FORMAT_FLOAT_BE; - } - } else if(settings.sampleSize() == 64) { - if(settings.byteOrder() == QAudioFormat::LittleEndian) - pcmformat = SND_PCM_FORMAT_FLOAT64_LE; - else - pcmformat = SND_PCM_FORMAT_FLOAT64_BE; - } - - return pcmformat != SND_PCM_FORMAT_UNKNOWN - ? snd_pcm_hw_params_set_format( handle, hwparams, pcmformat) - : -1; -} - -void QAudioOutputPrivate::start(QIODevice* device) -{ - if(deviceState != QAudio::StoppedState) - deviceState = QAudio::StoppedState; - - errorState = QAudio::NoError; - - // Handle change of mode - if(audioSource && !pullMode) { - delete audioSource; - audioSource = 0; - } - - close(); - - pullMode = true; - audioSource = device; - - deviceState = QAudio::ActiveState; - - open(); - - emit stateChanged(deviceState); -} - -QIODevice* QAudioOutputPrivate::start() -{ - if(deviceState != QAudio::StoppedState) - deviceState = QAudio::StoppedState; - - errorState = QAudio::NoError; - - // Handle change of mode - if(audioSource && !pullMode) { - delete audioSource; - audioSource = 0; - } - - close(); - - audioSource = new OutputPrivate(this); - audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); - pullMode = false; - - deviceState = QAudio::IdleState; - - open(); - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAudioOutputPrivate::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - close(); - emit stateChanged(deviceState); -} - -bool QAudioOutputPrivate::open() -{ - if(opened) - return true; - -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; -#endif - timeStamp.restart(); - elapsedTimeOffset = 0; - - int dir; - int err = 0; - int count=0; - unsigned int sampleRate=settings.sampleRate(); - - if (!settings.isValid()) { - qWarning("QAudioOutput: open error, invalid format."); - } else if (settings.sampleRate() <= 0) { - qWarning("QAudioOutput: open error, invalid sample rate (%d).", - settings.sampleRate()); - } else { - err = -1; - } - - if (err == 0) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit errorChanged(errorState); - return false; - } - - QString dev = QString(QLatin1String(m_device.constData())); - QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput); - if(dev.compare(QLatin1String("default")) == 0) { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - if (devices.size() > 0) - dev = QLatin1String(devices.first()); - else - return false; -#else - dev = QLatin1String("hw:0,0"); -#endif - } else { -#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) - dev = QLatin1String(m_device); -#else - int idx = 0; - char *name; - - QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData()); - - while (snd_card_get_name(idx,&name) == 0) { - if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0) - break; - idx++; - } - dev = QString(QLatin1String("hw:%1,0")).arg(idx); -#endif - } - - // Step 1: try and open the device - while((count < 5) && (err < 0)) { - err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0); - if(err < 0) - count++; - } - if (( err < 0)||(handle == 0)) { - errorState = QAudio::OpenError; - emit errorChanged(errorState); - deviceState = QAudio::StoppedState; - return false; - } - snd_pcm_nonblock( handle, 0 ); - - // Step 2: Set the desired HW parameters. - snd_pcm_hw_params_alloca( &hwparams ); - - bool fatal = false; - QString errMessage; - unsigned int chunks = 8; - - err = snd_pcm_hw_params_any( handle, hwparams ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err); - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_access( handle, hwparams, access ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err); - } - } - if ( !fatal ) { - err = setFormat(); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channelCount() ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &sampleRate, 0 ); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err); - } - } - if ( !fatal ) { - unsigned int maxBufferTime = 0; - unsigned int minBufferTime = 0; - unsigned int maxPeriodTime = 0; - unsigned int minPeriodTime = 0; - - err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir); - if ( err >= 0) - err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir); - if ( err >= 0) - err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir); - if ( err >= 0) - err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir); - - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); - } else { - if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { -#ifdef DEBUG_AUDIO - qDebug()<<"defaults out of range"; - qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; -#endif - period_time = minPeriodTime; - if (period_time*4 <= maxBufferTime) { - // Use 4 periods if possible - buffer_time = period_time*4; - chunks = 4; - } else if (period_time*2 <= maxBufferTime) { - // Use 2 periods if possible - buffer_time = period_time*2; - chunks = 2; - } else { - qWarning()<<"QAudioOutput: alsa only supports single period!"; - fatal = true; - } -#ifdef DEBUG_AUDIO - qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; -#endif - } - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err); - } - } - if ( !fatal ) { - err = snd_pcm_hw_params(handle, hwparams); - if ( err < 0 ) { - fatal = true; - errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err); - } - } - if( err < 0) { - qWarning()<<errMessage; - errorState = QAudio::OpenError; - emit errorChanged(errorState); - deviceState = QAudio::StoppedState; - return false; - } - snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames); - buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames); - snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir); - period_size = snd_pcm_frames_to_bytes(handle,period_frames); - snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir); - snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir); - - // Step 3: Set the desired SW parameters. - snd_pcm_sw_params_t *swparams; - snd_pcm_sw_params_alloca(&swparams); - snd_pcm_sw_params_current(handle, swparams); - snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames); - snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames); - snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames); - snd_pcm_sw_params(handle, swparams); - - // Step 4: Prepare audio - if(audioBuffer == 0) - audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)]; - snd_pcm_prepare( handle ); - snd_pcm_start(handle); - - // Step 5: Setup callback and timer fallback - snd_async_add_pcm_handler(&ahandler, handle, async_callback, this); - bytesAvailable = bytesFree(); - - // Step 6: Start audio processing - timer->start(period_time/1000); - - clockStamp.restart(); - timeStamp.restart(); - elapsedTimeOffset = 0; - errorState = QAudio::NoError; - totalTimeValue = 0; - opened = true; - - return true; -} - -void QAudioOutputPrivate::close() -{ - timer->stop(); - - if ( handle ) { - snd_pcm_drain( handle ); - snd_pcm_close( handle ); - handle = 0; - delete [] audioBuffer; - audioBuffer=0; - } - if(!pullMode && audioSource) { - delete audioSource; - audioSource = 0; - } - opened = false; -} - -int QAudioOutputPrivate::bytesFree() const -{ - if(resuming) - return period_size; - - if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) - return 0; - - int frames = snd_pcm_avail_update(handle); - if (frames == -EPIPE) { - // Try and handle buffer underrun - int err = snd_pcm_recover(handle, frames, 0); - if (err < 0) - return 0; - else - frames = snd_pcm_avail_update(handle); - } else if (frames < 0) { - return 0; - } - - if ((int)frames > (int)buffer_frames) - frames = buffer_frames; - - return snd_pcm_frames_to_bytes(handle, frames); -} - -qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) -{ - // Write out some audio data - if ( !handle ) - return 0; -#ifdef DEBUG_AUDIO - qDebug()<<"frames to write out = "<< - snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes"; -#endif - int frames, err; - int space = bytesFree(); - - if (!space) - return 0; - - if (len < space) - space = len; - - frames = snd_pcm_bytes_to_frames(handle, space); - - if (m_volume < 1.0f) { - char out[space]; - QAudioHelperInternal::qMultiplySamples(m_volume, settings, data, out, space); - err = snd_pcm_writei(handle, out, frames); - } else { - err = snd_pcm_writei(handle, data, frames); - } - - if(err > 0) { - totalTimeValue += err; - resuming = false; - errorState = QAudio::NoError; - if (deviceState != QAudio::ActiveState) { - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - return snd_pcm_frames_to_bytes( handle, err ); - } else - err = xrun_recovery(err); - - if(err < 0) { - close(); - errorState = QAudio::FatalError; - emit errorChanged(errorState); - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - } - return 0; -} - -int QAudioOutputPrivate::periodSize() const -{ - return period_size; -} - -void QAudioOutputPrivate::setBufferSize(int value) -{ - if(deviceState == QAudio::StoppedState) - buffer_size = value; -} - -int QAudioOutputPrivate::bufferSize() const -{ - return buffer_size; -} - -void QAudioOutputPrivate::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAudioOutputPrivate::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAudioOutputPrivate::processedUSecs() const -{ - return qint64(1000000) * totalTimeValue / settings.sampleRate(); -} - -void QAudioOutputPrivate::resume() -{ - if(deviceState == QAudio::SuspendedState) { - int err = 0; - - if(handle) { - err = snd_pcm_prepare( handle ); - if(err < 0) - xrun_recovery(err); - - err = snd_pcm_start(handle); - if(err < 0) - xrun_recovery(err); - - bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames); - } - resuming = true; - - deviceState = QAudio::ActiveState; - - errorState = QAudio::NoError; - timer->start(period_time/1000); - emit stateChanged(deviceState); - } -} - -void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -QAudioFormat QAudioOutputPrivate::format() const -{ - return settings; -} - -void QAudioOutputPrivate::suspend() -{ - if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { - timer->stop(); - deviceState = QAudio::SuspendedState; - errorState = QAudio::NoError; - emit stateChanged(deviceState); - } -} - -void QAudioOutputPrivate::userFeed() -{ - if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) - return; -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT"; -#endif - if(deviceState == QAudio::IdleState) - bytesAvailable = bytesFree(); - - deviceReady(); -} - -void QAudioOutputPrivate::feedback() -{ - updateAvailable(); -} - - -void QAudioOutputPrivate::updateAvailable() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()"; -#endif - bytesAvailable = bytesFree(); -} - -bool QAudioOutputPrivate::deviceReady() -{ - if(pullMode) { - int l = 0; - int chunks = bytesAvailable/period_size; - if(chunks==0) { - bytesAvailable = bytesFree(); - return false; - } -#ifdef DEBUG_AUDIO - qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes"; - qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks; -#endif - int input = period_frames*chunks; - if(input > (int)buffer_frames) - input = buffer_frames; - l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input)); - - // reading can take a while and stream may have been stopped - if (!handle) - return false; - - if(l > 0) { - // Got some data to output - if(deviceState != QAudio::ActiveState) - return true; - qint64 bytesWritten = write(audioBuffer,l); - if (bytesWritten != l) - audioSource->seek(audioSource->pos()-(l-bytesWritten)); - bytesAvailable = bytesFree(); - - } else if(l == 0) { - // Did not get any data to output - bytesAvailable = bytesFree(); - if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { - // Underrun - if (deviceState != QAudio::IdleState) { - errorState = QAudio::UnderrunError; - emit errorChanged(errorState); - deviceState = QAudio::IdleState; - emit stateChanged(deviceState); - } - } - - } else if(l < 0) { - close(); - deviceState = QAudio::StoppedState; - errorState = QAudio::IOError; - emit errorChanged(errorState); - emit stateChanged(deviceState); - } - } else { - bytesAvailable = bytesFree(); - if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) { - // Underrun - if (deviceState != QAudio::IdleState) { - errorState = QAudio::UnderrunError; - emit errorChanged(errorState); - deviceState = QAudio::IdleState; - emit stateChanged(deviceState); - } - } - } - - if(deviceState != QAudio::ActiveState) - return true; - - if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { - emit notify(); - elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; - timeStamp.restart(); - } - return true; -} - -qint64 QAudioOutputPrivate::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return clockStamp.elapsed()*1000; -} - -void QAudioOutputPrivate::reset() -{ - if(handle) - snd_pcm_reset(handle); - - stop(); -} - -OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio) -{ - audioDevice = qobject_cast<QAudioOutputPrivate*>(audio); -} - -OutputPrivate::~OutputPrivate() {} - -qint64 OutputPrivate::readData( char* data, qint64 len) -{ - Q_UNUSED(data) - Q_UNUSED(len) - - return 0; -} - -qint64 OutputPrivate::writeData(const char* data, qint64 len) -{ - int retry = 0; - qint64 written = 0; - if((audioDevice->deviceState == QAudio::ActiveState) - ||(audioDevice->deviceState == QAudio::IdleState)) { - while(written < len) { - int chunk = audioDevice->write(data+written,(len-written)); - if(chunk <= 0) - retry++; - written+=chunk; - if(retry > 10) - return written; - } - } - return written; - -} - -QT_END_NAMESPACE - -#include "moc_qaudiooutput_alsa_p.cpp" diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.h b/src/multimedia/audio/qaudiooutput_alsa_p.h deleted file mode 100644 index 3bcb94ffc..000000000 --- a/src/multimedia/audio/qaudiooutput_alsa_p.h +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QAUDIOOUTPUTALSA_H -#define QAUDIOOUTPUTALSA_H - -#include <alsa/asoundlib.h> - -#include <QtCore/qfile.h> -#include <QtCore/qdebug.h> -#include <QtCore/qtimer.h> -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qdatetime.h> - -#include "qaudio.h" -#include "qaudiodeviceinfo.h" -#include "qaudiosystem.h" - -QT_BEGIN_NAMESPACE - - -class OutputPrivate; - -class QAudioOutputPrivate : public QAbstractAudioOutput -{ - friend class OutputPrivate; - Q_OBJECT -public: - QAudioOutputPrivate(const QByteArray &device); - ~QAudioOutputPrivate(); - - qint64 write( const char *data, qint64 len ); - - void start(QIODevice* device); - QIODevice* start(); - void stop(); - void reset(); - void suspend(); - void resume(); - int bytesFree() const; - int periodSize() const; - void setBufferSize(int value); - int bufferSize() const; - void setNotifyInterval(int milliSeconds); - int notifyInterval() const; - qint64 processedUSecs() const; - qint64 elapsedUSecs() const; - QAudio::Error error() const; - QAudio::State state() const; - void setFormat(const QAudioFormat& fmt); - QAudioFormat format() const; - void setVolume(qreal); - qreal volume() const; - - - QIODevice* audioSource; - QAudioFormat settings; - QAudio::Error errorState; - QAudio::State deviceState; - -private slots: - void userFeed(); - void feedback(); - void updateAvailable(); - bool deviceReady(); - -signals: - void processMore(); - -private: - bool opened; - bool pullMode; - bool resuming; - int buffer_size; - int period_size; - int intervalTime; - qint64 totalTimeValue; - unsigned int buffer_time; - unsigned int period_time; - snd_pcm_uframes_t buffer_frames; - snd_pcm_uframes_t period_frames; - static void async_callback(snd_async_handler_t *ahandler); - int xrun_recovery(int err); - - int setFormat(); - bool open(); - void close(); - - QTimer* timer; - QByteArray m_device; - int bytesAvailable; - QTime timeStamp; - QTime clockStamp; - qint64 elapsedTimeOffset; - char* audioBuffer; - snd_pcm_t* handle; - snd_async_handler_t* ahandler; - snd_pcm_access_t access; - snd_pcm_format_t pcmformat; - snd_timestamp_t* timestamp; - snd_pcm_hw_params_t *hwparams; - qreal m_volume; -}; - -class OutputPrivate : public QIODevice -{ - friend class QAudioOutputPrivate; - Q_OBJECT -public: - OutputPrivate(QAudioOutputPrivate* audio); - ~OutputPrivate(); - - qint64 readData( char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - -private: - QAudioOutputPrivate *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp deleted file mode 100644 index dbc46fb80..000000000 --- a/src/multimedia/audio/qaudiooutput_win32_p.cpp +++ /dev/null @@ -1,762 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// INTERNAL USE ONLY: Do NOT use for any other purpose. -// - -#include "qaudiooutput_win32_p.h" -#include <QtEndian> - -#ifndef SPEAKER_FRONT_LEFT - #define SPEAKER_FRONT_LEFT 0x00000001 - #define SPEAKER_FRONT_RIGHT 0x00000002 - #define SPEAKER_FRONT_CENTER 0x00000004 - #define SPEAKER_LOW_FREQUENCY 0x00000008 - #define SPEAKER_BACK_LEFT 0x00000010 - #define SPEAKER_BACK_RIGHT 0x00000020 - #define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040 - #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080 - #define SPEAKER_BACK_CENTER 0x00000100 - #define SPEAKER_SIDE_LEFT 0x00000200 - #define SPEAKER_SIDE_RIGHT 0x00000400 - #define SPEAKER_TOP_CENTER 0x00000800 - #define SPEAKER_TOP_FRONT_LEFT 0x00001000 - #define SPEAKER_TOP_FRONT_CENTER 0x00002000 - #define SPEAKER_TOP_FRONT_RIGHT 0x00004000 - #define SPEAKER_TOP_BACK_LEFT 0x00008000 - #define SPEAKER_TOP_BACK_CENTER 0x00010000 - #define SPEAKER_TOP_BACK_RIGHT 0x00020000 - #define SPEAKER_RESERVED 0x7FFC0000 - #define SPEAKER_ALL 0x80000000 -#endif - -#ifndef _WAVEFORMATEXTENSIBLE_ - - #define _WAVEFORMATEXTENSIBLE_ - typedef struct - { - WAVEFORMATEX Format; // Base WAVEFORMATEX data - union - { - WORD wValidBitsPerSample; // Valid bits in each sample container - WORD wSamplesPerBlock; // Samples per block of audio data; valid - // if wBitsPerSample=0 (but rarely used). - WORD wReserved; // Zero if neither case above applies. - } Samples; - DWORD dwChannelMask; // Positions of the audio channels - GUID SubFormat; // Format identifier GUID - } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPPWAVEFORMATEXTENSIBLE; - typedef const WAVEFORMATEXTENSIBLE* LPCWAVEFORMATEXTENSIBLE; - -#endif - -#if !defined(WAVE_FORMAT_EXTENSIBLE) -#define WAVE_FORMAT_EXTENSIBLE 0xFFFE -#endif - -//#define DEBUG_AUDIO 1 - -QT_BEGIN_NAMESPACE - -QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) -{ - bytesAvailable = 0; - buffer_size = 0; - period_size = 0; - m_device = device; - totalTimeValue = 0; - intervalTime = 1000; - audioBuffer = 0; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - audioSource = 0; - pullMode = true; - finished = false; - volumeCache = (qreal)1.; -} - -QAudioOutputPrivate::~QAudioOutputPrivate() -{ - mutex.lock(); - finished = true; - mutex.unlock(); - - close(); -} - -void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, - DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ) -{ - Q_UNUSED(dwParam1) - Q_UNUSED(dwParam2) - Q_UNUSED(hWaveOut) - - QAudioOutputPrivate* qAudio; - qAudio = (QAudioOutputPrivate*)(dwInstance); - if(!qAudio) - return; - - QMutexLocker(&qAudio->mutex); - - switch(uMsg) { - case WOM_OPEN: - qAudio->feedback(); - break; - case WOM_CLOSE: - return; - case WOM_DONE: - if(qAudio->finished || qAudio->buffer_size == 0 || qAudio->period_size == 0) { - return; - } - qAudio->waveFreeBlockCount++; - if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size) - qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size; - qAudio->feedback(); - break; - default: - return; - } -} - -WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count) -{ - int i; - unsigned char* buffer; - WAVEHDR* blocks; - DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count; - - if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - totalBufferSize)) == 0) { - qWarning("QAudioOutput: Memory allocation error"); - return 0; - } - blocks = (WAVEHDR*)buffer; - buffer += sizeof(WAVEHDR)*count; - for(i = 0; i < count; i++) { - blocks[i].dwBufferLength = size; - blocks[i].lpData = (LPSTR)buffer; - buffer += size; - } - return blocks; -} - -void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray) -{ - WAVEHDR* blocks = blockArray; - - int count = buffer_size/period_size; - - for(int i = 0; i < count; i++) { - waveOutUnprepareHeader(hWaveOut,blocks, sizeof(WAVEHDR)); - blocks++; - } - HeapFree(GetProcessHeap(), 0, blockArray); -} - -QAudioFormat QAudioOutputPrivate::format() const -{ - return settings; -} - -void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -void QAudioOutputPrivate::start(QIODevice* device) -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = true; - audioSource = device; - - deviceState = QAudio::ActiveState; - - if(!open()) - return; - - emit stateChanged(deviceState); -} - -QIODevice* QAudioOutputPrivate::start() -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = false; - audioSource = new OutputPrivate(this); - audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); - - deviceState = QAudio::IdleState; - - if(!open()) - return 0; - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAudioOutputPrivate::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - close(); - if(!pullMode && audioSource) { - delete audioSource; - audioSource = 0; - } - emit stateChanged(deviceState); -} - -bool QAudioOutputPrivate::open() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()"; -#endif - - period_size = 0; - - if (!settings.isValid()) { - qWarning("QAudioOutput: open error, invalid format."); - } else if (settings.channelCount() <= 0) { - qWarning("QAudioOutput: open error, invalid number of channels (%d).", - settings.channelCount()); - } else if (settings.sampleSize() <= 0) { - qWarning("QAudioOutput: open error, invalid sample size (%d).", - settings.sampleSize()); - } else if (settings.sampleRate() < 8000 || settings.sampleRate() > 96000) { - qWarning("QAudioOutput: open error, sample rate out of range (%d).", settings.sampleRate()); - } else if (buffer_size == 0) { - // Default buffer size, 200ms, default period size is 40ms - buffer_size - = (settings.sampleRate() - * settings.channelCount() - * settings.sampleSize() - + 39) / 40; - period_size = buffer_size / 5; - } else { - period_size = buffer_size / 5; - } - - if (period_size == 0) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - return false; - } - - waveBlocks = allocateBlocks(period_size, buffer_size/period_size); - - mutex.lock(); - waveFreeBlockCount = buffer_size/period_size; - mutex.unlock(); - - waveCurrentBlock = 0; - - if(audioBuffer == 0) - audioBuffer = new char[buffer_size]; - - timeStamp.restart(); - elapsedTimeOffset = 0; - - wfx.nSamplesPerSec = settings.sampleRate(); - wfx.wBitsPerSample = settings.sampleSize(); - wfx.nChannels = settings.channelCount(); - wfx.cbSize = 0; - - bool surround = false; - - if (settings.channelCount() > 2) - surround = true; - - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels; - wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; - - QDataStream ds(&m_device, QIODevice::ReadOnly); - quint32 deviceId; - ds >> deviceId; - - if (!surround) { - if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfx, - (DWORD_PTR)&waveOutProc, - (DWORD_PTR) this, - CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - qWarning("QAudioOutput: open error"); - return false; - } - } else { - WAVEFORMATEXTENSIBLE wfex; - wfex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfex.Format.nChannels = settings.channelCount(); - wfex.Format.wBitsPerSample = settings.sampleSize(); - wfex.Format.nSamplesPerSec = settings.sampleRate(); - wfex.Format.nBlockAlign = wfex.Format.nChannels*wfex.Format.wBitsPerSample/8; - wfex.Format.nAvgBytesPerSec=wfex.Format.nSamplesPerSec*wfex.Format.nBlockAlign; - wfex.Samples.wValidBitsPerSample=wfex.Format.wBitsPerSample; - static const GUID _KSDATAFORMAT_SUBTYPE_PCM = { - 0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; - wfex.SubFormat=_KSDATAFORMAT_SUBTYPE_PCM; - wfex.Format.cbSize=22; - - wfex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - if (settings.channelCount() >= 4) - wfex.dwChannelMask |= SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; - if (settings.channelCount() >= 6) - wfex.dwChannelMask |= SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY; - if (settings.channelCount() == 8) - wfex.dwChannelMask |= SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; - - if (waveOutOpen(&hWaveOut, UINT_PTR(deviceId), &wfex.Format, - (DWORD_PTR)&waveOutProc, - (DWORD_PTR) this, - CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { - errorState = QAudio::OpenError; - deviceState = QAudio::StoppedState; - emit stateChanged(deviceState); - qWarning("QAudioOutput: open error"); - return false; - } - } - - totalTimeValue = 0; - timeStampOpened.restart(); - elapsedTimeOffset = 0; - - setVolume(volumeCache); - - errorState = QAudio::NoError; - if(pullMode) { - deviceState = QAudio::ActiveState; - QTimer::singleShot(10, this, SLOT(feedback())); - } else - deviceState = QAudio::IdleState; - - return true; -} - -void QAudioOutputPrivate::close() -{ - if(deviceState == QAudio::StoppedState) - return; - - deviceState = QAudio::StoppedState; - errorState = QAudio::NoError; - int delay = (buffer_size-bytesFree())*1000/(settings.sampleRate() - *settings.channelCount()*(settings.sampleSize()/8)); - waveOutReset(hWaveOut); - Sleep(delay+10); - - freeBlocks(waveBlocks); - waveOutClose(hWaveOut); - delete [] audioBuffer; - audioBuffer = 0; - buffer_size = 0; -} - -int QAudioOutputPrivate::bytesFree() const -{ - int buf; - buf = waveFreeBlockCount*period_size; - - return buf; -} - -int QAudioOutputPrivate::periodSize() const -{ - return period_size; -} - -void QAudioOutputPrivate::setBufferSize(int value) -{ - if(deviceState == QAudio::StoppedState) - buffer_size = value; -} - -int QAudioOutputPrivate::bufferSize() const -{ - return buffer_size; -} - -void QAudioOutputPrivate::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAudioOutputPrivate::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAudioOutputPrivate::processedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - qint64 result = qint64(1000000) * totalTimeValue / - (settings.channelCount()*(settings.sampleSize()/8)) / - settings.sampleRate(); - - return result; -} - -qint64 QAudioOutputPrivate::write( const char *data, qint64 len ) -{ - // Write out some audio data - if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) - return 0; - - char* p = (char*)data; - int l = (int)len; - - QByteArray reverse; - if (settings.byteOrder() == QAudioFormat::BigEndian) { - - switch (settings.sampleSize()) { - case 8: - // No need to convert - break; - - case 16: - reverse.resize(l); - for (qint64 i = 0; i < (l >> 1); i++) - *((qint16*)reverse.data() + i) = qFromBigEndian(*((qint16*)data + i)); - p = reverse.data(); - break; - - case 32: - reverse.resize(l); - for (qint64 i = 0; i < (l >> 2); i++) - *((qint32*)reverse.data() + i) = qFromBigEndian(*((qint32*)data + i)); - p = reverse.data(); - break; - } - } - - WAVEHDR* current; - int remain; - current = &waveBlocks[waveCurrentBlock]; - while(l > 0) { - mutex.lock(); - if(waveFreeBlockCount==0) { - mutex.unlock(); - break; - } - mutex.unlock(); - - if(current->dwFlags & WHDR_PREPARED) - waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR)); - - if(l < period_size) - remain = l; - else - remain = period_size; - memcpy(current->lpData, p, remain); - - l -= remain; - p += remain; - current->dwBufferLength = remain; - waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR)); - waveOutWrite(hWaveOut, current, sizeof(WAVEHDR)); - - mutex.lock(); - waveFreeBlockCount--; -#ifdef DEBUG_AUDIO - qDebug("write out l=%d, waveFreeBlockCount=%d", - current->dwBufferLength,waveFreeBlockCount); -#endif - mutex.unlock(); - - totalTimeValue += current->dwBufferLength; - waveCurrentBlock++; - waveCurrentBlock %= buffer_size/period_size; - current = &waveBlocks[waveCurrentBlock]; - current->dwUser = 0; - errorState = QAudio::NoError; - if (deviceState != QAudio::ActiveState) { - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - } - return (len-l); -} - -void QAudioOutputPrivate::resume() -{ - if(deviceState == QAudio::SuspendedState) { - deviceState = QAudio::ActiveState; - errorState = QAudio::NoError; - waveOutRestart(hWaveOut); - QTimer::singleShot(10, this, SLOT(feedback())); - emit stateChanged(deviceState); - } -} - -void QAudioOutputPrivate::suspend() -{ - if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) { - int delay = (buffer_size-bytesFree())*1000/(settings.sampleRate() - *settings.channelCount()*(settings.sampleSize()/8)); - waveOutPause(hWaveOut); - Sleep(delay+10); - deviceState = QAudio::SuspendedState; - errorState = QAudio::NoError; - emit stateChanged(deviceState); - } -} - -void QAudioOutputPrivate::feedback() -{ -#ifdef DEBUG_AUDIO - QTime now(QTime::currentTime()); - qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback()"; -#endif - bytesAvailable = bytesFree(); - - if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState)) { - if(bytesAvailable >= period_size) - QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection); - } -} - -bool QAudioOutputPrivate::deviceReady() -{ - if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState) - return false; - - if(pullMode) { - int chunks = bytesAvailable/period_size; -#ifdef DEBUG_AUDIO - qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes"; - qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<chunks*period_size; -#endif - bool startup = false; - if(totalTimeValue == 0) - startup = true; - - bool full=false; - - mutex.lock(); - if (waveFreeBlockCount==0) full = true; - mutex.unlock(); - - if (full) { -#ifdef DEBUG_AUDIO - qDebug() << "Skipping data as unable to write"; -#endif - if ((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { - emit notify(); - elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; - timeStamp.restart(); - } - return true; - } - - if(startup) - waveOutPause(hWaveOut); - int input = period_size*chunks; - int l = audioSource->read(audioBuffer,input); - if(l > 0) { - int out= write(audioBuffer,l); - if(out > 0) { - if (deviceState != QAudio::ActiveState) { - deviceState = QAudio::ActiveState; - emit stateChanged(deviceState); - } - } - if ( out < l) { - // Didn't write all data - audioSource->seek(audioSource->pos()-(l-out)); - } - if (startup) - waveOutRestart(hWaveOut); - } else if(l == 0) { - bytesAvailable = bytesFree(); - - int check = 0; - - mutex.lock(); - check = waveFreeBlockCount; - mutex.unlock(); - - if(check == buffer_size/period_size) { - if (deviceState != QAudio::IdleState) { - errorState = QAudio::UnderrunError; - deviceState = QAudio::IdleState; - emit stateChanged(deviceState); - } - } - - } else if(l < 0) { - bytesAvailable = bytesFree(); - if (errorState != QAudio::IOError) - errorState = QAudio::IOError; - } - } else { - int buffered; - - mutex.lock(); - buffered = waveFreeBlockCount; - mutex.unlock(); - - if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) { - if (deviceState != QAudio::IdleState) { - errorState = QAudio::UnderrunError; - deviceState = QAudio::IdleState; - emit stateChanged(deviceState); - } - } - } - if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) - return true; - - if(intervalTime && (timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) { - emit notify(); - elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime; - timeStamp.restart(); - } - - return true; -} - -qint64 QAudioOutputPrivate::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return timeStampOpened.elapsed()*1000; -} - -QAudio::Error QAudioOutputPrivate::error() const -{ - return errorState; -} - -QAudio::State QAudioOutputPrivate::state() const -{ - return deviceState; -} - -void QAudioOutputPrivate::setVolume(qreal v) -{ - const qreal normalizedVolume = qBound(qreal(0.0), v, qreal(1.0)); - if (deviceState != QAudio::ActiveState) { - volumeCache = normalizedVolume; - return; - } - const quint16 scaled = normalizedVolume * 0xFFFF; - DWORD vol = MAKELONG(scaled, scaled); - MMRESULT res = waveOutSetVolume(hWaveOut, vol); - if (res == MMSYSERR_NOERROR) - volumeCache = normalizedVolume; -} - -qreal QAudioOutputPrivate::volume() const -{ - return volumeCache; -} - -void QAudioOutputPrivate::reset() -{ - close(); -} - -OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio) -{ - audioDevice = qobject_cast<QAudioOutputPrivate*>(audio); -} - -OutputPrivate::~OutputPrivate() {} - -qint64 OutputPrivate::readData( char* data, qint64 len) -{ - Q_UNUSED(data) - Q_UNUSED(len) - - return 0; -} - -qint64 OutputPrivate::writeData(const char* data, qint64 len) -{ - int retry = 0; - qint64 written = 0; - - if((audioDevice->deviceState == QAudio::ActiveState) - ||(audioDevice->deviceState == QAudio::IdleState)) { - qint64 l = len; - while(written < l) { - int chunk = audioDevice->write(data+written,(l-written)); - if(chunk <= 0) - retry++; - else - written+=chunk; - - if(retry > 10) - return written; - } - audioDevice->deviceState = QAudio::ActiveState; - } - return written; -} - -QT_END_NAMESPACE - -#include "moc_qaudiooutput_win32_p.cpp" diff --git a/src/multimedia/audio/qaudiooutput_win32_p.h b/src/multimedia/audio/qaudiooutput_win32_p.h deleted file mode 100644 index cdff12821..000000000 --- a/src/multimedia/audio/qaudiooutput_win32_p.h +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of other Qt classes. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QAUDIOOUTPUTWIN_H -#define QAUDIOOUTPUTWIN_H - -#include <QtCore/qt_windows.h> -#include <mmsystem.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qtimer.h> -#include <QtCore/qstring.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qmutex.h> - -#include <qaudio.h> -#include <qaudiodeviceinfo.h> -#include <qaudiosystem.h> - -// For compat with 4.6 -#if !defined(QT_WIN_CALLBACK) -# if defined(Q_CC_MINGW) -# define QT_WIN_CALLBACK CALLBACK __attribute__ ((force_align_arg_pointer)) -# else -# define QT_WIN_CALLBACK CALLBACK -# endif -#endif - -QT_BEGIN_NAMESPACE - - -class QAudioOutputPrivate : public QAbstractAudioOutput -{ - Q_OBJECT -public: - QAudioOutputPrivate(const QByteArray &device); - ~QAudioOutputPrivate(); - - qint64 write( const char *data, qint64 len ); - - void setFormat(const QAudioFormat& fmt); - QAudioFormat format() const; - QIODevice* start(); - void start(QIODevice* device); - void stop(); - void reset(); - void suspend(); - void resume(); - int bytesFree() const; - int periodSize() const; - void setBufferSize(int value); - int bufferSize() const; - void setNotifyInterval(int milliSeconds); - int notifyInterval() const; - qint64 processedUSecs() const; - qint64 elapsedUSecs() const; - QAudio::Error error() const; - QAudio::State state() const; - void setVolume(qreal); - qreal volume() const; - - QIODevice* audioSource; - QAudioFormat settings; - QAudio::Error errorState; - QAudio::State deviceState; - -private slots: - void feedback(); - bool deviceReady(); - -private: - QByteArray m_device; - bool resuming; - int bytesAvailable; - QTime timeStamp; - qint64 elapsedTimeOffset; - QTime timeStampOpened; - qint32 buffer_size; - qint32 period_size; - qint64 totalTimeValue; - bool pullMode; - int intervalTime; - qreal volumeCache; - static void QT_WIN_CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg, - DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2 ); - - QMutex mutex; - - WAVEHDR* allocateBlocks(int size, int count); - void freeBlocks(WAVEHDR* blockArray); - bool open(); - void close(); - - WAVEFORMATEX wfx; - HWAVEOUT hWaveOut; - MMRESULT result; - WAVEHDR header; - WAVEHDR* waveBlocks; - volatile bool finished; - volatile int waveFreeBlockCount; - int waveCurrentBlock; - char* audioBuffer; -}; - -class OutputPrivate : public QIODevice -{ - Q_OBJECT -public: - OutputPrivate(QAudioOutputPrivate* audio); - ~OutputPrivate(); - - qint64 readData( char* data, qint64 len); - qint64 writeData(const char* data, qint64 len); - -private: - QAudioOutputPrivate *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif |