summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/multimedia/spectrum/app/mainwidget.cpp7
-rw-r--r--src/multimedia/audio/qaudio.cpp22
-rw-r--r--src/multimedia/audio/qaudio.h2
-rw-r--r--src/plugins/qnx-audio/audio/qnxaudiooutput.cpp123
-rw-r--r--src/plugins/qnx-audio/audio/qnxaudiooutput.h14
5 files changed, 139 insertions, 29 deletions
diff --git a/examples/multimedia/spectrum/app/mainwidget.cpp b/examples/multimedia/spectrum/app/mainwidget.cpp
index a69c85a44..35b92d13e 100644
--- a/examples/multimedia/spectrum/app/mainwidget.cpp
+++ b/examples/multimedia/spectrum/app/mainwidget.cpp
@@ -109,7 +109,9 @@ void MainWidget::stateChanged(QAudio::Mode mode, QAudio::State state)
updateButtonStates();
- if (QAudio::ActiveState != state && QAudio::SuspendedState != state) {
+ if (QAudio::ActiveState != state &&
+ QAudio::SuspendedState != state &&
+ QAudio::InterruptedState != state) {
m_levelMeter->reset();
m_spectrograph->reset();
}
@@ -418,7 +420,8 @@ void MainWidget::updateButtonStates()
const bool playEnabled = (/*m_engine->dataLength() &&*/
(QAudio::AudioOutput != m_engine->mode() ||
(QAudio::ActiveState != m_engine->state() &&
- QAudio::IdleState != m_engine->state())));
+ QAudio::IdleState != m_engine->state() &&
+ QAudio::InterruptedState != m_engine->state())));
m_playButton->setEnabled(playEnabled);
}
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp
index d4f89e898..dea9a05a5 100644
--- a/src/multimedia/audio/qaudio.cpp
+++ b/src/multimedia/audio/qaudio.cpp
@@ -79,13 +79,18 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes)
/*!
\enum QAudio::State
- \value ActiveState Audio data is being processed, this state is set after start() is called
- and while audio data is available to be processed.
- \value SuspendedState The audio device is in a suspended state, this state will only be entered
- after suspend() is called.
- \value StoppedState The audio device is closed, and is not processing any audio data
- \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state
- is set after start() is called and while no audio data is available to be processed.
+ \value ActiveState Audio data is being processed, this state is set after start() is called
+ and while audio data is available to be processed.
+ \value SuspendedState The audio stream is in a suspended state. Entered after suspend() is called
+ or when another stream takes control of the audio device. In the later case,
+ a call to resume will return control of the audio device to this stream. This
+ should usually only be done upon user request.
+ \value StoppedState The audio device is closed, and is not processing any audio data
+ \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state
+ is set after start() is called and while no audio data is available to be processed.
+ \value InterruptedState 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.
*/
/*!
@@ -285,6 +290,9 @@ QDebug operator<<(QDebug dbg, QAudio::State state)
case QAudio::IdleState:
dbg << "IdleState";
break;
+ case QAudio::InterruptedState:
+ dbg << "InterruptedState";
+ break;
}
return dbg;
}
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
index 1c38e9f35..2603d71d1 100644
--- a/src/multimedia/audio/qaudio.h
+++ b/src/multimedia/audio/qaudio.h
@@ -55,7 +55,7 @@ class QString;
namespace QAudio
{
enum Error { NoError, OpenError, IOError, UnderrunError, FatalError };
- enum State { ActiveState, SuspendedState, StoppedState, IdleState };
+ enum State { ActiveState, SuspendedState, StoppedState, IdleState, InterruptedState };
enum Mode { AudioInput, AudioOutput };
enum Role {
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