6#include <private/qaudiohelpers_p.h>
7#include <sys/asoundlib.h>
8#include <sys/asound_common.h>
13#pragma GCC diagnostic ignored "-Wvla"
23 , m_state(
QAudio::StoppedState)
24 , m_suspendedInState(
QAudio::SuspendedState)
28 , m_requestedBufferSize(0)
29 , m_deviceInfo(deviceInfo)
40 m_requestedBufferSize =
info->max_fragment_size;
95#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
96 snd_pcm_playback_drain(m_pcmHandle.get());
98 snd_pcm_channel_drain(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
108 snd_pcm_playback_pause(m_pcmHandle.get());
117 snd_pcm_playback_resume(m_pcmHandle.get());
123 m_requestedBufferSize = std::clamp<qsizetype>(
bufferSize, 0, std::numeric_limits<int>::max());
128 const std::optional<snd_pcm_channel_setup_t> setup = m_pcmHandle
132 return setup ? setup->buf.block.frag_size : m_requestedBufferSize;
143 return status ? status->free : 0;
182void QQnxAudioSink::updateState()
196void QQnxAudioSink::pullData()
214 char buffer[bytesRequested];
215 const int bytesRead = m_source->
read(
buffer, bytesRequested);
239bool QQnxAudioSink::open()
243 qWarning(
"QQnxAudioSink: open error, invalid format.");
245 qWarning(
"QQnxAudioSink: open error, invalid sample rate (%d).", m_format.
sampleRate());
258 if ((errorCode = snd_pcm_nonblock_mode(m_pcmHandle.get(), 0)) < 0) {
259 qWarning(
"QQnxAudioSink: open error, couldn't set non block mode (0x%x)", -errorCode);
267 snd_pcm_plugin_set_disable(m_pcmHandle.get(), PLUGIN_MMAP);
277 const int fragmentSize = std::clamp(m_requestedBufferSize,
278 info->min_fragment_size,
info->max_fragment_size);
283 if ((errorCode = snd_pcm_plugin_params(m_pcmHandle.get(), &
params)) < 0) {
284 qWarning(
"QQnxAudioSink: open error, couldn't set channel params (0x%x)", -errorCode);
289 if ((errorCode = snd_pcm_plugin_prepare(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK)) < 0) {
290 qWarning(
"QQnxAudioSink: open error, couldn't prepare channel (0x%x)", -errorCode);
303 m_periodSize =
qMin(2048, setup->buf.block.frag_size);
306 createPcmNotifiers();
311void QQnxAudioSink::close()
316 destroyPcmNotifiers();
319#if SND_PCM_VERSION < SND_PROTOCOL_VERSION('P',3,0,2)
320 snd_pcm_plugin_flush(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
322 snd_pcm_plugin_drop(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK);
324 m_pcmHandle =
nullptr;
335 if (m_state !=
state) {
340 if (m_error !=
error) {
360 constexpr int maxRetries = 10;
362 while (totalWritten <
len) {
368 if (retry >= maxRetries) {
399 if (m_volume < 1.0f) {
402 written = snd_pcm_plugin_write(m_pcmHandle.get(),
out,
size);
404 written = snd_pcm_plugin_write(m_pcmHandle.get(),
data,
size);
408 m_bytesWritten += written;
420 m_suspendedInState = m_state;
424void QQnxAudioSink::resumeInternal()
434 Q_ASSERT(
event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED);
438void QQnxAudioSink::addPcmEventFilter()
443 filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) |
444 (1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) |
445 (1<<SND_PCM_EVENT_OUTPUTCLASS) |
446 (1<<SND_PCM_EVENT_UNDERRUN);
447 snd_pcm_set_filter(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK, &
filter);
450void QQnxAudioSink::createPcmNotifiers()
454 m_pcmNotifier =
new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle.get(),
455 SND_PCM_CHANNEL_PLAYBACK),
458 this, &QQnxAudioSink::pcmNotifierActivated);
461void QQnxAudioSink::destroyPcmNotifiers()
464 delete m_pcmNotifier;
469void QQnxAudioSink::pcmNotifierActivated(
int socket)
473 snd_pcm_event_t pcm_event;
474 memset(&pcm_event, 0,
sizeof(pcm_event));
475 while (snd_pcm_channel_read_event(m_pcmHandle.get(), SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) {
476 if (pcm_event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS) {
477 if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED)
479 else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_RUNNING)
481 else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_PAUSED)
483 }
else if (pcm_event.type == SND_PCM_EVENT_UNDERRUN) {
The QAudioDevice class provides an information about audio devices and their functionality.
QByteArray id
\qmlproperty string QtMultimedia::audioDevice::id
void stateChanged(QAudio::State state)
void errorChanged(QAudio::Error error)
\inmodule QtCore \reentrant
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
QAudio::State state() const override
qint64 pushData(const char *data, qint64 len)
void setBufferSize(qsizetype) override
qreal volume() const override
void setFormat(const QAudioFormat &format) override
qsizetype bufferSize() const override
qsizetype bytesFree() const override
QIODevice * start() override
QQnxAudioSink(const QAudioDevice &deviceInfo, QObject *parent)
QAudioFormat format() const override
void setVolume(qreal volume) override
QAudio::Error error() const override
qint64 processedUSecs() const override
void activated(QSocketDescriptor socket, QSocketNotifier::Type activationEvent, QPrivateSignal)
void setSingleShot(bool singleShot)
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void setInterval(int msec)
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
QnxPushIODevice(QQnxAudioSink *output)
qint64 writeData(const char *data, qint64 len)
Writes up to maxSize bytes from data to the device.
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
qint64 readData(char *data, qint64 len)
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
void qMultiplySamples(qreal factor, const QAudioFormat &format, const void *src, void *dest, int len)
Combined button and popup list for selecting options.
std::optional< snd_pcm_channel_info_t > pcmChannelInfo(snd_pcm_t *handle, QAudioDevice::Mode mode)
std::optional< snd_pcm_channel_setup_t > pcmChannelSetup(snd_pcm_t *handle, QAudioDevice::Mode mode)
HandleUniquePtr openPcmDevice(const QByteArray &id, QAudioDevice::Mode mode)
std::optional< snd_pcm_channel_status_t > pcmChannelStatus(snd_pcm_t *handle, QAudioDevice::Mode mode)
snd_pcm_channel_params_t formatToChannelParams(const QAudioFormat &format, QAudioDevice::Mode mode, int fragmentSize)
DBusConnection const char DBusError * error
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
GLenum GLsizei GLuint GLint * bytesWritten
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLint GLsizei GLsizei GLenum format
GLsizei GLsizei GLchar * source
QAudio::State suspendState(const snd_pcm_event_t &event)
QT_BEGIN_NAMESPACE typedef uchar * output
QTextStream out(stdout)
[7]