summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2021-05-12 13:19:07 +0200
committerLars Knoll <lars.knoll@qt.io>2021-05-18 08:41:44 +0000
commit202ce66b89e3924a81f5d2d63f217c8a72a41478 (patch)
tree1f06382f7ca13df080c1d6bb45f66e675b00d4e9
parentf6b68bb6834214dd3a05f95421b0ae5aa2404b03 (diff)
Fix a crash in the gstreamer audio output
Closing the audio output would delete the pipeline, and would lead to deleting the GstAppSrc from within QGstAppSrc::pushData(). Speed up the qsoundeffect autotest (this uncovered the issue). Change-Id: I3c5843854f5a74d563eb271df553c8a1a5854f63 Reviewed-by: André de la Rocha <andre.rocha@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
-rw-r--r--src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp46
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstappsrc.cpp17
-rw-r--r--tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp44
3 files changed, 58 insertions, 49 deletions
diff --git a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp
index eb74c2ee6..1b0fec46a 100644
--- a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp
+++ b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp
@@ -61,14 +61,35 @@ QGStreamerAudioOutput::QGStreamerAudioOutput(const QAudioDeviceInfo &device)
{
gstPipeline.installMessageFilter(this);
+ m_appSrc = new QGstAppSrc;
+ connect(m_appSrc, &QGstAppSrc::bytesProcessed, this, &QGStreamerAudioOutput::bytesProcessedByAppSrc);
+ connect(m_appSrc, &QGstAppSrc::noMoreData, this, &QGStreamerAudioOutput::needData);
+ gstAppSrc = m_appSrc->element();
+
+ // gstDecodeBin = gst_element_factory_make ("decodebin", "dec");
+ QGstElement conv("audioconvert", "conv");
+ gstVolume = QGstElement("volume", "volume");
+ if (m_volume != 1.)
+ gstVolume.set("volume", m_volume);
+
+ // link decodeBin to audioconvert in a callback once we get a pad from the decoder
+ // g_signal_connect (gstDecodeBin, "pad-added", (GCallback) padAdded, conv);
+
const auto *audioInfo = static_cast<const QGStreamerAudioDeviceInfo *>(device.handle());
gstOutput = gst_device_create_element(audioInfo->gstDevice, nullptr);
+
+ gstPipeline.add(gstAppSrc, /*gstDecodeBin, */ conv, gstVolume, gstOutput);
+ gstAppSrc.link(conv, gstVolume, gstOutput);
}
QGStreamerAudioOutput::~QGStreamerAudioOutput()
{
close();
- QCoreApplication::processEvents();
+ gstPipeline = {};
+ gstVolume = {};
+ gstAppSrc = {};
+ delete m_appSrc;
+ m_appSrc = nullptr;
}
void QGStreamerAudioOutput::setError(QAudio::Error error)
@@ -203,26 +224,9 @@ bool QGStreamerAudioOutput::open()
}
// qDebug() << "GST caps:" << gst_caps_to_string(caps);
- m_appSrc = new QGstAppSrc;
m_appSrc->setup(m_audioSource, m_audioSource ? m_audioSource->pos() : 0);
m_appSrc->setAudioFormat(m_format);
- connect(m_appSrc, &QGstAppSrc::bytesProcessed, this, &QGStreamerAudioOutput::bytesProcessedByAppSrc);
- connect(m_appSrc, &QGstAppSrc::noMoreData, this, &QGStreamerAudioOutput::needData);
- gstAppSrc = m_appSrc->element();
-
-// gstDecodeBin = gst_element_factory_make ("decodebin", "dec");
- QGstElement conv("audioconvert", "conv");
- gstVolume = QGstElement("volume", "volume");
- if (m_volume != 1.)
- gstVolume.set("volume", m_volume);
-
- gstPipeline.add(gstAppSrc, /*gstDecodeBin, */ conv, gstVolume, gstOutput);
- gstAppSrc.link(conv, gstVolume, gstOutput);
-
- // link decodeBin to audioconvert in a callback once we get a pad from the decoder
-// g_signal_connect (gstDecodeBin, "pad-added", (GCallback) padAdded, conv);
-
/* run */
gstPipeline.setState(GST_STATE_PLAYING);
@@ -239,10 +243,8 @@ void QGStreamerAudioOutput::close()
if (!m_opened)
return;
- gstPipeline.setStateSync(GST_STATE_NULL);
- gstPipeline = {};
- gstVolume = {};
- gstAppSrc = {};
+ if (!gstPipeline.setStateSync(GST_STATE_NULL))
+ qWarning() << "failed to close the audio output stream";
if (!m_pullMode && m_audioSource)
delete m_audioSource;
diff --git a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp b/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp
index 7ff9b177f..2cf33fbce 100644
--- a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp
+++ b/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp
@@ -56,6 +56,9 @@ QGstAppSrc::QGstAppSrc(QObject *parent)
QGstAppSrc::~QGstAppSrc()
{
+ m_appSrc.setStateSync(GST_STATE_NULL);
+ streamDestroyed();
+ qCDebug(qLcAppSrc) << "~QGstAppSrc";
}
bool QGstAppSrc::setup(QIODevice *stream, qint64 offset)
@@ -68,6 +71,7 @@ bool QGstAppSrc::setup(QIODevice *stream, qint64 offset)
auto *appSrc = GST_APP_SRC(m_appSrc.element());
GstAppSrcCallbacks m_callbacks;
+ memset(&m_callbacks, 0, sizeof(GstAppSrcCallbacks));
m_callbacks.need_data = &QGstAppSrc::on_need_data;
m_callbacks.enough_data = &QGstAppSrc::on_enough_data;
m_callbacks.seek_data = &QGstAppSrc::on_seek_data;
@@ -141,20 +145,20 @@ void QGstAppSrc::write(const char *data, qsizetype size)
Q_ASSERT(!m_stream);
m_buffer.append(data, size);
m_noMoreData = false;
- if (m_dataRequestSize)
- pushData();
+ pushData();
}
void QGstAppSrc::onDataReady()
{
qCDebug(qLcAppSrc) << "onDataReady" << m_stream->bytesAvailable() << m_stream->size();
- if (m_dataRequestSize)
- pushData();
+ pushData();
}
void QGstAppSrc::streamDestroyed()
{
+ qCDebug(qLcAppSrc) << "stream destroyed";
m_stream = nullptr;
+ m_dataRequestSize = 0;
sendEOS();
}
@@ -166,6 +170,7 @@ void QGstAppSrc::pushData()
qCDebug(qLcAppSrc) << "pushData" << m_stream << m_stream->atEnd() << m_buffer.size();
if ((m_stream && m_stream->atEnd())) {
eosOrIdle();
+ qCDebug(qLcAppSrc) << "end pushData" << m_stream << m_stream->atEnd() << m_buffer.size();
return;
}
@@ -213,6 +218,7 @@ void QGstAppSrc::pushData()
if (bytesRead == 0) {
gst_buffer_unref(buffer);
eosOrIdle();
+ qCDebug(qLcAppSrc) << "end pushData" << m_stream << m_stream->atEnd() << m_buffer.size();
return;
}
m_noMoreData = false;
@@ -224,6 +230,8 @@ void QGstAppSrc::pushData()
} else if (ret == GST_FLOW_FLUSHING) {
qWarning() << "QGstAppSrc: push buffer wrong state";
}
+ qCDebug(qLcAppSrc) << "end pushData" << m_stream << m_stream->atEnd() << m_buffer.size();
+
}
bool QGstAppSrc::doSeek(qint64 value)
@@ -264,6 +272,7 @@ void QGstAppSrc::on_need_data(GstAppSrc *, guint arg0, gpointer userdata)
Q_ASSERT(self);
self->m_dataRequestSize = arg0;
QMetaObject::invokeMethod(self, "pushData", Qt::AutoConnection);
+ qCDebug(qLcAppSrc) << "done on_need_data";
}
void QGstAppSrc::sendEOS()
diff --git a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
index 020daeea6..4367810fc 100644
--- a/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
+++ b/tests/auto/integration/qsoundeffect/tst_qsoundeffect.cpp
@@ -127,8 +127,8 @@ void tst_QSoundEffect::testSource()
QTestEventLoop::instance().enterLoop(1);
sound->play();
-
- QTest::qWait(3000);
+ QTRY_COMPARE(sound->isPlaying(), false);
+ QCOMPARE(sound->loopsRemaining(), 0);
}
void tst_QSoundEffect::testLooping()
@@ -139,9 +139,9 @@ void tst_QSoundEffect::testLooping()
QSignalSpy readSignal_Count(sound, SIGNAL(loopCountChanged()));
QSignalSpy readSignal_Remaining(sound, SIGNAL(loopsRemainingChanged()));
- sound->setLoopCount(5);
+ sound->setLoopCount(3);
sound->setVolume(0.1f);
- QCOMPARE(sound->loopCount(), 5);
+ QCOMPARE(sound->loopCount(), 3);
QCOMPARE(readSignal_Count.count(), 1);
QCOMPARE(sound->loopsRemaining(), 0);
QCOMPARE(readSignal_Remaining.count(), 0);
@@ -149,11 +149,11 @@ void tst_QSoundEffect::testLooping()
sound->play();
QVERIFY(readSignal_Remaining.count() > 0);
- // test.wav is about 200ms, wait until it has finished playing 5 times
+ // test.wav is about 200ms, wait until it has finished playing 3 times
QTestEventLoop::instance().enterLoop(3);
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QVERIFY(readSignal_Remaining.count() >= 6);
+ QVERIFY(readSignal_Remaining.count() == 4);
QTRY_VERIFY(!sound->isPlaying());
// QTBUG-36643 (setting the loop count while playing should work)
@@ -161,8 +161,8 @@ void tst_QSoundEffect::testLooping()
readSignal_Count.clear();
readSignal_Remaining.clear();
- sound->setLoopCount(30);
- QCOMPARE(sound->loopCount(), 30);
+ sound->setLoopCount(10);
+ QCOMPARE(sound->loopCount(), 10);
QCOMPARE(readSignal_Count.count(), 1);
QCOMPARE(sound->loopsRemaining(), 0);
QCOMPARE(readSignal_Remaining.count(), 0);
@@ -171,21 +171,21 @@ void tst_QSoundEffect::testLooping()
QVERIFY(readSignal_Remaining.count() > 0);
// wait for the sound to be played several times
- QTRY_VERIFY(sound->loopsRemaining() <= 20);
- QVERIFY(readSignal_Remaining.count() >= 10);
+ QTRY_VERIFY(sound->loopsRemaining() <= 7);
+ QVERIFY(readSignal_Remaining.count() >= 3);
readSignal_Count.clear();
readSignal_Remaining.clear();
// change the loop count while playing
- sound->setLoopCount(5);
- QCOMPARE(sound->loopCount(), 5);
+ sound->setLoopCount(3);
+ QCOMPARE(sound->loopCount(), 3);
QCOMPARE(readSignal_Count.count(), 1);
- QCOMPARE(sound->loopsRemaining(), 5);
+ QCOMPARE(sound->loopsRemaining(), 3);
QCOMPARE(readSignal_Remaining.count(), 1);
// wait for all the loops to be completed
QTRY_COMPARE(sound->loopsRemaining(), 0);
- QTRY_VERIFY(readSignal_Remaining.count() >= 6);
+ QTRY_VERIFY(readSignal_Remaining.count() == 4);
QTRY_VERIFY(!sound->isPlaying());
}
@@ -203,7 +203,7 @@ void tst_QSoundEffect::testLooping()
QTRY_COMPARE(sound->loopsRemaining(), int(QSoundEffect::Infinite));
QCOMPARE(readSignal_Remaining.count(), 1);
- QTest::qWait(1500);
+ QTest::qWait(500);
QVERIFY(sound->isPlaying());
readSignal_Count.clear();
readSignal_Remaining.clear();
@@ -228,8 +228,7 @@ void tst_QSoundEffect::testVolume()
sound->setVolume(0.5);
QCOMPARE(sound->volume(),0.5);
- QTest::qWait(20);
- QCOMPARE(readSignal.count(),1);
+ QTRY_COMPARE(readSignal.count(),1);
}
void tst_QSoundEffect::testMuting()
@@ -239,8 +238,7 @@ void tst_QSoundEffect::testMuting()
sound->setMuted(true);
QCOMPARE(sound->isMuted(),true);
- QTest::qWait(20);
- QCOMPARE(readSignal.count(),1);
+ QTRY_COMPARE(readSignal.count(),1);
}
void tst_QSoundEffect::testPlaying()
@@ -303,7 +301,7 @@ void tst_QSoundEffect::testDestroyWhilePlaying()
instance->setVolume(0.1f);
QTestEventLoop::instance().enterLoop(1);
instance->play();
- QTest::qWait(500);
+ QTest::qWait(100);
delete instance;
QTestEventLoop::instance().enterLoop(1);
}
@@ -315,7 +313,7 @@ void tst_QSoundEffect::testDestroyWhileRestartPlaying()
instance->setVolume(0.1f);
QTestEventLoop::instance().enterLoop(1);
instance->play();
- QTest::qWait(1000);
+ QTRY_COMPARE(instance->isPlaying(), false);
//restart playing
instance->play();
delete instance;
@@ -324,7 +322,7 @@ void tst_QSoundEffect::testDestroyWhileRestartPlaying()
void tst_QSoundEffect::testSetSourceWhileLoading()
{
- for (int i = 0; i < 10; i++) {
+ for (int i = 0; i < 2; i++) {
sound->setSource(url);
QVERIFY(sound->status() == QSoundEffect::Loading || sound->status() == QSoundEffect::Ready);
sound->setSource(url); // set same source again
@@ -352,7 +350,7 @@ void tst_QSoundEffect::testSetSourceWhileLoading()
void tst_QSoundEffect::testSetSourceWhilePlaying()
{
- for (int i = 0; i < 10; i++) {
+ for (int i = 0; i < 2; i++) {
sound->setSource(url);
QTRY_COMPARE(sound->status(), QSoundEffect::Ready);
sound->play();