diff options
Diffstat (limited to 'src/plugins/alsa')
-rw-r--r-- | src/plugins/alsa/alsa.json | 3 | ||||
-rw-r--r-- | src/plugins/alsa/alsa.pro | 23 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudiodeviceinfo.cpp | 430 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudiodeviceinfo.h | 120 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudioinput.cpp | 872 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudioinput.h | 185 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudiooutput.cpp | 813 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaaudiooutput.h | 164 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaplugin.cpp | 77 | ||||
-rw-r--r-- | src/plugins/alsa/qalsaplugin.h | 68 |
10 files changed, 0 insertions, 2755 deletions
diff --git a/src/plugins/alsa/alsa.json b/src/plugins/alsa/alsa.json deleted file mode 100644 index c2b22dfec..000000000 --- a/src/plugins/alsa/alsa.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": ["alsa"] -} diff --git a/src/plugins/alsa/alsa.pro b/src/plugins/alsa/alsa.pro deleted file mode 100644 index 4012bb8f6..000000000 --- a/src/plugins/alsa/alsa.pro +++ /dev/null @@ -1,23 +0,0 @@ -TARGET = qtaudio_alsa -QT += multimedia-private - -QMAKE_USE += alsa - -HEADERS += \ - qalsaplugin.h \ - qalsaaudiodeviceinfo.h \ - qalsaaudioinput.h \ - qalsaaudiooutput.h - -SOURCES += \ - qalsaplugin.cpp \ - qalsaaudiodeviceinfo.cpp \ - qalsaaudioinput.cpp \ - qalsaaudiooutput.cpp - -OTHER_FILES += \ - alsa.json - -PLUGIN_TYPE = audio -PLUGIN_CLASS_NAME = QAlsaPlugin -load(qt_plugin) diff --git a/src/plugins/alsa/qalsaaudiodeviceinfo.cpp b/src/plugins/alsa/qalsaaudiodeviceinfo.cpp deleted file mode 100644 index 5cfcb27e0..000000000 --- a/src/plugins/alsa/qalsaaudiodeviceinfo.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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 "qalsaaudiodeviceinfo.h" - -#include <alsa/version.h> - -QT_BEGIN_NAMESPACE - -QAlsaAudioDeviceInfo::QAlsaAudioDeviceInfo(const QByteArray &dev, QAudio::Mode mode) -{ - handle = 0; - - device = QLatin1String(dev); - this->mode = mode; - - checkSurround(); -} - -QAlsaAudioDeviceInfo::~QAlsaAudioDeviceInfo() -{ - close(); -} - -bool QAlsaAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const -{ - return testSettings(format); -} - -QAudioFormat QAlsaAudioDeviceInfo::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 QAlsaAudioDeviceInfo::deviceName() const -{ - return device; -} - -QStringList QAlsaAudioDeviceInfo::supportedCodecs() -{ - updateLists(); - return codecz; -} - -QList<int> QAlsaAudioDeviceInfo::supportedSampleRates() -{ - updateLists(); - return sampleRatez; -} - -QList<int> QAlsaAudioDeviceInfo::supportedChannelCounts() -{ - updateLists(); - return channelz; -} - -QList<int> QAlsaAudioDeviceInfo::supportedSampleSizes() -{ - updateLists(); - return sizez; -} - -QList<QAudioFormat::Endian> QAlsaAudioDeviceInfo::supportedByteOrders() -{ - updateLists(); - return byteOrderz; -} - -QList<QAudioFormat::SampleType> QAlsaAudioDeviceInfo::supportedSampleTypes() -{ - updateLists(); - return typez; -} - -QByteArray QAlsaAudioDeviceInfo::defaultDevice(QAudio::Mode mode) -{ - const auto &devices = availableDevices(mode); - if (devices.size() == 0) - return QByteArray(); - - return devices.first(); -} - -bool QAlsaAudioDeviceInfo::open() -{ - int err = 0; - QString dev; - - if (!availableDevices(mode).contains(device.toLocal8Bit())) - return false; - -#if SND_LIB_VERSION < 0x1000e // 1.0.14 - if (device.compare(QLatin1String("default")) != 0) - dev = deviceFromCardName(device); - else -#endif - dev = device; - - 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 QAlsaAudioDeviceInfo::close() -{ - if(handle) - snd_pcm_close(handle); - handle = 0; -} - -bool QAlsaAudioDeviceInfo::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_VERSION < 0x1000e // 1.0.14 - if (device.compare(QLatin1String("default")) != 0) - dev = deviceFromCardName(device); - else -#endif - dev = device; - - 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 QAlsaAudioDeviceInfo::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> QAlsaAudioDeviceInfo::availableDevices(QAudio::Mode mode) -{ - QList<QByteArray> devices; - bool hasDefault = false; - -#if SND_LIB_VERSION >= 0x1000e // 1.0.14 - QByteArray filter; - - // Create a list of all current audio devices that support mode - void **hints, **n; - char *name, *descr, *io; - - if(snd_device_name_hint(-1, "pcm", &hints) < 0) { - qWarning() << "no alsa devices available"; - return devices; - } - n = hints; - - if(mode == QAudio::AudioInput) { - filter = "Input"; - } else { - filter = "Output"; - } - - 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))) { - devices.append(name); - if (strcmp(name, "default") == 0) - hasDefault = true; - } - - 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); - if (strcmp(name, "default") == 0) - hasDefault = true; - idx++; - } -#endif - - if (!hasDefault && devices.size() > 0) - devices.prepend("default"); - - return devices; -} - -void QAlsaAudioDeviceInfo::checkSurround() -{ - surround40 = false; - surround51 = false; - surround71 = false; - - void **hints, **n; - char *name, *descr, *io; - - if(snd_device_name_hint(-1, "pcm", &hints) < 0) - return; - - 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); -} - -QString QAlsaAudioDeviceInfo::deviceFromCardName(const QString &card) -{ - int idx = 0; - char *name; - - QStringView shortName = QStringView{card}.mid(card.indexOf(QLatin1String("="), 0) + 1); - - while (snd_card_get_name(idx, &name) == 0) { - if (shortName.compare(QLatin1String(name)) == 0) - break; - idx++; - } - - return QString(QLatin1String("hw:%1,0")).arg(idx); -} - -QT_END_NAMESPACE diff --git a/src/plugins/alsa/qalsaaudiodeviceinfo.h b/src/plugins/alsa/qalsaaudiodeviceinfo.h deleted file mode 100644 index cdf08bfab..000000000 --- a/src/plugins/alsa/qalsaaudiodeviceinfo.h +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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 QALSAAUDIODEVICEINFO_H -#define QALSAAUDIODEVICEINFO_H - -#include <alsa/asoundlib.h> - -#include <QtCore/qbytearray.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qlist.h> -#include <QtCore/qdebug.h> - -#include <QtMultimedia/qaudio.h> -#include <QtMultimedia/qaudiodeviceinfo.h> -#include <QtMultimedia/qaudiosystem.h> - -QT_BEGIN_NAMESPACE - - -const unsigned int MAX_SAMPLE_RATES = 5; -const unsigned int SAMPLE_RATES[] = - { 8000, 11025, 22050, 44100, 48000 }; - -class QAlsaAudioDeviceInfo : public QAbstractAudioDeviceInfo -{ - Q_OBJECT -public: - QAlsaAudioDeviceInfo(const QByteArray &dev,QAudio::Mode mode); - ~QAlsaAudioDeviceInfo(); - - bool testSettings(const QAudioFormat& format) const; - void updateLists(); - QAudioFormat preferredFormat() const override; - bool isFormatSupported(const QAudioFormat& format) const override; - QString deviceName() const override; - QStringList supportedCodecs() override; - QList<int> supportedSampleRates() override; - QList<int> supportedChannelCounts() override; - QList<int> supportedSampleSizes() override; - QList<QAudioFormat::Endian> supportedByteOrders() override; - QList<QAudioFormat::SampleType> supportedSampleTypes() override; - static QByteArray defaultDevice(QAudio::Mode mode); - static QList<QByteArray> availableDevices(QAudio::Mode); - static QString deviceFromCardName(const QString &card); - -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 // QALSAAUDIODEVICEINFO_H diff --git a/src/plugins/alsa/qalsaaudioinput.cpp b/src/plugins/alsa/qalsaaudioinput.cpp deleted file mode 100644 index bff23dfe1..000000000 --- a/src/plugins/alsa/qalsaaudioinput.cpp +++ /dev/null @@ -1,872 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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 <QtCore/qvarlengtharray.h> -#include <QtMultimedia/private/qaudiohelpers_p.h> -#include "qalsaaudioinput.h" -#include "qalsaaudiodeviceinfo.h" - -QT_BEGIN_NAMESPACE - -//#define DEBUG_AUDIO 1 - -QAlsaAudioInput::QAlsaAudioInput(const QByteArray &device) -{ - bytesAvailable = 0; - handle = 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())); -} - -QAlsaAudioInput::~QAlsaAudioInput() -{ - close(); - disconnect(timer, SIGNAL(timeout())); - QCoreApplication::processEvents(); - delete timer; -} - -void QAlsaAudioInput::setVolume(qreal vol) -{ - m_volume = vol; -} - -qreal QAlsaAudioInput::volume() const -{ - return m_volume; -} - -QAudio::Error QAlsaAudioInput::error() const -{ - return errorState; -} - -QAudio::State QAlsaAudioInput::state() const -{ - return deviceState; -} - -void QAlsaAudioInput::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -QAudioFormat QAlsaAudioInput::format() const -{ - return settings; -} - -int QAlsaAudioInput::xrun_recovery(int err) -{ - int count = 0; - bool reset = false; - - // ESTRPIPE is not available in all OSes where ALSA is available - int estrpipe = EIO; -#ifdef ESTRPIPE - estrpipe = ESTRPIPE; -#endif - - 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 QAlsaAudioInput::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 QAlsaAudioInput::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* QAlsaAudioInput::start() -{ - if(deviceState != QAudio::StoppedState) - close(); - - if(!pullMode && audioSource) - delete audioSource; - - pullMode = false; - audioSource = new AlsaInputPrivate(this); - audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); - - deviceState = QAudio::IdleState; - - if( !open() ) - return 0; - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAlsaAudioInput::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - - deviceState = QAudio::StoppedState; - - close(); - emit stateChanged(deviceState); -} - -bool QAlsaAudioInput::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; - } - - - if (!QAlsaAudioDeviceInfo::availableDevices(QAudio::AudioInput).contains(m_device)) - return false; - - QString dev; -#if SND_LIB_VERSION < 0x1000e // 1.0.14 - if (m_device != "default") - dev = QAlsaAudioDeviceInfo::deviceFromCardName(m_device); - else -#endif - dev = m_device; - - // 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 QAlsaAudioInput::close() -{ - timer->stop(); - - if ( handle ) { - snd_pcm_drop( handle ); - snd_pcm_close( handle ); - handle = 0; - } -} - -int QAlsaAudioInput::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 QAlsaAudioInput::bytesReady() const -{ - return qMax(bytesAvailable, 0); -} - -qint64 QAlsaAudioInput::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; - QVarLengthArray<char, 4096> buffer(bytesToRead); - while(count < 5 && bytesToRead > 0) { - 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.data(), frames); - bytesRead = snd_pcm_frames_to_bytes(handle, readFrames); - if (m_volume < 1.0f) - QAudioHelperInternal::qMultiplySamples(m_volume, settings, - buffer.constData(), - buffer.data(), bytesRead); - - if (readFrames >= 0) { - ringBuffer.write(buffer.data(), 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); -#ifdef ESTRPIPE - } else if(readFrames == -ESTRPIPE) { - err = snd_pcm_prepare(handle); -#endif - } - 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 QAlsaAudioInput::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 QAlsaAudioInput::setBufferSize(int value) -{ - buffer_size = value; -} - -int QAlsaAudioInput::bufferSize() const -{ - return buffer_size; -} - -int QAlsaAudioInput::periodSize() const -{ - return period_size; -} - -void QAlsaAudioInput::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAlsaAudioInput::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAlsaAudioInput::processedUSecs() const -{ - qint64 result = qint64(1000000) * totalTimeValue / - (settings.channelCount()*(settings.sampleSize()/8)) / - settings.sampleRate(); - - return result; -} - -void QAlsaAudioInput::suspend() -{ - if(deviceState == QAudio::ActiveState||resuming) { - snd_pcm_drain(handle); - timer->stop(); - deviceState = QAudio::SuspendedState; - emit stateChanged(deviceState); - } -} - -void QAlsaAudioInput::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 QAlsaAudioInput::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 - AlsaInputPrivate* a = qobject_cast<AlsaInputPrivate*>(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 QAlsaAudioInput::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return clockStamp.elapsed() * qint64(1000); -} - -void QAlsaAudioInput::reset() -{ - if(handle) - snd_pcm_reset(handle); - stop(); - bytesAvailable = 0; -} - -void QAlsaAudioInput::drain() -{ - if(handle) - snd_pcm_drain(handle); -} - -AlsaInputPrivate::AlsaInputPrivate(QAlsaAudioInput* audio) -{ - audioDevice = qobject_cast<QAlsaAudioInput*>(audio); -} - -AlsaInputPrivate::~AlsaInputPrivate() -{ -} - -qint64 AlsaInputPrivate::readData( char* data, qint64 len) -{ - return audioDevice->read(data,len); -} - -qint64 AlsaInputPrivate::writeData(const char* data, qint64 len) -{ - Q_UNUSED(data); - Q_UNUSED(len); - return 0; -} - -void AlsaInputPrivate::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_qalsaaudioinput.cpp" diff --git a/src/plugins/alsa/qalsaaudioinput.h b/src/plugins/alsa/qalsaaudioinput.h deleted file mode 100644 index 62e1be039..000000000 --- a/src/plugins/alsa/qalsaaudioinput.h +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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/qelapsedtimer.h> -#include <QtCore/qiodevice.h> - -#include <QtMultimedia/qaudio.h> -#include <QtMultimedia/qaudiodeviceinfo.h> -#include <QtMultimedia/qaudiosystem.h> - -QT_BEGIN_NAMESPACE - - -class AlsaInputPrivate; - -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 QAlsaAudioInput : public QAbstractAudioInput -{ - Q_OBJECT -public: - QAlsaAudioInput(const QByteArray &device); - ~QAlsaAudioInput(); - - qint64 read(char* data, qint64 len); - - void start(QIODevice* device) override; - QIODevice* start() override; - void stop() override; - void reset() override; - void suspend() override; - void resume() override; - int bytesReady() const override; - int periodSize() const override; - void setBufferSize(int value) override; - int bufferSize() const override; - void setNotifyInterval(int milliSeconds) override; - int notifyInterval() const override; - qint64 processedUSecs() const override; - qint64 elapsedUSecs() const override; - QAudio::Error error() const override; - QAudio::State state() const override; - void setFormat(const QAudioFormat& fmt) override; - QAudioFormat format() const override; - void setVolume(qreal) override; - qreal volume() const override; - 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; - QElapsedTimer timeStamp; - QElapsedTimer 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_pcm_access_t access; - snd_pcm_format_t pcmformat; - snd_pcm_hw_params_t *hwparams; - qreal m_volume; -}; - -class AlsaInputPrivate : public QIODevice -{ - Q_OBJECT -public: - AlsaInputPrivate(QAlsaAudioInput* audio); - ~AlsaInputPrivate(); - - qint64 readData( char* data, qint64 len) override; - qint64 writeData(const char* data, qint64 len) override; - - void trigger(); -private: - QAlsaAudioInput *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp deleted file mode 100644 index f66e5e6e8..000000000 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ /dev/null @@ -1,813 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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 <QtCore/qvarlengtharray.h> -#include <QtMultimedia/private/qaudiohelpers_p.h> -#include "qalsaaudiooutput.h" -#include "qalsaaudiodeviceinfo.h" -#include <QLoggingCategory> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcAlsaOutput, "qt.multimedia.alsa.output") -//#define DEBUG_AUDIO 1 - -QAlsaAudioOutput::QAlsaAudioOutput(const QByteArray &device) -{ - bytesAvailable = 0; - handle = 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())); -} - -QAlsaAudioOutput::~QAlsaAudioOutput() -{ - close(); - disconnect(timer, SIGNAL(timeout())); - QCoreApplication::processEvents(); - delete timer; -} - -void QAlsaAudioOutput::setVolume(qreal vol) -{ - m_volume = vol; -} - -qreal QAlsaAudioOutput::volume() const -{ - return m_volume; -} - -QAudio::Error QAlsaAudioOutput::error() const -{ - return errorState; -} - -QAudio::State QAlsaAudioOutput::state() const -{ - return deviceState; -} - -int QAlsaAudioOutput::xrun_recovery(int err) -{ - int count = 0; - bool reset = false; - - // ESTRPIPE is not available in all OSes where ALSA is available - int estrpipe = EIO; -#ifdef ESTRPIPE - estrpipe = ESTRPIPE; -#endif - - 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 QAlsaAudioOutput::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 QAlsaAudioOutput::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* QAlsaAudioOutput::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 AlsaOutputPrivate(this); - audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered); - pullMode = false; - - deviceState = QAudio::IdleState; - - open(); - - emit stateChanged(deviceState); - - return audioSource; -} - -void QAlsaAudioOutput::stop() -{ - if(deviceState == QAudio::StoppedState) - return; - errorState = QAudio::NoError; - deviceState = QAudio::StoppedState; - close(); - emit stateChanged(deviceState); -} - -bool QAlsaAudioOutput::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; -#if SND_LIB_VERSION < 0x1000e // 1.0.14 - if (m_device != "default") - dev = QAlsaAudioDeviceInfo::deviceFromCardName(m_device); - else -#endif - dev = m_device; - - // 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 { - static unsigned user_buffer_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_BUFFER_TIME"); - static unsigned user_period_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_PERIOD_TIME"); - const bool outOfRange = maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time; - if (outOfRange || user_period_time || user_buffer_time) { - period_time = user_period_time ? user_period_time : minPeriodTime; - if (!user_buffer_time) { - chunks = maxBufferTime / period_time; - buffer_time = period_time * chunks; - } else { - buffer_time = user_buffer_time; - chunks = buffer_time / period_time; - } - } - qCDebug(lcAlsaOutput) << "buffer time: [" << minBufferTime << "-" << maxBufferTime << "] =" << buffer_time; - qCDebug(lcAlsaOutput) << "period time: [" << minPeriodTime << "-" << maxPeriodTime << "] =" << period_time; - qCDebug(lcAlsaOutput) << "chunks =" << chunks; - } - } - 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 timer - 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 QAlsaAudioOutput::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 QAlsaAudioOutput::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 QAlsaAudioOutput::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) { - QVarLengthArray<char, 4096> out(space); - QAudioHelperInternal::qMultiplySamples(m_volume, settings, data, out.data(), space); - err = snd_pcm_writei(handle, out.constData(), 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 QAlsaAudioOutput::periodSize() const -{ - return period_size; -} - -void QAlsaAudioOutput::setBufferSize(int value) -{ - if(deviceState == QAudio::StoppedState) - buffer_size = value; -} - -int QAlsaAudioOutput::bufferSize() const -{ - return buffer_size; -} - -void QAlsaAudioOutput::setNotifyInterval(int ms) -{ - intervalTime = qMax(0, ms); -} - -int QAlsaAudioOutput::notifyInterval() const -{ - return intervalTime; -} - -qint64 QAlsaAudioOutput::processedUSecs() const -{ - return qint64(1000000) * totalTimeValue / settings.sampleRate(); -} - -void QAlsaAudioOutput::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 = pullMode ? QAudio::ActiveState : QAudio::IdleState; - - errorState = QAudio::NoError; - timer->start(period_time/1000); - emit stateChanged(deviceState); - } -} - -void QAlsaAudioOutput::setFormat(const QAudioFormat& fmt) -{ - if (deviceState == QAudio::StoppedState) - settings = fmt; -} - -QAudioFormat QAlsaAudioOutput::format() const -{ - return settings; -} - -void QAlsaAudioOutput::suspend() -{ - if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) { - snd_pcm_drain(handle); - timer->stop(); - deviceState = QAudio::SuspendedState; - errorState = QAudio::NoError; - emit stateChanged(deviceState); - } -} - -void QAlsaAudioOutput::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(); -} - -bool QAlsaAudioOutput::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 && deviceState != QAudio::IdleState) - 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 QAlsaAudioOutput::elapsedUSecs() const -{ - if (deviceState == QAudio::StoppedState) - return 0; - - return clockStamp.elapsed() * qint64(1000); -} - -void QAlsaAudioOutput::reset() -{ - if(handle) - snd_pcm_reset(handle); - - stop(); -} - -AlsaOutputPrivate::AlsaOutputPrivate(QAlsaAudioOutput* audio) -{ - audioDevice = qobject_cast<QAlsaAudioOutput*>(audio); -} - -AlsaOutputPrivate::~AlsaOutputPrivate() {} - -qint64 AlsaOutputPrivate::readData( char* data, qint64 len) -{ - Q_UNUSED(data); - Q_UNUSED(len); - - return 0; -} - -qint64 AlsaOutputPrivate::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_qalsaaudiooutput.cpp" diff --git a/src/plugins/alsa/qalsaaudiooutput.h b/src/plugins/alsa/qalsaaudiooutput.h deleted file mode 100644 index 72b9c2e4c..000000000 --- a/src/plugins/alsa/qalsaaudiooutput.h +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// 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/qelapsedtimer.h> -#include <QtCore/qiodevice.h> - -#include <QtMultimedia/qaudio.h> -#include <QtMultimedia/qaudiodeviceinfo.h> -#include <QtMultimedia/qaudiosystem.h> - -QT_BEGIN_NAMESPACE - -class QAlsaAudioOutput : public QAbstractAudioOutput -{ - friend class AlsaOutputPrivate; - Q_OBJECT -public: - QAlsaAudioOutput(const QByteArray &device); - ~QAlsaAudioOutput(); - - qint64 write( const char *data, qint64 len ); - - void start(QIODevice* device) override; - QIODevice* start() override; - void stop() override; - void reset() override; - void suspend() override; - void resume() override; - int bytesFree() const override; - int periodSize() const override; - void setBufferSize(int value) override; - int bufferSize() const override; - void setNotifyInterval(int milliSeconds) override; - int notifyInterval() const override; - qint64 processedUSecs() const override; - qint64 elapsedUSecs() const override; - QAudio::Error error() const override; - QAudio::State state() const override; - void setFormat(const QAudioFormat& fmt) override; - QAudioFormat format() const override; - void setVolume(qreal) override; - qreal volume() const override; - - - QIODevice* audioSource; - QAudioFormat settings; - QAudio::Error errorState; - QAudio::State deviceState; - -private slots: - void userFeed(); - 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; - int xrun_recovery(int err); - - int setFormat(); - bool open(); - void close(); - - QTimer* timer; - QByteArray m_device; - int bytesAvailable; - QElapsedTimer timeStamp; - QElapsedTimer clockStamp; - qint64 elapsedTimeOffset; - char* audioBuffer; - snd_pcm_t* handle; - snd_pcm_access_t access; - snd_pcm_format_t pcmformat; - snd_pcm_hw_params_t *hwparams; - qreal m_volume; -}; - -class AlsaOutputPrivate : public QIODevice -{ - friend class QAlsaAudioOutput; - Q_OBJECT -public: - AlsaOutputPrivate(QAlsaAudioOutput* audio); - ~AlsaOutputPrivate(); - - qint64 readData( char* data, qint64 len) override; - qint64 writeData(const char* data, qint64 len) override; - -private: - QAlsaAudioOutput *audioDevice; -}; - -QT_END_NAMESPACE - - -#endif diff --git a/src/plugins/alsa/qalsaplugin.cpp b/src/plugins/alsa/qalsaplugin.cpp deleted file mode 100644 index e52e9ee83..000000000 --- a/src/plugins/alsa/qalsaplugin.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qalsaplugin.h" -#include "qalsaaudiodeviceinfo.h" -#include "qalsaaudioinput.h" -#include "qalsaaudiooutput.h" - -QT_BEGIN_NAMESPACE - -QAlsaPlugin::QAlsaPlugin(QObject *parent) - : QAudioSystemPlugin(parent) -{ -} - -QByteArray QAlsaPlugin::defaultDevice(QAudio::Mode mode) const -{ - return QAlsaAudioDeviceInfo::defaultDevice(mode); -} - -QList<QByteArray> QAlsaPlugin::availableDevices(QAudio::Mode mode) const -{ - return QAlsaAudioDeviceInfo::availableDevices(mode); -} - -QAbstractAudioInput *QAlsaPlugin::createInput(const QByteArray &device) -{ - return new QAlsaAudioInput(device); -} - -QAbstractAudioOutput *QAlsaPlugin::createOutput(const QByteArray &device) -{ - return new QAlsaAudioOutput(device); -} - -QAbstractAudioDeviceInfo *QAlsaPlugin::createDeviceInfo(const QByteArray &device, QAudio::Mode mode) -{ - return new QAlsaAudioDeviceInfo(device, mode); -} - -QT_END_NAMESPACE diff --git a/src/plugins/alsa/qalsaplugin.h b/src/plugins/alsa/qalsaplugin.h deleted file mode 100644 index cebede13b..000000000 --- a/src/plugins/alsa/qalsaplugin.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QALSAPLUGIN_H -#define QALSAPLUGIN_H - -#include <QtMultimedia/qaudiosystemplugin.h> -#include <QtMultimedia/private/qaudiosystempluginext_p.h> - -QT_BEGIN_NAMESPACE - -class QAlsaPlugin : public QAudioSystemPlugin, public QAudioSystemPluginExtension -{ - Q_OBJECT - - Q_PLUGIN_METADATA(IID "org.qt-project.qt.audiosystemfactory/5.0" FILE "alsa.json") - Q_INTERFACES(QAudioSystemPluginExtension) - -public: - QAlsaPlugin(QObject *parent = 0); - ~QAlsaPlugin() {} - - QByteArray defaultDevice(QAudio::Mode mode) const override; - QList<QByteArray> availableDevices(QAudio::Mode mode) const override; - QAbstractAudioInput *createInput(const QByteArray &device) override; - QAbstractAudioOutput *createOutput(const QByteArray &device) override; - QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode) override; -}; - -QT_END_NAMESPACE - -#endif // QALSAPLUGIN_H |