From 99667804e1c64cace1246d4ce342a218fc1fb1ba Mon Sep 17 00:00:00 2001 From: Frank Osterfeld Date: Tue, 5 Nov 2013 14:28:08 +0100 Subject: QNX: Restructure plugins Now that the MmRenderer implementation is ported to plain QNX, rename the directories and files accordingly: "blackberry" becomes "qnx", replace the Bb prefix with MmRenderer for classes concerned with mm-renderer. The legacy alsa support for plain qnx is now "qnx-audio". Change-Id: I6abd98ecdd713b2d5e554d42224dc30f13772f43 Reviewed-by: Thomas McGuire --- src/plugins/qnx-audio/audio/audio.pro | 22 + src/plugins/qnx-audio/audio/qnx_audio.json | 3 + src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.cpp | 150 +++++++ src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.h | 74 ++++ src/plugins/qnx-audio/audio/qnxaudioinput.cpp | 447 +++++++++++++++++++++ src/plugins/qnx-audio/audio/qnxaudioinput.h | 139 +++++++ src/plugins/qnx-audio/audio/qnxaudiooutput.cpp | 443 ++++++++++++++++++++ src/plugins/qnx-audio/audio/qnxaudiooutput.h | 131 ++++++ src/plugins/qnx-audio/audio/qnxaudioplugin.cpp | 88 ++++ src/plugins/qnx-audio/audio/qnxaudioplugin.h | 66 +++ src/plugins/qnx-audio/audio/qnxaudioutils.cpp | 130 ++++++ src/plugins/qnx-audio/audio/qnxaudioutils.h | 57 +++ 12 files changed, 1750 insertions(+) create mode 100644 src/plugins/qnx-audio/audio/audio.pro create mode 100644 src/plugins/qnx-audio/audio/qnx_audio.json create mode 100644 src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.cpp create mode 100644 src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.h create mode 100644 src/plugins/qnx-audio/audio/qnxaudioinput.cpp create mode 100644 src/plugins/qnx-audio/audio/qnxaudioinput.h create mode 100644 src/plugins/qnx-audio/audio/qnxaudiooutput.cpp create mode 100644 src/plugins/qnx-audio/audio/qnxaudiooutput.h create mode 100644 src/plugins/qnx-audio/audio/qnxaudioplugin.cpp create mode 100644 src/plugins/qnx-audio/audio/qnxaudioplugin.h create mode 100644 src/plugins/qnx-audio/audio/qnxaudioutils.cpp create mode 100644 src/plugins/qnx-audio/audio/qnxaudioutils.h (limited to 'src/plugins/qnx-audio/audio') diff --git a/src/plugins/qnx-audio/audio/audio.pro b/src/plugins/qnx-audio/audio/audio.pro new file mode 100644 index 000000000..35ddf73de --- /dev/null +++ b/src/plugins/qnx-audio/audio/audio.pro @@ -0,0 +1,22 @@ +TARGET = qtmedia_qnx_audio +QT += multimedia-private +CONFIG += no_private_qt_headers_warning + +PLUGIN_TYPE = audio +load(qt_plugin) + +LIBS += -lasound + +HEADERS += qnxaudioplugin.h \ + qnxaudiodeviceinfo.h \ + qnxaudioinput.h \ + qnxaudiooutput.h \ + qnxaudioutils.h + +SOURCES += qnxaudioplugin.cpp \ + qnxaudiodeviceinfo.cpp \ + qnxaudioinput.cpp \ + qnxaudiooutput.cpp \ + qnxaudioutils.cpp + +OTHER_FILES += qnx_audio.json diff --git a/src/plugins/qnx-audio/audio/qnx_audio.json b/src/plugins/qnx-audio/audio/qnx_audio.json new file mode 100644 index 000000000..a31d52107 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnx_audio.json @@ -0,0 +1,3 @@ +{ + "Keys": ["default"] +} diff --git a/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.cpp b/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.cpp new file mode 100644 index 000000000..ce8083573 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#include "qnxaudiodeviceinfo.h" + +#include "qnxaudioutils.h" + +#include + +QT_BEGIN_NAMESPACE + +QnxAudioDeviceInfo::QnxAudioDeviceInfo(const QString &deviceName, QAudio::Mode mode) + : m_name(deviceName), + m_mode(mode) +{ +} + +QnxAudioDeviceInfo::~QnxAudioDeviceInfo() +{ +} + +QAudioFormat QnxAudioDeviceInfo::preferredFormat() const +{ + QAudioFormat format; + if (m_mode == QAudio::AudioOutput) { + format.setSampleRate(44100); + format.setChannelCount(2); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + format.setSampleSize(16); + format.setCodec(QLatin1String("audio/pcm")); + } else { + format.setSampleRate(8000); + format.setChannelCount(1); + format.setSampleType(QAudioFormat::UnSignedInt); + format.setSampleSize(8); + format.setCodec(QLatin1String("audio/pcm")); + if (!isFormatSupported(format)) { + format.setChannelCount(2); + format.setSampleSize(16); + format.setSampleType(QAudioFormat::SignedInt); + } + } + return format; +} + +bool QnxAudioDeviceInfo::isFormatSupported(const QAudioFormat &format) const +{ + if (!format.codec().startsWith(QLatin1String("audio/pcm"))) + return false; + + const int pcmMode = (m_mode == QAudio::AudioOutput) ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE; + snd_pcm_t *handle; + + int card = 0; + int device = 0; + if (snd_pcm_open_preferred(&handle, &card, &device, pcmMode) < 0) + return false; + + snd_pcm_channel_info_t info; + memset (&info, 0, sizeof(info)); + info.channel = (m_mode == QAudio::AudioOutput) ? SND_PCM_CHANNEL_PLAYBACK : SND_PCM_CHANNEL_CAPTURE; + + if (snd_pcm_plugin_info(handle, &info) < 0) { + qWarning("QAudioDeviceInfo: couldn't get channel info"); + snd_pcm_close(handle); + return false; + } + + snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(format, m_mode, info.max_fragment_size); + const int errorCode = snd_pcm_plugin_params(handle, ¶ms); + snd_pcm_close(handle); + + return errorCode == 0; +} + +QString QnxAudioDeviceInfo::deviceName() const +{ + return m_name; +} + +QStringList QnxAudioDeviceInfo::supportedCodecs() +{ + return QStringList() << QLatin1String("audio/pcm"); +} + +QList QnxAudioDeviceInfo::supportedSampleRates() +{ + return QList() << 8000 << 11025 << 22050 << 44100 << 48000; +} + +QList QnxAudioDeviceInfo::supportedChannelCounts() +{ + return QList() << 1 << 2; +} + +QList QnxAudioDeviceInfo::supportedSampleSizes() +{ + return QList() << 8 << 16 << 32; +} + +QList QnxAudioDeviceInfo::supportedByteOrders() +{ + return QList() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian; +} + +QList QnxAudioDeviceInfo::supportedSampleTypes() +{ + return QList() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.h b/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.h new file mode 100644 index 000000000..72c10cc75 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudiodeviceinfo.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#ifndef QNXAUDIODEVICEINFO_H +#define QNXAUDIODEVICEINFO_H + +#include "qaudiosystem.h" + +QT_BEGIN_NAMESPACE + +class QnxAudioDeviceInfo : public QAbstractAudioDeviceInfo +{ + Q_OBJECT + +public: + QnxAudioDeviceInfo(const QString &deviceName, QAudio::Mode mode); + ~QnxAudioDeviceInfo(); + + QAudioFormat preferredFormat() const Q_DECL_OVERRIDE; + bool isFormatSupported(const QAudioFormat &format) const Q_DECL_OVERRIDE; + QString deviceName() const Q_DECL_OVERRIDE; + QStringList supportedCodecs() Q_DECL_OVERRIDE; + QList supportedSampleRates() Q_DECL_OVERRIDE; + QList supportedChannelCounts() Q_DECL_OVERRIDE; + QList supportedSampleSizes() Q_DECL_OVERRIDE; + QList supportedByteOrders() Q_DECL_OVERRIDE; + QList supportedSampleTypes() Q_DECL_OVERRIDE; + +private: + const QString m_name; + const QAudio::Mode m_mode; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx-audio/audio/qnxaudioinput.cpp b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp new file mode 100644 index 000000000..eb8064598 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#include "qnxaudioinput.h" + +#include "qnxaudioutils.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +QnxAudioInput::QnxAudioInput() + : m_audioSource(0) + , m_pcmHandle(0) + , m_pcmNotifier(0) + , m_error(QAudio::NoError) + , m_state(QAudio::StoppedState) + , m_bytesRead(0) + , m_elapsedTimeOffset(0) + , m_totalTimeValue(0) + , m_volume(qreal(1.0f)) + , m_bytesAvailable(0) + , m_bufferSize(0) + , m_periodSize(0) + , m_intervalTime(1000) + , m_pullMode(true) +{ +} + +QnxAudioInput::~QnxAudioInput() +{ + close(); +} + +void QnxAudioInput::start(QIODevice *device) +{ + if (m_state != QAudio::StoppedState) + close(); + + if (!m_pullMode && m_audioSource) + delete m_audioSource; + + m_pullMode = true; + m_audioSource = device; + + if (open()) { + setError(QAudio::NoError); + setState(QAudio::ActiveState); + } else { + setError(QAudio::OpenError); + setState(QAudio::StoppedState); + } +} + +QIODevice *QnxAudioInput::start() +{ + if (m_state != QAudio::StoppedState) + close(); + + if (!m_pullMode && m_audioSource) + delete m_audioSource; + + m_pullMode = false; + m_audioSource = new InputPrivate(this); + m_audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + + if (open()) { + setError(QAudio::NoError); + setState(QAudio::IdleState); + } else { + delete m_audioSource; + m_audioSource = 0; + + setError(QAudio::OpenError); + setState(QAudio::StoppedState); + } + + return m_audioSource; +} + +void QnxAudioInput::stop() +{ + if (m_state == QAudio::StoppedState) + return; + + setError(QAudio::NoError); + setState(QAudio::StoppedState); + close(); +} + +void QnxAudioInput::reset() +{ + stop(); + m_bytesAvailable = 0; +} + +void QnxAudioInput::suspend() +{ + if (m_pcmNotifier) + m_pcmNotifier->setEnabled(false); + + setState(QAudio::SuspendedState); +} + +void QnxAudioInput::resume() +{ + if (m_pcmNotifier) + m_pcmNotifier->setEnabled(true); + + if (m_pullMode) { + setState(QAudio::ActiveState); + } else { + setState(QAudio::IdleState); + } +} + +int QnxAudioInput::bytesReady() const +{ + return qMax(m_bytesAvailable, 0); +} + +int QnxAudioInput::periodSize() const +{ + return m_periodSize; +} + +void QnxAudioInput::setBufferSize(int bufferSize) +{ + m_bufferSize = bufferSize; +} + +int QnxAudioInput::bufferSize() const +{ + return m_bufferSize; +} + +void QnxAudioInput::setNotifyInterval(int milliSeconds) +{ + m_intervalTime = qMax(0, milliSeconds); +} + +int QnxAudioInput::notifyInterval() const +{ + return m_intervalTime; +} + +qint64 QnxAudioInput::processedUSecs() const +{ + return qint64(1000000) * m_format.framesForBytes(m_bytesRead) / m_format.sampleRate(); +} + +qint64 QnxAudioInput::elapsedUSecs() const +{ + if (m_state == QAudio::StoppedState) + return 0; + + return m_clockStamp.elapsed() * 1000; +} + +QAudio::Error QnxAudioInput::error() const +{ + return m_error; +} + +QAudio::State QnxAudioInput::state() const +{ + return m_state; +} + +void QnxAudioInput::setFormat(const QAudioFormat &format) +{ + if (m_state == QAudio::StoppedState) + m_format = format; +} + +QAudioFormat QnxAudioInput::format() const +{ + return m_format; +} + +void QnxAudioInput::setVolume(qreal volume) +{ + m_volume = qBound(qreal(0.0), volume, qreal(1.0)); +} + +qreal QnxAudioInput::volume() const +{ + return m_volume; +} + +void QnxAudioInput::userFeed() +{ + if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState) + return; + + deviceReady(); +} + +bool QnxAudioInput::deviceReady() +{ + if (m_pullMode) { + // reads some audio data and writes it to QIODevice + read(0, 0); + } else { + m_bytesAvailable = m_periodSize; + + // emits readyRead() so user will call read() on QIODevice to get some audio data + if (m_audioSource != 0) { + InputPrivate *input = qobject_cast(m_audioSource); + input->trigger(); + } + } + + if (m_state != QAudio::ActiveState) + return true; + + if (m_intervalTime && (m_timeStamp.elapsed() + m_elapsedTimeOffset) > m_intervalTime) { + emit notify(); + m_elapsedTimeOffset = m_timeStamp.elapsed() + m_elapsedTimeOffset - m_intervalTime; + m_timeStamp.restart(); + } + + return true; +} + +bool QnxAudioInput::open() +{ + if (!m_format.isValid() || m_format.sampleRate() <= 0) { + if (!m_format.isValid()) + qWarning("QnxAudioInput: open error, invalid format."); + else + qWarning("QnxAudioInput: open error, invalid sample rate (%d).", m_format.sampleRate()); + + return false; + } + + int errorCode = 0; + + int card = 0; + int device = 0; + if ((errorCode = snd_pcm_open_preferred(&m_pcmHandle, &card, &device, SND_PCM_OPEN_CAPTURE)) < 0) { + qWarning("QnxAudioInput: open error, couldn't open card (0x%x)", -errorCode); + return false; + } + + // Necessary so that bytesFree() which uses the "free" member of the status struct works + snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_DISABLE_MMAP); + + snd_pcm_channel_info_t info; + memset(&info, 0, sizeof(info)); + info.channel = SND_PCM_CHANNEL_CAPTURE; + if ((errorCode = snd_pcm_plugin_info(m_pcmHandle, &info)) < 0) { + qWarning("QnxAudioInput: open error, couldn't get channel info (0x%x)", -errorCode); + close(); + return false; + } + + snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudio::AudioInput, info.max_fragment_size); + + if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, ¶ms)) < 0) { + qWarning("QnxAudioInput: open error, couldn't set channel params (0x%x)", -errorCode); + close(); + return false; + } + + if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE)) < 0) { + qWarning("QnxAudioInput: open error, couldn't prepare channel (0x%x)", -errorCode); + close(); + return false; + } + + snd_pcm_channel_setup_t setup; + + memset(&setup, 0, sizeof(setup)); + setup.channel = SND_PCM_CHANNEL_CAPTURE; + if ((errorCode = snd_pcm_plugin_setup(m_pcmHandle, &setup)) < 0) { + qWarning("QnxAudioInput: open error, couldn't get channel setup (0x%x)", -errorCode); + close(); + return false; + } + + m_periodSize = qMin(2048, setup.buf.block.frag_size); + + m_clockStamp.restart(); + m_timeStamp.restart(); + m_elapsedTimeOffset = 0; + m_totalTimeValue = 0; + m_bytesRead = 0; + + m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE), + QSocketNotifier::Read, this); + connect(m_pcmNotifier, SIGNAL(activated(int)), SLOT(userFeed())); + + return true; +} + +void QnxAudioInput::close() +{ + if (m_pcmHandle) + snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE); + + if (m_pcmNotifier) { + delete m_pcmNotifier; + m_pcmNotifier = 0; + } + + if (m_pcmHandle) { + snd_pcm_close(m_pcmHandle); + m_pcmHandle = 0; + } + + if (!m_pullMode && m_audioSource) { + delete m_audioSource; + m_audioSource = 0; + } +} + +qint64 QnxAudioInput::read(char *data, qint64 len) +{ + int errorCode = 0; + QByteArray tempBuffer(m_periodSize, 0); + + const int actualRead = snd_pcm_plugin_read(m_pcmHandle, tempBuffer.data(), m_periodSize); + if (actualRead < 1) { + snd_pcm_channel_status_t status; + memset(&status, 0, sizeof(status)); + status.channel = SND_PCM_CHANNEL_CAPTURE; + if ((errorCode = snd_pcm_plugin_status(m_pcmHandle, &status)) < 0) { + qWarning("QnxAudioInput: read error, couldn't get plugin status (0x%x)", -errorCode); + close(); + setError(QAudio::FatalError); + setState(QAudio::StoppedState); + return -1; + } + + if (status.status == SND_PCM_STATUS_READY + || status.status == SND_PCM_STATUS_OVERRUN) { + if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE)) < 0) { + qWarning("QnxAudioInput: read error, couldn't prepare plugin (0x%x)", -errorCode); + close(); + setError(QAudio::FatalError); + setState(QAudio::StoppedState); + return -1; + } + } + } else { + setError(QAudio::NoError); + setState(QAudio::ActiveState); + } + + if (m_volume < 1.0f) + QAudioHelperInternal::qMultiplySamples(m_volume, m_format, tempBuffer.data(), tempBuffer.data(), actualRead); + + m_bytesRead += actualRead; + + if (m_pullMode) { + m_audioSource->write(tempBuffer.data(), actualRead); + } else { + memcpy(data, tempBuffer.data(), qMin(static_cast(actualRead), len)); + } + + m_bytesAvailable = 0; + + return actualRead; +} + +void QnxAudioInput::setError(QAudio::Error error) +{ + if (m_error == error) + return; + + m_error = error; + emit errorChanged(m_error); +} + +void QnxAudioInput::setState(QAudio::State state) +{ + if (m_state == state) + return; + + m_state = state; + emit stateChanged(m_state); +} + +InputPrivate::InputPrivate(QnxAudioInput *audio) + : m_audioDevice(audio) +{ +} + +qint64 InputPrivate::readData(char *data, qint64 len) +{ + return m_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(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx-audio/audio/qnxaudioinput.h b/src/plugins/qnx-audio/audio/qnxaudioinput.h new file mode 100644 index 000000000..3084b1de3 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioinput.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#ifndef QNXAUDIOINPUT_H +#define QNXAUDIOINPUT_H + +#include "qaudiosystem.h" + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QnxAudioInput : public QAbstractAudioInput +{ + Q_OBJECT + +public: + QnxAudioInput(); + ~QnxAudioInput(); + + void start(QIODevice*) Q_DECL_OVERRIDE; + QIODevice* start() Q_DECL_OVERRIDE; + void stop() Q_DECL_OVERRIDE; + void reset() Q_DECL_OVERRIDE; + void suspend() Q_DECL_OVERRIDE; + void resume() Q_DECL_OVERRIDE; + int bytesReady() const Q_DECL_OVERRIDE; + int periodSize() const Q_DECL_OVERRIDE; + void setBufferSize(int ) Q_DECL_OVERRIDE; + int bufferSize() const Q_DECL_OVERRIDE; + void setNotifyInterval(int ) Q_DECL_OVERRIDE; + int notifyInterval() const Q_DECL_OVERRIDE; + qint64 processedUSecs() const Q_DECL_OVERRIDE; + qint64 elapsedUSecs() const Q_DECL_OVERRIDE; + QAudio::Error error() const Q_DECL_OVERRIDE; + QAudio::State state() const Q_DECL_OVERRIDE; + void setFormat(const QAudioFormat&) Q_DECL_OVERRIDE; + QAudioFormat format() const Q_DECL_OVERRIDE; + void setVolume(qreal) Q_DECL_OVERRIDE; + qreal volume() const Q_DECL_OVERRIDE; + +private slots: + void userFeed(); + bool deviceReady(); + +private: + friend class InputPrivate; + + bool open(); + void close(); + qint64 read(char *data, qint64 len); + void setError(QAudio::Error error); + void setState(QAudio::State state); + + QTime m_timeStamp; + QTime m_clockStamp; + QAudioFormat m_format; + + QIODevice *m_audioSource; + snd_pcm_t *m_pcmHandle; + QSocketNotifier *m_pcmNotifier; + + QAudio::Error m_error; + QAudio::State m_state; + + qint64 m_bytesRead; + qint64 m_elapsedTimeOffset; + qint64 m_totalTimeValue; + + qreal m_volume; + + int m_bytesAvailable; + int m_bufferSize; + int m_periodSize; + int m_intervalTime; + + bool m_pullMode; +}; + +class InputPrivate : public QIODevice +{ + Q_OBJECT +public: + InputPrivate(QnxAudioInput *audio); + + qint64 readData(char *data, qint64 len) Q_DECL_OVERRIDE; + qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE; + + void trigger(); + +private: + QnxAudioInput *m_audioDevice; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp new file mode 100644 index 000000000..4a82e93bb --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp @@ -0,0 +1,443 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#include "qnxaudiooutput.h" + +#include "qnxaudioutils.h" + +#include + +QT_BEGIN_NAMESPACE + +QnxAudioOutput::QnxAudioOutput() + : m_source(0), + m_pushSource(false), + m_notifyInterval(1000), + m_error(QAudio::NoError), + m_state(QAudio::StoppedState), + m_volume(1.0), + m_periodSize(0), + m_pcmHandle(0), + m_bytesWritten(0), + m_intervalOffset(0) +{ + m_timer.setSingleShot(false); + m_timer.setInterval(20); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(pullData())); +} + +QnxAudioOutput::~QnxAudioOutput() +{ + stop(); +} + +void QnxAudioOutput::start(QIODevice *source) +{ + if (m_state != QAudio::StoppedState) + stop(); + + m_error = QAudio::NoError; + m_source = source; + m_pushSource = false; + + if (open()) { + setState(QAudio::ActiveState); + m_timer.start(); + } else { + setError(QAudio::OpenError); + setState(QAudio::StoppedState); + } +} + +QIODevice *QnxAudioOutput::start() +{ + if (m_state != QAudio::StoppedState) + stop(); + + m_error = QAudio::NoError; + m_source = new QnxPushIODevice(this); + m_source->open(QIODevice::WriteOnly|QIODevice::Unbuffered); + m_pushSource = true; + + if (open()) + setState(QAudio::IdleState); + else { + setError(QAudio::OpenError); + setState(QAudio::StoppedState); + } + + return m_source; +} + +void QnxAudioOutput::stop() +{ + if (m_state == QAudio::StoppedState) + return; + + setError(QAudio::NoError); + setState(QAudio::StoppedState); + close(); +} + +void QnxAudioOutput::reset() +{ + if (m_pcmHandle) + snd_pcm_playback_drain(m_pcmHandle); + stop(); +} + +void QnxAudioOutput::suspend() +{ + m_timer.stop(); + setState(QAudio::SuspendedState); +} + +void QnxAudioOutput::resume() +{ + if (m_pushSource) + setState(QAudio::IdleState); + else { + setState(QAudio::ActiveState); + m_timer.start(); + } +} + +int QnxAudioOutput::bytesFree() const +{ + if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState) + return 0; + + snd_pcm_channel_status_t status; + status.channel = SND_PCM_CHANNEL_PLAYBACK; + const int errorCode = snd_pcm_plugin_status(m_pcmHandle, &status); + + if (errorCode) + return 0; + else + return status.free; +} + +int QnxAudioOutput::periodSize() const +{ + return m_periodSize; +} + +void QnxAudioOutput::setNotifyInterval(int ms) +{ + m_notifyInterval = ms; +} + +int QnxAudioOutput::notifyInterval() const +{ + return m_notifyInterval; +} + +qint64 QnxAudioOutput::processedUSecs() const +{ + return qint64(1000000) * m_format.framesForBytes(m_bytesWritten) / m_format.sampleRate(); +} + +qint64 QnxAudioOutput::elapsedUSecs() const +{ + if (m_state == QAudio::StoppedState) + return 0; + else + return m_startTimeStamp.elapsed() * 1000; +} + +QAudio::Error QnxAudioOutput::error() const +{ + return m_error; +} + +QAudio::State QnxAudioOutput::state() const +{ + return m_state; +} + +void QnxAudioOutput::setFormat(const QAudioFormat &format) +{ + if (m_state == QAudio::StoppedState) + m_format = format; +} + +QAudioFormat QnxAudioOutput::format() const +{ + return m_format; +} + +void QnxAudioOutput::setVolume(qreal volume) +{ + m_volume = qBound(qreal(0.0), volume, qreal(1.0)); +} + +qreal QnxAudioOutput::volume() const +{ + return m_volume; +} + +void QnxAudioOutput::pullData() +{ + if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState) + return; + + const int bytesAvailable = bytesFree(); + const int frames = m_format.framesForBytes(bytesAvailable); + + if (frames == 0 || bytesAvailable < periodSize()) + return; + + const int bytesRequested = m_format.bytesForFrames(frames); + + char buffer[bytesRequested]; + const int bytesRead = m_source->read(buffer, bytesRequested); + + // reading can take a while and stream may have been stopped + if (!m_pcmHandle) + return; + + if (bytesRead > 0) { + // Got some data to output + if (m_state != QAudio::ActiveState) + return; + + const qint64 bytesWritten = write(buffer, bytesRead); + if (bytesWritten != bytesRead) + m_source->seek(m_source->pos()-(bytesRead-bytesWritten)); + + } else { + // We're done + close(); + if (bytesRead != 0) + setError(QAudio::IOError); + setState(QAudio::StoppedState); + } + + if (m_state != QAudio::ActiveState) + return; + + if (m_notifyInterval > 0 && (m_intervalTimeStamp.elapsed() + m_intervalOffset) > m_notifyInterval) { + emit notify(); + m_intervalOffset = m_intervalTimeStamp.elapsed() + m_intervalOffset - m_notifyInterval; + m_intervalTimeStamp.restart(); + } +} + +bool QnxAudioOutput::open() +{ + if (!m_format.isValid() || m_format.sampleRate() <= 0) { + if (!m_format.isValid()) + qWarning("QnxAudioOutput: open error, invalid format."); + else + qWarning("QnxAudioOutput: open error, invalid sample rate (%d).", m_format.sampleRate()); + + return false; + } + + int errorCode = 0; + + int card = 0; + int device = 0; + if ((errorCode = snd_pcm_open_preferred(&m_pcmHandle, &card, &device, SND_PCM_OPEN_PLAYBACK)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't open card (0x%x)", -errorCode); + return false; + } + + if ((errorCode = snd_pcm_nonblock_mode(m_pcmHandle, 0)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't set non block mode (0x%x)", -errorCode); + close(); + return false; + } + + // Necessary so that bytesFree() which uses the "free" member of the status struct works + snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_DISABLE_MMAP); + + snd_pcm_channel_info_t info; + memset(&info, 0, sizeof(info)); + info.channel = SND_PCM_CHANNEL_PLAYBACK; + if ((errorCode = snd_pcm_plugin_info(m_pcmHandle, &info)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't get channel info (0x%x)", -errorCode); + close(); + return false; + } + + snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudio::AudioOutput, info.max_fragment_size); + + if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, ¶ms)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't set channel params (0x%x)", -errorCode); + close(); + return false; + } + + if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't prepare channel (0x%x)", -errorCode); + close(); + return false; + } + + snd_pcm_channel_setup_t setup; + memset(&setup, 0, sizeof(setup)); + setup.channel = SND_PCM_CHANNEL_PLAYBACK; + if ((errorCode = snd_pcm_plugin_setup(m_pcmHandle, &setup)) < 0) { + qWarning("QnxAudioOutput: open error, couldn't get channel setup (0x%x)", -errorCode); + close(); + return false; + } + + m_periodSize = qMin(2048, setup.buf.block.frag_size); + m_startTimeStamp.restart(); + m_intervalTimeStamp.restart(); + m_intervalOffset = 0; + m_bytesWritten = 0; + + return true; +} + +void QnxAudioOutput::close() +{ + m_timer.stop(); + + if (m_pcmHandle) { + snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK); + snd_pcm_close(m_pcmHandle); + m_pcmHandle = 0; + } + + if (m_pushSource) { + delete m_source; + m_source = 0; + } +} + +void QnxAudioOutput::setError(QAudio::Error error) +{ + if (m_error != error) { + m_error = error; + emit errorChanged(error); + } +} + +void QnxAudioOutput::setState(QAudio::State state) +{ + if (m_state != state) { + m_state = state; + emit stateChanged(state); + } +} + +qint64 QnxAudioOutput::write(const char *data, qint64 len) +{ + if (!m_pcmHandle) + return 0; + + // Make sure we're writing (N * frame) worth of bytes + const int size = m_format.bytesForFrames(qBound(qint64(0), qint64(bytesFree()), len) / m_format.bytesPerFrame()); + + if (size == 0) + return 0; + + int written = 0; + + if (m_volume < 1.0f) { + char out[size]; + QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, out, size); + written = snd_pcm_plugin_write(m_pcmHandle, out, size); + } else { + written = snd_pcm_plugin_write(m_pcmHandle, data, size); + } + + if (written > 0) { + m_bytesWritten += written; + setError(QAudio::NoError); + setState(QAudio::ActiveState); + return written; + } else { + close(); + setError(QAudio::FatalError); + setState(QAudio::StoppedState); + return 0; + } +} + +QnxPushIODevice::QnxPushIODevice(QnxAudioOutput *output) + : QIODevice(output), + m_output(output) +{ +} + +QnxPushIODevice::~QnxPushIODevice() +{ +} + +qint64 QnxPushIODevice::readData(char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + return 0; +} + +qint64 QnxPushIODevice::writeData(const char *data, qint64 len) +{ + int retry = 0; + qint64 written = 0; + + if (m_output->state() == QAudio::ActiveState + || m_output->state() == QAudio::IdleState) { + while (written < len) { + const int writeSize = m_output->write(data + written, len - written); + + if (writeSize <= 0) { + retry++; + if (retry > 10) + return written; + else + continue; + } + + retry = 0; + written += writeSize; + } + } + + return written; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.h b/src/plugins/qnx-audio/audio/qnxaudiooutput.h new file mode 100644 index 000000000..77c15e47a --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#ifndef QNXAUDIOOUTPUT_H +#define QNXAUDIOOUTPUT_H + +#include "qaudiosystem.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QnxPushIODevice; + +class QnxAudioOutput : public QAbstractAudioOutput +{ + Q_OBJECT + +public: + QnxAudioOutput(); + ~QnxAudioOutput(); + + void start(QIODevice *source) Q_DECL_OVERRIDE; + QIODevice *start() Q_DECL_OVERRIDE; + void stop() Q_DECL_OVERRIDE; + void reset() Q_DECL_OVERRIDE; + void suspend() Q_DECL_OVERRIDE; + void resume() Q_DECL_OVERRIDE; + int bytesFree() const Q_DECL_OVERRIDE; + int periodSize() const Q_DECL_OVERRIDE; + void setBufferSize(int) Q_DECL_OVERRIDE {} + int bufferSize() const Q_DECL_OVERRIDE { return 0; } + void setNotifyInterval(int ms) Q_DECL_OVERRIDE; + int notifyInterval() const Q_DECL_OVERRIDE; + qint64 processedUSecs() const Q_DECL_OVERRIDE; + qint64 elapsedUSecs() const Q_DECL_OVERRIDE; + QAudio::Error error() const Q_DECL_OVERRIDE; + QAudio::State state() const Q_DECL_OVERRIDE; + void setFormat(const QAudioFormat &format) Q_DECL_OVERRIDE; + QAudioFormat format() const Q_DECL_OVERRIDE; + void setVolume(qreal volume) Q_DECL_OVERRIDE; + qreal volume() const Q_DECL_OVERRIDE; + +private slots: + void pullData(); + +private: + bool open(); + void close(); + void setError(QAudio::Error error); + void setState(QAudio::State state); + + friend class QnxPushIODevice; + qint64 write(const char *data, qint64 len); + + QIODevice *m_source; + bool m_pushSource; + QTimer m_timer; + + int m_notifyInterval; + QAudio::Error m_error; + QAudio::State m_state; + QAudioFormat m_format; + qreal m_volume; + int m_periodSize; + + snd_pcm_t *m_pcmHandle; + qint64 m_bytesWritten; + QTime m_startTimeStamp; + QTime m_intervalTimeStamp; + qint64 m_intervalOffset; +}; + +class QnxPushIODevice : public QIODevice +{ + Q_OBJECT +public: + explicit QnxPushIODevice(QnxAudioOutput *output); + ~QnxPushIODevice(); + + qint64 readData(char *data, qint64 len); + qint64 writeData(const char *data, qint64 len); + +private: + QnxAudioOutput *m_output; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx-audio/audio/qnxaudioplugin.cpp b/src/plugins/qnx-audio/audio/qnxaudioplugin.cpp new file mode 100644 index 000000000..f63474f90 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioplugin.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#include "qnxaudioplugin.h" + +#include "qnxaudiodeviceinfo.h" +#include "qnxaudioinput.h" +#include "qnxaudiooutput.h" + +#include + +static const char *INPUT_ID = "QnxAudioInput"; +static const char *OUTPUT_ID = "QnxAudioOutput"; + +QT_BEGIN_NAMESPACE + +QnxAudioPlugin::QnxAudioPlugin(QObject *parent) + : QAudioSystemPlugin(parent) +{ +} + +QList QnxAudioPlugin::availableDevices(QAudio::Mode mode) const +{ + if (mode == QAudio::AudioOutput) + return QList() << OUTPUT_ID; + else + return QList() << INPUT_ID; +} + +QAbstractAudioInput *QnxAudioPlugin::createInput(const QByteArray &device) +{ + Q_ASSERT(device == INPUT_ID); + Q_UNUSED(device); + return new QnxAudioInput(); +} + +QAbstractAudioOutput *QnxAudioPlugin::createOutput(const QByteArray &device) +{ + Q_ASSERT(device == OUTPUT_ID); + Q_UNUSED(device); + return new QnxAudioOutput(); +} + +QAbstractAudioDeviceInfo *QnxAudioPlugin::createDeviceInfo(const QByteArray &device, QAudio::Mode mode) +{ + Q_ASSERT(device == OUTPUT_ID || device == INPUT_ID); + return new QnxAudioDeviceInfo(device, mode); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx-audio/audio/qnxaudioplugin.h b/src/plugins/qnx-audio/audio/qnxaudioplugin.h new file mode 100644 index 000000000..1886057b4 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioplugin.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#ifndef QNXAUDIOPLUGIN_H +#define QNXAUDIOPLUGIN_H + +#include + +QT_BEGIN_NAMESPACE + +class QnxAudioPlugin : public QAudioSystemPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.qt.audiosystemfactory/5.0" FILE "qnx_audio.json") + +public: + explicit QnxAudioPlugin(QObject *parent = 0); + ~QnxAudioPlugin() {} + + QList availableDevices(QAudio::Mode mode) const Q_DECL_OVERRIDE; + QAbstractAudioInput *createInput(const QByteArray &device) Q_DECL_OVERRIDE; + QAbstractAudioOutput *createOutput(const QByteArray &device) Q_DECL_OVERRIDE; + QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode) Q_DECL_OVERRIDE; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx-audio/audio/qnxaudioutils.cpp b/src/plugins/qnx-audio/audio/qnxaudioutils.cpp new file mode 100644 index 000000000..d6400c2b1 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioutils.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#include "qnxaudioutils.h" + +QT_BEGIN_NAMESPACE + +snd_pcm_channel_params_t QnxAudioUtils::formatToChannelParams(const QAudioFormat &format, QAudio::Mode mode, int fragmentSize) +{ + snd_pcm_channel_params_t params; + memset(¶ms, 0, sizeof(params)); + params.channel = (mode == QAudio::AudioOutput) ? SND_PCM_CHANNEL_PLAYBACK : SND_PCM_CHANNEL_CAPTURE; + params.mode = SND_PCM_MODE_BLOCK; + params.start_mode = SND_PCM_START_DATA; + params.stop_mode = SND_PCM_STOP_ROLLOVER; + params.buf.block.frag_size = fragmentSize; + params.buf.block.frags_min = 1; + params.buf.block.frags_max = 1; + strcpy(params.sw_mixer_subchn_name, "QAudio Channel"); + + params.format.interleave = 1; + params.format.rate = format.sampleRate(); + params.format.voices = format.channelCount(); + + switch (format.sampleSize()) { + case 8: + switch (format.sampleType()) { + case QAudioFormat::SignedInt: + params.format.format = SND_PCM_SFMT_S8; + break; + case QAudioFormat::UnSignedInt: + params.format.format = SND_PCM_SFMT_U8; + break; + default: + break; + } + break; + + case 16: + switch (format.sampleType()) { + case QAudioFormat::SignedInt: + if (format.byteOrder() == QAudioFormat::LittleEndian) { + params.format.format = SND_PCM_SFMT_S16_LE; + } else { + params.format.format = SND_PCM_SFMT_S16_BE; + } + break; + case QAudioFormat::UnSignedInt: + if (format.byteOrder() == QAudioFormat::LittleEndian) { + params.format.format = SND_PCM_SFMT_U16_LE; + } else { + params.format.format = SND_PCM_SFMT_U16_BE; + } + break; + default: + break; + } + break; + + case 32: + switch (format.sampleType()) { + case QAudioFormat::SignedInt: + if (format.byteOrder() == QAudioFormat::LittleEndian) { + params.format.format = SND_PCM_SFMT_S32_LE; + } else { + params.format.format = SND_PCM_SFMT_S32_BE; + } + break; + case QAudioFormat::UnSignedInt: + if (format.byteOrder() == QAudioFormat::LittleEndian) { + params.format.format = SND_PCM_SFMT_U32_LE; + } else { + params.format.format = SND_PCM_SFMT_U32_BE; + } + break; + case QAudioFormat::Float: + if (format.byteOrder() == QAudioFormat::LittleEndian) { + params.format.format = SND_PCM_SFMT_FLOAT_LE; + } else { + params.format.format = SND_PCM_SFMT_FLOAT_BE; + } + break; + default: + break; + } + break; + } + + return params; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx-audio/audio/qnxaudioutils.h b/src/plugins/qnx-audio/audio/qnxaudioutils.h new file mode 100644 index 000000000..ddd30b191 --- /dev/null +++ b/src/plugins/qnx-audio/audio/qnxaudioutils.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion +** 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$ +** +****************************************************************************/ + +#ifndef QNXAUDIOUTILS_H +#define QNXAUDIOUTILS_H + +#include "qaudiosystem.h" +#include + +QT_BEGIN_NAMESPACE + +namespace QnxAudioUtils +{ + snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudio::Mode mode, int fragmentSize); +} + +QT_END_NAMESPACE + +#endif -- cgit v1.2.1