From b4d03dc82f6d282582dda2137fadd54f97d3b9a7 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 25 Nov 2015 16:27:08 +0100 Subject: GStreamer: fix GstAppSrc usage. Allow our GstAppSrc wrapper to be reconfigured with a new GstAppSrc object. This is necessary because that object changes every time playback is restarted, even for the same source. The consequence of not allowing the reconfigure was that playback for a given qrc media would only work the first time; any subsequent calls to play() would not work since our wrapper wouldn't know about the new GstAppSrc object and therefore wouldn't be able to produce any data. Also improved management of the wrapper lifecycle. Task-number: QTBUG-49531 Change-Id: I905afb6848cc7e9a563b4edc2c5875cdd7e53d21 Reviewed-by: Christian Stromme --- src/gsttools/qgstappsrc.cpp | 39 +++++++++++++--------- src/multimedia/gsttools_headers/qgstappsrc_p.h | 2 -- .../audiodecoder/qgstreameraudiodecodersession.cpp | 8 ++--- .../mediaplayer/qgstreamerplayersession.cpp | 19 ++++++++--- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/gsttools/qgstappsrc.cpp b/src/gsttools/qgstappsrc.cpp index 66c384992..c2b2faeb1 100644 --- a/src/gsttools/qgstappsrc.cpp +++ b/src/gsttools/qgstappsrc.cpp @@ -41,7 +41,6 @@ QGstAppSrc::QGstAppSrc(QObject *parent) ,m_appSrc(0) ,m_sequential(false) ,m_maxBytes(0) - ,m_setup(false) ,m_dataRequestSize(~0) ,m_dataRequested(false) ,m_enoughData(false) @@ -60,11 +59,13 @@ QGstAppSrc::~QGstAppSrc() bool QGstAppSrc::setup(GstElement* appsrc) { - if (m_setup || m_stream == 0 || appsrc == 0) - return false; - - if (m_appSrc) + if (m_appSrc) { gst_object_unref(G_OBJECT(m_appSrc)); + m_appSrc = 0; + } + + if (!appsrc || !m_stream) + return false; m_appSrc = GST_APP_SRC(appsrc); gst_object_ref(G_OBJECT(m_appSrc)); @@ -79,32 +80,35 @@ bool QGstAppSrc::setup(GstElement* appsrc) gst_app_src_set_stream_type(m_appSrc, m_streamType); gst_app_src_set_size(m_appSrc, (m_sequential) ? -1 : m_stream->size()); - return m_setup = true; + return true; } void QGstAppSrc::setStream(QIODevice *stream) { - if (stream == 0) - return; if (m_stream) { disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); disconnect(m_stream, SIGNAL(destroyed()), this, SLOT(streamDestroyed())); + m_stream = 0; } - if (m_appSrc) + + if (m_appSrc) { gst_object_unref(G_OBJECT(m_appSrc)); + m_appSrc = 0; + } m_dataRequestSize = ~0; m_dataRequested = false; m_enoughData = false; m_forceData = false; + m_sequential = false; m_maxBytes = 0; - m_appSrc = 0; - m_stream = stream; - connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed())); - connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); - m_sequential = m_stream->isSequential(); - m_setup = false; + if (stream) { + m_stream = stream; + connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed())); + connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); + m_sequential = m_stream->isSequential(); + } } QIODevice *QGstAppSrc::stream() const @@ -135,7 +139,7 @@ void QGstAppSrc::streamDestroyed() void QGstAppSrc::pushDataToAppSrc() { - if (!isStreamValid() || !m_setup) + if (!isStreamValid() || !m_appSrc) return; if (m_dataRequested && !m_enoughData) { @@ -242,6 +246,9 @@ void QGstAppSrc::destroy_notify(gpointer data) void QGstAppSrc::sendEOS() { + if (!m_appSrc) + return; + gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc)); if (isStreamValid() && !stream()->isSequential()) stream()->reset(); diff --git a/src/multimedia/gsttools_headers/qgstappsrc_p.h b/src/multimedia/gsttools_headers/qgstappsrc_p.h index ec54af0d1..c5f94ea32 100644 --- a/src/multimedia/gsttools_headers/qgstappsrc_p.h +++ b/src/multimedia/gsttools_headers/qgstappsrc_p.h @@ -54,7 +54,6 @@ public: ~QGstAppSrc(); bool setup(GstElement *); - bool isReady() const { return m_setup; } void setStream(QIODevice *); QIODevice *stream() const; @@ -93,7 +92,6 @@ private: GstAppStreamType m_streamType; GstAppSrcCallbacks m_callbacks; qint64 m_maxBytes; - bool m_setup; unsigned int m_dataRequestSize; bool m_dataRequested; bool m_enoughData; diff --git a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp index efa8dcb47..3360583c4 100644 --- a/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp +++ b/src/plugins/gstreamer/audiodecoder/qgstreameraudiodecodersession.cpp @@ -142,9 +142,6 @@ void QGstreamerAudioDecoderSession::configureAppSrcElement(GObject* object, GObj if (!self->appsrc()) return; - if (self->appsrc()->isReady()) - return; - GstElement *appsrc; g_object_get(orig, "source", &appsrc, NULL); @@ -350,9 +347,8 @@ void QGstreamerAudioDecoderSession::start() return; } - if (m_appSrc) - m_appSrc->deleteLater(); - m_appSrc = new QGstAppSrc(this); + if (!m_appSrc) + m_appSrc = new QGstAppSrc(this); m_appSrc->setStream(mDevice); g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", NULL); diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp index c3d20e790..a1eee0166 100644 --- a/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayersession.cpp @@ -241,6 +241,10 @@ QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) g_signal_connect(G_OBJECT(m_playbin), "video-changed", G_CALLBACK(handleStreamsChange), this); g_signal_connect(G_OBJECT(m_playbin), "audio-changed", G_CALLBACK(handleStreamsChange), this); g_signal_connect(G_OBJECT(m_playbin), "text-changed", G_CALLBACK(handleStreamsChange), this); + +#if defined(HAVE_GST_APPSRC) + g_signal_connect(G_OBJECT(m_playbin), "deep-notify::source", G_CALLBACK(configureAppSrcElement), this); +#endif } } @@ -274,7 +278,7 @@ void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *o Q_UNUSED(object); Q_UNUSED(pspec); - if (self->appsrc()->isReady()) + if (!self->appsrc()) return; GstElement *appsrc; @@ -298,16 +302,14 @@ void QGstreamerPlayerSession::loadFromStream(const QNetworkRequest &request, QIO m_lastPosition = 0; m_isPlaylist = false; - if (m_appSrc) - m_appSrc->deleteLater(); - m_appSrc = new QGstAppSrc(this); + if (!m_appSrc) + m_appSrc = new QGstAppSrc(this); m_appSrc->setStream(appSrcStream); if (m_playbin) { m_tags.clear(); emit tagsChanged(); - g_signal_connect(G_OBJECT(m_playbin), "deep-notify::source", (GCallback) &QGstreamerPlayerSession::configureAppSrcElement, (gpointer)this); g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", NULL); if (!m_streamTypes.isEmpty()) { @@ -330,6 +332,13 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) m_lastPosition = 0; m_isPlaylist = false; +#if defined(HAVE_GST_APPSRC) + if (m_appSrc) { + m_appSrc->deleteLater(); + m_appSrc = 0; + } +#endif + if (m_playbin) { m_tags.clear(); emit tagsChanged(); -- cgit v1.2.3 From f97c4aaa86a8a0a5694e0e534892e7a3aa76d2ca Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jan 2016 13:35:33 +0100 Subject: WindowsAudio: fix QAudioOutput state after resume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In push mode, the state must be IdleState after resume(), and only change to ActiveState once it receives some data. Task-number: QTBUG-50390 Change-Id: I0e12f4eaff350b9423e44779f229e0e1061cf576 Reviewed-by: Pasi Petäjäjärvi --- src/plugins/windowsaudio/qwindowsaudiooutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp index 7e2205dea..22746a63a 100644 --- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp @@ -434,7 +434,7 @@ qint64 QWindowsAudioOutput::write( const char *data, qint64 len ) void QWindowsAudioOutput::resume() { if(deviceState == QAudio::SuspendedState) { - deviceState = QAudio::ActiveState; + deviceState = pullMode ? QAudio::ActiveState : QAudio::IdleState; errorState = QAudio::NoError; waveOutRestart(hWaveOut); QTimer::singleShot(10, this, SLOT(feedback())); -- cgit v1.2.3 From 94c846fb48baec9f1a6ddcc974d6db61c95658d8 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jan 2016 13:58:06 +0100 Subject: CoreAudio: fix QAudioOutput state after resume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In push mode, the state must be IdleState after resume(), and only change to ActiveState once it receives some data. Task-number: QTBUG-50390 Change-Id: I4a38aa84a55e90d7a2db3e1d504674b2a688bbde Reviewed-by: Pasi Petäjäjärvi --- src/plugins/coreaudio/coreaudiooutput.h | 1 + src/plugins/coreaudio/coreaudiooutput.mm | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreaudio/coreaudiooutput.h b/src/plugins/coreaudio/coreaudiooutput.h index 4b4b781f5..cc391f783 100644 --- a/src/plugins/coreaudio/coreaudiooutput.h +++ b/src/plugins/coreaudio/coreaudiooutput.h @@ -187,6 +187,7 @@ private: QTimer *m_intervalTimer; CoreAudioDeviceInfo *m_audioDeviceInfo; qreal m_cachedVolume; + bool m_pullMode; QAudio::Error m_errorCode; QAudio::State m_stateCode; diff --git a/src/plugins/coreaudio/coreaudiooutput.mm b/src/plugins/coreaudio/coreaudiooutput.mm index 149b5a8c0..2db26297a 100644 --- a/src/plugins/coreaudio/coreaudiooutput.mm +++ b/src/plugins/coreaudio/coreaudiooutput.mm @@ -222,6 +222,7 @@ CoreAudioOutput::CoreAudioOutput(const QByteArray &device) , m_startTime(0) , m_audioBuffer(0) , m_cachedVolume(1.0) + , m_pullMode(false) , m_errorCode(QAudio::NoError) , m_stateCode(QAudio::StoppedState) { @@ -271,6 +272,7 @@ void CoreAudioOutput::start(QIODevice *device) m_stateCode = QAudio::ActiveState; // Start + m_pullMode = true; m_errorCode = QAudio::NoError; m_totalFrames = 0; m_startTime = CoreAudioUtils::currentTime(); @@ -296,6 +298,7 @@ QIODevice *CoreAudioOutput::start() m_stateCode = QAudio::IdleState; // Start + m_pullMode = false; m_errorCode = QAudio::NoError; m_totalFrames = 0; m_startTime = CoreAudioUtils::currentTime(); @@ -347,7 +350,7 @@ void CoreAudioOutput::resume() if (m_stateCode == QAudio::SuspendedState) { audioThreadStart(); - m_stateCode = QAudio::ActiveState; + m_stateCode = m_pullMode ? QAudio::ActiveState : QAudio::IdleState; m_errorCode = QAudio::NoError; emit stateChanged(m_stateCode); } -- cgit v1.2.3 From 627e488d548878ddfcddc2689c74dbf0fa52518b Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jan 2016 14:08:55 +0100 Subject: PulseAudio: fix QAudioOutput state after resume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In push mode, the state must be IdleState after resume(), and only change to ActiveState once it receives some data. Change-Id: I8caff011f517e91629abf45af51580f24136bcea Task-number: QTBUG-50390 Reviewed-by: Pasi Petäjäjärvi --- src/plugins/pulseaudio/qaudiooutput_pulse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp index 533cd674c..a654af86c 100644 --- a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp +++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp @@ -555,7 +555,7 @@ void QPulseAudioOutput::resume() m_tickTimer->start(m_periodTime); - setState(QAudio::ActiveState); + setState(m_pullMode ? QAudio::ActiveState : QAudio::IdleState); setError(QAudio::NoError); } } -- cgit v1.2.3 From 4fd2b2f6849cda72cdcc06aa0907bc565875f6dd Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jan 2016 14:12:19 +0100 Subject: Alsa: fix QAudioOutput state after resume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In push mode, the state must be IdleState after resume(), and only change to ActiveState once it receives some data. Task-number: QTBUG-50390 Change-Id: Idd08d8826f00d943b3bf750524f811874e010149 Reviewed-by: Pasi Petäjäjärvi --- src/plugins/alsa/qalsaaudiooutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index f8f0f58e8..a382b666a 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -651,7 +651,7 @@ void QAlsaAudioOutput::resume() } resuming = true; - deviceState = QAudio::ActiveState; + deviceState = pullMode ? QAudio::ActiveState : QAudio::IdleState; errorState = QAudio::NoError; timer->start(period_time/1000); -- cgit v1.2.3 From e126dbb6fb7440882b49fb2fcbde53f4b0a5e180 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jan 2016 14:15:40 +0100 Subject: OpenSL ES: fix QAudioOutput state after resume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In push mode, the state must be IdleState after resume(), and only change to ActiveState once it receives some data. Task-number: QTBUG-50390 Change-Id: Iaf47363196ee94b80ac4ebe58a588929af8d3fad Reviewed-by: Pasi Petäjäjärvi --- src/plugins/opensles/qopenslesaudiooutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index d17363d20..b12908c39 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -238,7 +238,7 @@ void QOpenSLESAudioOutput::resume() return; } - setState(QAudio::ActiveState); + setState(m_pullMode ? QAudio::ActiveState : QAudio::IdleState); setError(QAudio::NoError); } -- cgit v1.2.3 From 42dc97388137b753fbe7dc77371a51dfbd98d127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pasi=20Pet=C3=A4j=C3=A4j=C3=A4rvi?= Date: Mon, 11 Jan 2016 13:52:50 +0200 Subject: Fix tst_QAudioOutput::pushSuspendResume(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation states that state in push mode after suspend and resume should be QAudio::IdleState. Task-number: QTBUG-50390 Change-Id: I214f1808948ce862b62afd0fb9d245d0c7e4ad26 Reviewed-by: Pasi Petäjäjärvi --- tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp index 07043e9ce..b887d3f9a 100755 --- a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp +++ b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp @@ -825,10 +825,10 @@ void tst_QAudioOutput::pushSuspendResume() // but not too much or the rest of the file may be processed QTest::qWait(20); - // Check that QAudioOutput immediately transitions to ActiveState + // Check that QAudioOutput immediately transitions to IdleState QVERIFY2((stateSignal.count() == 1), QString("didn't emit signal after resume(), got %1 signals instead").arg(stateSignal.count()).toLocal8Bit().constData()); - QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after resume()"); + QVERIFY2((audioOutput.state() == QAudio::IdleState), "didn't transition to IdleState after resume()"); QVERIFY2((audioOutput.error() == QAudio::NoError), "error state is not equal to QAudio::NoError after resume()"); stateSignal.clear(); @@ -837,6 +837,7 @@ void tst_QAudioOutput::pushSuspendResume() if (audioOutput.bytesFree() >= audioOutput.periodSize()) { qint64 len = audioFile->read(buffer.data(),audioOutput.periodSize()); written += feed->write(buffer.constData(), len); + QVERIFY2((audioOutput.state() == QAudio::ActiveState), "didn't transition to ActiveState after writing audio data"); } else QTest::qWait(20); } -- cgit v1.2.3