diff options
author | James McDonnell <jmcdonnell@blackberry.com> | 2017-03-24 11:34:30 -0400 |
---|---|---|
committer | James McDonnell <jmcdonnell@blackberry.com> | 2017-03-27 19:04:01 +0000 |
commit | 883df8dfda760fdbe850303383ba098887abbf62 (patch) | |
tree | 1839f3e9aa41e97217795ac83242a9eb70191da7 /src/plugins/qnx-audio | |
parent | 1221f6a7e3767e14d2afdfc806120953bd6535be (diff) |
io-audio based audio management for QNX 7.0.0
Add code to setup and handle io-audio based audio management
notifications.
Add InterruptedState to QAudio::State. Indicates that this
stream is in a suspended state because another higher priority
stream currently has control of the audio device. Playback
cannot resume until the higher priority stream relinquishes
control of the audio device.
Adjust the documentation for QAudio::State SuspendedState to
reflect the fact that audio management events can also put the
stream into this state.
Add InterruptedState handling to the spectrum example.
Change-Id: Ie8616af03ae4c503de1d0571a222e5853035cc0e
Reviewed-by: Yoann Lopes <yoann.lopes@qt.io>
Diffstat (limited to 'src/plugins/qnx-audio')
-rw-r--r-- | src/plugins/qnx-audio/audio/qnxaudiooutput.cpp | 123 | ||||
-rw-r--r-- | src/plugins/qnx-audio/audio/qnxaudiooutput.h | 14 |
2 files changed, 118 insertions, 19 deletions
diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp index 084c5b371..c4c09f543 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp @@ -43,19 +43,24 @@ #include <private/qaudiohelpers_p.h> +#pragma GCC diagnostic ignored "-Wvla" + 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_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) +#if _NTO_VERSION >= 700 + , m_pcmNotifier(0) +#endif { m_timer.setSingleShot(false); m_timer.setInterval(20); @@ -124,20 +129,16 @@ void QnxAudioOutput::reset() void QnxAudioOutput::suspend() { - m_timer.stop(); snd_pcm_playback_pause(m_pcmHandle); - setState(QAudio::SuspendedState); + if (state() != QAudio::InterruptedState) + suspendInternal(QAudio::SuspendedState); } void QnxAudioOutput::resume() { snd_pcm_playback_resume(m_pcmHandle); - if (m_pushSource) - setState(QAudio::IdleState); - else { - setState(QAudio::ActiveState); - m_timer.start(); - } + if (state() != QAudio::InterruptedState) + resumeInternal(); } int QnxAudioOutput::bytesFree() const @@ -146,6 +147,7 @@ int QnxAudioOutput::bytesFree() const return 0; snd_pcm_channel_status_t status; + memset(&status, 0, sizeof(status)); status.channel = SND_PCM_CHANNEL_PLAYBACK; const int errorCode = snd_pcm_plugin_status(m_pcmHandle, &status); @@ -226,7 +228,9 @@ QString QnxAudioOutput::category() const void QnxAudioOutput::pullData() { - if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState) + if (m_state == QAudio::StoppedState + || m_state == QAudio::SuspendedState + || m_state == QAudio::InterruptedState) return; const int bytesAvailable = bytesFree(); @@ -300,6 +304,8 @@ bool QnxAudioOutput::open() return false; } + addPcmEventFilter(); + // Necessary so that bytesFree() which uses the "free" member of the status struct works snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_MMAP); @@ -342,6 +348,8 @@ bool QnxAudioOutput::open() m_intervalOffset = 0; m_bytesWritten = 0; + createPcmNotifiers(); + return true; } @@ -349,6 +357,8 @@ void QnxAudioOutput::close() { m_timer.stop(); + destroyPcmNotifiers(); + if (m_pcmHandle) { snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK); snd_pcm_close(m_pcmHandle); @@ -411,8 +421,62 @@ qint64 QnxAudioOutput::write(const char *data, qint64 len) } } +void QnxAudioOutput::suspendInternal(QAudio::State suspendState) +{ + m_timer.stop(); + setState(suspendState); +} + +void QnxAudioOutput::resumeInternal() +{ + if (m_pushSource) { + setState(QAudio::IdleState); + } else { + setState(QAudio::ActiveState); + m_timer.start(); + } +} + #if _NTO_VERSION >= 700 +QAudio::State suspendState(const snd_pcm_event_t &event) +{ + Q_ASSERT(event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS); + Q_ASSERT(event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED); + return event.data.audiomgmt_status.flags & SND_PCM_STATUS_EVENT_HARD_SUSPEND + ? QAudio::InterruptedState : QAudio::SuspendedState; +} + +void QnxAudioOutput::addPcmEventFilter() +{ + /* Enable PCM events */ + snd_pcm_filter_t filter; + memset(&filter, 0, sizeof(filter)); + filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) | + (1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) | + (1<<SND_PCM_EVENT_OUTPUTCLASS); + snd_pcm_set_filter(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &filter); +} + +void QnxAudioOutput::createPcmNotifiers() +{ + // QSocketNotifier::Read for poll based event dispatcher. Exception for + // select based event dispatcher. + m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, + SND_PCM_CHANNEL_PLAYBACK), + QSocketNotifier::Read, this); + connect(m_pcmNotifier, &QSocketNotifier::activated, + this, &QnxAudioOutput::pcmNotifierActivated); +} + +void QnxAudioOutput::destroyPcmNotifiers() +{ + if (m_pcmNotifier) { + delete m_pcmNotifier; + m_pcmNotifier = 0; + } +} + void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *params) { if (m_category.isEmpty()) @@ -433,8 +497,29 @@ void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *params) strcpy(params->audio_type_name, latin1Category.constData()); } +void QnxAudioOutput::pcmNotifierActivated(int socket) +{ + Q_UNUSED(socket); + + snd_pcm_event_t pcm_event; + memset(&pcm_event, 0, sizeof(pcm_event)); + while (snd_pcm_channel_read_event(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) { + if (pcm_event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS) { + if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED) + suspendInternal(suspendState(pcm_event)); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_RUNNING) + resumeInternal(); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_PAUSED) + suspendInternal(QAudio::SuspendedState); + } + } +} + #else +void QnxAudioOutput::addPcmEventFilter() {} +void QnxAudioOutput::createPcmNotifiers() {} +void QnxAudioOutput::destroyPcmNotifiers() {} void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *) {} #endif diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.h b/src/plugins/qnx-audio/audio/qnxaudiooutput.h index c4fe37516..85aadf4b9 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.h +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.h @@ -45,6 +45,7 @@ #include <QTime> #include <QTimer> #include <QIODevice> +#include <QSocketNotifier> #include <sys/asoundlib.h> #include <sys/neutrino.h> @@ -93,8 +94,14 @@ private: void setError(QAudio::Error error); void setState(QAudio::State state); + void addPcmEventFilter(); + void createPcmNotifiers(); + void destroyPcmNotifiers(); void setTypeName(snd_pcm_channel_params_t *params); + void suspendInternal(QAudio::State suspendState); + void resumeInternal(); + friend class QnxPushIODevice; qint64 write(const char *data, qint64 len); @@ -115,6 +122,13 @@ private: QTime m_startTimeStamp; QTime m_intervalTimeStamp; qint64 m_intervalOffset; + +#if _NTO_VERSION >= 700 + QSocketNotifier *m_pcmNotifier; + +private slots: + void pcmNotifierActivated(int socket); +#endif }; class QnxPushIODevice : public QIODevice |