summaryrefslogtreecommitdiffstats
path: root/src/plugins/qnx-audio
diff options
context:
space:
mode:
authorJames McDonnell <jmcdonnell@blackberry.com>2017-03-24 11:34:30 -0400
committerJames McDonnell <jmcdonnell@blackberry.com>2017-03-27 19:04:01 +0000
commit883df8dfda760fdbe850303383ba098887abbf62 (patch)
tree1839f3e9aa41e97217795ac83242a9eb70191da7 /src/plugins/qnx-audio
parent1221f6a7e3767e14d2afdfc806120953bd6535be (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.cpp123
-rw-r--r--src/plugins/qnx-audio/audio/qnxaudiooutput.h14
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