summaryrefslogtreecommitdiffstats
path: root/src/plugins/multimedia/gstreamer/audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/multimedia/gstreamer/audio')
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp391
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h22
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp25
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h18
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp381
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h124
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp369
-rw-r--r--src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h120
8 files changed, 249 insertions, 1201 deletions
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
index 240c69b5b..ba1582877 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder.cpp
@@ -21,8 +21,6 @@
#include <QtCore/qurl.h>
#include <QtCore/qloggingcategory.h>
-#define MAX_BUFFERS_IN_QUEUE 4
-
QT_BEGIN_NAMESPACE
static Q_LOGGING_CATEGORY(qLcGstreamerAudioDecoder, "qt.multimedia.gstreameraudiodecoder");
@@ -42,23 +40,22 @@ typedef enum {
QMaybe<QPlatformAudioDecoder *> QGstreamerAudioDecoder::create(QAudioDecoder *parent)
{
- QGstElement audioconvert = QGstElement::createFromFactory("audioconvert", "audioconvert");
- if (!audioconvert)
- return errorMessageCannotFindElement("audioconvert");
-
- QGstPipeline playbin = QGstPipeline::adopt(
- GST_PIPELINE_CAST(QGstElement::createFromFactory("playbin", "playbin").element()));
- if (!playbin)
- return errorMessageCannotFindElement("playbin");
+ static const auto error = qGstErrorMessageIfElementsNotAvailable("audioconvert", "playbin");
+ if (error)
+ return *error;
- return new QGstreamerAudioDecoder(playbin, audioconvert, parent);
+ return new QGstreamerAudioDecoder(parent);
}
-QGstreamerAudioDecoder::QGstreamerAudioDecoder(QGstPipeline playbin, QGstElement audioconvert,
- QAudioDecoder *parent)
+QGstreamerAudioDecoder::QGstreamerAudioDecoder(QAudioDecoder *parent)
: QPlatformAudioDecoder(parent),
- m_playbin(std::move(playbin)),
- m_audioConvert(std::move(audioconvert))
+ m_playbin{
+ QGstPipeline::adopt(GST_PIPELINE_CAST(
+ QGstElement::createFromFactory("playbin", "playbin").element())),
+ },
+ m_audioConvert{
+ QGstElement::createFromFactory("audioconvert", "audioconvert"),
+ }
{
// Sort out messages
m_playbin.installMessageFilter(this);
@@ -73,8 +70,9 @@ QGstreamerAudioDecoder::QGstreamerAudioDecoder(QGstPipeline playbin, QGstElement
m_outputBin.addGhostPad(m_audioConvert, "sink");
g_object_set(m_playbin.object(), "audio-sink", m_outputBin.element(), NULL);
- g_signal_connect(m_playbin.object(), "deep-notify::source",
- (GCallback)&QGstreamerAudioDecoder::configureAppSrcElement, (gpointer)this);
+
+ m_deepNotifySourceConnection = m_playbin.connect(
+ "deep-notify::source", (GCallback)&configureAppSrcElement, (gpointer)this);
// Set volume to 100%
gdouble volume = 1.0;
@@ -115,63 +113,24 @@ void QGstreamerAudioDecoder::configureAppSrcElement([[maybe_unused]] GObject *ob
bool QGstreamerAudioDecoder::processBusMessage(const QGstreamerMessage &message)
{
- if (message.isNull())
- return false;
-
- constexpr bool extendedMessageTracing = false;
-
qCDebug(qLcGstreamerAudioDecoder) << "received bus message:" << message;
GstMessage *gm = message.message();
- if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_DURATION) {
+ switch (message.type()) {
+ case GST_MESSAGE_DURATION: {
updateDuration();
- } else if (GST_MESSAGE_SRC(gm) == m_playbin.object()) {
- switch (GST_MESSAGE_TYPE(gm)) {
- case GST_MESSAGE_STATE_CHANGED: {
- GstState oldState;
- GstState newState;
- GstState pending;
-
- gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
-
- if constexpr (extendedMessageTracing)
- qCDebug(qLcGstreamerAudioDecoder) << " state changed message from" << oldState
- << "to" << newState << pending;
-
- bool isDecoding = false;
- switch (newState) {
- case GST_STATE_VOID_PENDING:
- case GST_STATE_NULL:
- case GST_STATE_READY:
- break;
- case GST_STATE_PLAYING:
- isDecoding = true;
- break;
- case GST_STATE_PAUSED:
- isDecoding = true;
-
- // gstreamer doesn't give a reliable indication the duration
- // information is ready, GST_MESSAGE_DURATION is not sent by most elements
- // the duration is queried up to 5 times with increasing delay
- m_durationQueries = 5;
- updateDuration();
- break;
- }
+ return false;
+ }
- setIsDecoding(isDecoding);
- break;
- };
+ case GST_MESSAGE_ERROR: {
+ qCDebug(qLcGstreamerAudioDecoder) << " error" << QCompactGstMessageAdaptor(message);
- case GST_MESSAGE_EOS:
- m_playbin.setState(GST_STATE_NULL);
- finished();
- break;
+ QUniqueGErrorHandle err;
+ QGString debug;
+ gst_message_parse_error(gm, &err, &debug);
- case GST_MESSAGE_ERROR: {
- QUniqueGErrorHandle err;
- QGString debug;
- gst_message_parse_error(gm, &err, &debug);
+ if (message.source() == m_playbin) {
if (err.get()->domain == GST_STREAM_ERROR
&& err.get()->code == GST_STREAM_ERROR_CODEC_NOT_FOUND)
processInvalidMedia(QAudioDecoder::FormatError,
@@ -179,63 +138,103 @@ bool QGstreamerAudioDecoder::processBusMessage(const QGstreamerMessage &message)
else
processInvalidMedia(QAudioDecoder::ResourceError,
QString::fromUtf8(err.get()->message));
- qCWarning(qLcGstreamerAudioDecoder) << "Error:" << err;
- break;
+ } else {
+ QAudioDecoder::Error qerror = QAudioDecoder::ResourceError;
+ if (err.get()->domain == GST_STREAM_ERROR) {
+ switch (err.get()->code) {
+ case GST_STREAM_ERROR_DECRYPT:
+ case GST_STREAM_ERROR_DECRYPT_NOKEY:
+ qerror = QAudioDecoder::AccessDeniedError;
+ break;
+ case GST_STREAM_ERROR_FORMAT:
+ case GST_STREAM_ERROR_DEMUX:
+ case GST_STREAM_ERROR_DECODE:
+ case GST_STREAM_ERROR_WRONG_TYPE:
+ case GST_STREAM_ERROR_TYPE_NOT_FOUND:
+ case GST_STREAM_ERROR_CODEC_NOT_FOUND:
+ qerror = QAudioDecoder::FormatError;
+ break;
+ default:
+ break;
+ }
+ } else if (err.get()->domain == GST_CORE_ERROR) {
+ switch (err.get()->code) {
+ case GST_CORE_ERROR_MISSING_PLUGIN:
+ qerror = QAudioDecoder::FormatError;
+ break;
+ default:
+ break;
+ }
+ }
+
+ processInvalidMedia(qerror, QString::fromUtf8(err.get()->message));
}
- case GST_MESSAGE_WARNING: {
- QUniqueGErrorHandle err;
- QGString debug;
- gst_message_parse_warning(gm, &err, &debug);
- qCWarning(qLcGstreamerAudioDecoder) << "Warning:" << err;
+ break;
+ }
+
+ default:
+ if (message.source() == m_playbin)
+ return handlePlaybinMessage(message);
+ }
+
+ return false;
+}
+
+bool QGstreamerAudioDecoder::handlePlaybinMessage(const QGstreamerMessage &message)
+{
+ GstMessage *gm = message.message();
+
+ switch (GST_MESSAGE_TYPE(gm)) {
+ case GST_MESSAGE_STATE_CHANGED: {
+ GstState oldState;
+ GstState newState;
+ GstState pending;
+
+ gst_message_parse_state_changed(gm, &oldState, &newState, &pending);
+
+ bool isDecoding = false;
+ switch (newState) {
+ case GST_STATE_VOID_PENDING:
+ case GST_STATE_NULL:
+ case GST_STATE_READY:
break;
- }
- case GST_MESSAGE_INFO: {
- if (qLcGstreamerAudioDecoder().isDebugEnabled()) {
- QUniqueGErrorHandle err;
- QGString debug;
- gst_message_parse_info(gm, &err, &debug);
- qDebug() << "Info:" << err;
- }
+ case GST_STATE_PLAYING:
+ isDecoding = true;
break;
- }
- default:
+ case GST_STATE_PAUSED:
+ isDecoding = true;
+
+ // gstreamer doesn't give a reliable indication the duration
+ // information is ready, GST_MESSAGE_DURATION is not sent by most elements
+ // the duration is queried up to 5 times with increasing delay
+ m_durationQueries = 5;
+ updateDuration();
break;
}
- } else if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ERROR) {
- QUniqueGErrorHandle err;
- QGString debug;
- gst_message_parse_error(gm, &err, &debug);
- qCDebug(qLcGstreamerAudioDecoder) << " error" << err << debug;
-
- QAudioDecoder::Error qerror = QAudioDecoder::ResourceError;
- if (err.get()->domain == GST_STREAM_ERROR) {
- switch (err.get()->code) {
- case GST_STREAM_ERROR_DECRYPT:
- case GST_STREAM_ERROR_DECRYPT_NOKEY:
- qerror = QAudioDecoder::AccessDeniedError;
- break;
- case GST_STREAM_ERROR_FORMAT:
- case GST_STREAM_ERROR_DEMUX:
- case GST_STREAM_ERROR_DECODE:
- case GST_STREAM_ERROR_WRONG_TYPE:
- case GST_STREAM_ERROR_TYPE_NOT_FOUND:
- case GST_STREAM_ERROR_CODEC_NOT_FOUND:
- qerror = QAudioDecoder::FormatError;
- break;
- default:
- break;
- }
- } else if (err.get()->domain == GST_CORE_ERROR) {
- switch (err.get()->code) {
- case GST_CORE_ERROR_MISSING_PLUGIN:
- qerror = QAudioDecoder::FormatError;
- break;
- default:
- break;
- }
- }
- processInvalidMedia(qerror, QString::fromUtf8(err.get()->message));
+ setIsDecoding(isDecoding);
+ break;
+ };
+
+ case GST_MESSAGE_EOS:
+ m_playbin.setState(GST_STATE_NULL);
+ finished();
+ break;
+
+ case GST_MESSAGE_ERROR:
+ Q_UNREACHABLE_RETURN(false); // handled in processBusMessage
+
+ case GST_MESSAGE_WARNING:
+ qCWarning(qLcGstreamerAudioDecoder) << "Warning:" << QCompactGstMessageAdaptor(message);
+ break;
+
+ case GST_MESSAGE_INFO: {
+ if (qLcGstreamerAudioDecoder().isDebugEnabled())
+ qCWarning(qLcGstreamerAudioDecoder) << "Info:" << QCompactGstMessageAdaptor(message);
+ break;
+ }
+ default:
+ break;
}
return false;
@@ -325,6 +324,7 @@ void QGstreamerAudioDecoder::start()
void QGstreamerAudioDecoder::stop()
{
m_playbin.setState(GST_STATE_NULL);
+ m_currentSessionId += 1;
removeAppSink();
// GStreamer thread is stopped. Can safely access m_buffersAvailable
@@ -333,14 +333,14 @@ void QGstreamerAudioDecoder::stop()
bufferAvailableChanged(false);
}
- if (m_position != -1) {
- m_position = -1;
- positionChanged(m_position);
+ if (m_position != invalidPosition) {
+ m_position = invalidPosition;
+ positionChanged(m_position.count());
}
- if (m_duration != -1) {
- m_duration = -1;
- durationChanged(m_duration);
+ if (m_duration != invalidDuration) {
+ m_duration = invalidDuration;
+ durationChanged(m_duration.count());
}
setIsDecoding(false);
@@ -361,65 +361,54 @@ void QGstreamerAudioDecoder::setAudioFormat(const QAudioFormat &format)
QAudioBuffer QGstreamerAudioDecoder::read()
{
+ using namespace std::chrono;
+
QAudioBuffer audioBuffer;
- int buffersAvailable;
- {
- QMutexLocker locker(&m_buffersMutex);
- buffersAvailable = m_buffersAvailable;
+ if (m_buffersAvailable == 0)
+ return audioBuffer;
- // need to decrement before pulling a buffer
- // to make sure assert in QGstreamerAudioDecoderControl::new_buffer works
- m_buffersAvailable--;
- }
+ m_buffersAvailable -= 1;
+ if (m_buffersAvailable == 0)
+ bufferAvailableChanged(false);
- if (buffersAvailable) {
- if (buffersAvailable == 1)
- bufferAvailableChanged(false);
-
- const char* bufferData = nullptr;
- int bufferSize = 0;
-
- QGstSampleHandle sample = m_appSink.pullSample();
- GstBuffer *buffer = gst_sample_get_buffer(sample.get());
- GstMapInfo mapInfo;
- gst_buffer_map(buffer, &mapInfo, GST_MAP_READ);
- bufferData = (const char*)mapInfo.data;
- bufferSize = mapInfo.size;
- QAudioFormat format = QGstUtils::audioFormatForSample(sample.get());
-
- if (format.isValid()) {
- // XXX At the moment we have to copy data from GstBuffer into QAudioBuffer.
- // We could improve performance by implementing QAbstractAudioBuffer for GstBuffer.
- qint64 position = getPositionFromBuffer(buffer);
- audioBuffer = QAudioBuffer(QByteArray((const char*)bufferData, bufferSize), format, position);
- position /= 1000; // convert to milliseconds
- if (position != m_position) {
- m_position = position;
- positionChanged(m_position);
- }
+ QGstSampleHandle sample = m_appSink.pullSample();
+ GstBuffer *buffer = gst_sample_get_buffer(sample.get());
+ GstMapInfo mapInfo;
+ gst_buffer_map(buffer, &mapInfo, GST_MAP_READ);
+ const char *bufferData = (const char *)mapInfo.data;
+ int bufferSize = mapInfo.size;
+ QAudioFormat format = QGstUtils::audioFormatForSample(sample.get());
+
+ if (format.isValid()) {
+ // XXX At the moment we have to copy data from GstBuffer into QAudioBuffer.
+ // We could improve performance by implementing QAbstractAudioBuffer for GstBuffer.
+ nanoseconds position = getPositionFromBuffer(buffer);
+ audioBuffer = QAudioBuffer{
+ QByteArray(bufferData, bufferSize),
+ format,
+ round<microseconds>(position).count(),
+ };
+ milliseconds positionInMs = round<milliseconds>(position);
+ if (position != m_position) {
+ m_position = positionInMs;
+ positionChanged(m_position.count());
}
- gst_buffer_unmap(buffer, &mapInfo);
}
+ gst_buffer_unmap(buffer, &mapInfo);
return audioBuffer;
}
-bool QGstreamerAudioDecoder::bufferAvailable() const
-{
- QMutexLocker locker(&m_buffersMutex);
- return m_buffersAvailable > 0;
-}
-
qint64 QGstreamerAudioDecoder::position() const
{
- return m_position;
+ return m_position.count();
}
qint64 QGstreamerAudioDecoder::duration() const
{
- return m_duration;
+ return m_duration.count();
}
void QGstreamerAudioDecoder::processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString)
@@ -428,30 +417,30 @@ void QGstreamerAudioDecoder::processInvalidMedia(QAudioDecoder::Error errorCode,
error(int(errorCode), errorString);
}
-GstFlowReturn QGstreamerAudioDecoder::new_sample(GstAppSink *, gpointer user_data)
+GstFlowReturn QGstreamerAudioDecoder::newSample(GstAppSink *)
{
- qCDebug(qLcGstreamerAudioDecoder) << "QGstreamerAudioDecoder::new_sample";
-
// "Note that the preroll buffer will also be returned as the first buffer when calling
// gst_app_sink_pull_buffer()."
- QGstreamerAudioDecoder *decoder = reinterpret_cast<QGstreamerAudioDecoder*>(user_data);
-
- int buffersAvailable;
- {
- QMutexLocker locker(&decoder->m_buffersMutex);
- buffersAvailable = decoder->m_buffersAvailable;
- decoder->m_buffersAvailable++;
- Q_ASSERT(decoder->m_buffersAvailable <= MAX_BUFFERS_IN_QUEUE);
- }
- qCDebug(qLcGstreamerAudioDecoder) << "QGstreamerAudioDecoder::new_sample" << buffersAvailable;
+ QMetaObject::invokeMethod(this, [this, sessionId = m_currentSessionId] {
+ if (sessionId != m_currentSessionId)
+ return; // stop()ed before message is executed
+
+ m_buffersAvailable += 1;
+ bufferAvailableChanged(true);
+ bufferReady();
+ });
- if (!buffersAvailable)
- decoder->bufferAvailableChanged(true);
- decoder->bufferReady();
return GST_FLOW_OK;
}
+GstFlowReturn QGstreamerAudioDecoder::new_sample(GstAppSink *sink, gpointer user_data)
+{
+ QGstreamerAudioDecoder *decoder = reinterpret_cast<QGstreamerAudioDecoder *>(user_data);
+ qCDebug(qLcGstreamerAudioDecoder) << "QGstreamerAudioDecoder::new_sample";
+ return decoder->newSample(sink);
+}
+
void QGstreamerAudioDecoder::setAudioFlags(bool wantNativeAudio)
{
int flags = m_playbin.getInt("flags");
@@ -466,6 +455,8 @@ void QGstreamerAudioDecoder::setAudioFlags(bool wantNativeAudio)
void QGstreamerAudioDecoder::addAppSink()
{
+ using namespace std::chrono_literals;
+
if (m_appSink)
return;
@@ -474,8 +465,17 @@ void QGstreamerAudioDecoder::addAppSink()
GstAppSinkCallbacks callbacks{};
callbacks.new_sample = new_sample;
m_appSink.setCallbacks(callbacks, this, nullptr);
- gst_app_sink_set_max_buffers(m_appSink.appSink(), MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(m_appSink.baseSink(), FALSE);
+
+#if GST_CHECK_VERSION(1, 24, 0)
+ static constexpr auto maxBufferTime = 500ms;
+ m_appSink.setMaxBufferTime(maxBufferTime);
+#else
+ static constexpr int maxBuffers = 16;
+ m_appSink.setMaxBuffers(maxBuffers);
+#endif
+
+ static constexpr bool sync = false;
+ m_appSink.setSync(sync);
QGstPipeline::modifyPipelineWhileNotRunning(m_playbin.getPipeline(), [&] {
m_outputBin.add(m_appSink);
@@ -499,32 +499,35 @@ void QGstreamerAudioDecoder::removeAppSink()
void QGstreamerAudioDecoder::updateDuration()
{
- int duration = m_playbin.duration() / 1000000;
+ std::optional<std::chrono::milliseconds> duration = m_playbin.durationInMs();
+ if (!duration)
+ duration = invalidDuration;
if (m_duration != duration) {
- m_duration = duration;
- durationChanged(m_duration);
+ m_duration = *duration;
+ durationChanged(m_duration.count());
}
- if (m_duration > 0)
+ if (m_duration.count() > 0)
m_durationQueries = 0;
if (m_durationQueries > 0) {
//increase delay between duration requests
int delay = 25 << (5 - m_durationQueries);
- QTimer::singleShot(delay, this, SLOT(updateDuration()));
+ QTimer::singleShot(delay, this, &QGstreamerAudioDecoder::updateDuration);
m_durationQueries--;
}
}
-qint64 QGstreamerAudioDecoder::getPositionFromBuffer(GstBuffer* buffer)
+std::chrono::nanoseconds QGstreamerAudioDecoder::getPositionFromBuffer(GstBuffer *buffer)
{
- qint64 position = GST_BUFFER_TIMESTAMP(buffer);
- if (position >= 0)
- position = position / G_GINT64_CONSTANT(1000); // microseconds
+ using namespace std::chrono;
+ using namespace std::chrono_literals;
+ nanoseconds position{ GST_BUFFER_TIMESTAMP(buffer) };
+ if (position >= 0ns)
+ return position;
else
- position = -1;
- return position;
+ return invalidPosition;
}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
index c45e9f309..a5e192a38 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodecoder_p.h
@@ -57,7 +57,6 @@ public:
void setAudioFormat(const QAudioFormat &format) override;
QAudioBuffer read() override;
- bool bufferAvailable() const override;
qint64 position() const override;
qint64 duration() const override;
@@ -69,10 +68,12 @@ private slots:
void updateDuration();
private:
- QGstreamerAudioDecoder(QGstPipeline playbin, QGstElement audioconvert, QAudioDecoder *parent);
+ explicit QGstreamerAudioDecoder(QAudioDecoder *parent);
#if QT_CONFIG(gstreamer_app)
static GstFlowReturn new_sample(GstAppSink *sink, gpointer user_data);
+ GstFlowReturn newSample(GstAppSink *sink);
+
static void configureAppSrcElement(GObject *, GObject *, GParamSpec *,
QGstreamerAudioDecoder *_this);
#endif
@@ -81,8 +82,10 @@ private:
void addAppSink();
void removeAppSink();
- void processInvalidMedia(QAudioDecoder::Error errorCode, const QString& errorString);
- static qint64 getPositionFromBuffer(GstBuffer* buffer);
+ bool handlePlaybinMessage(const QGstreamerMessage &);
+
+ void processInvalidMedia(QAudioDecoder::Error errorCode, const QString &errorString);
+ static std::chrono::nanoseconds getPositionFromBuffer(GstBuffer *buffer);
QGstPipeline m_playbin;
QGstBin m_outputBin;
@@ -94,13 +97,18 @@ private:
QIODevice *mDevice = nullptr;
QAudioFormat mFormat;
- mutable QMutex m_buffersMutex;
int m_buffersAvailable = 0;
- qint64 m_position = -1;
- qint64 m_duration = -1;
+ static constexpr auto invalidDuration = std::chrono::milliseconds{ -1 };
+ static constexpr auto invalidPosition = std::chrono::milliseconds{ -1 };
+ std::chrono::milliseconds m_position{ invalidPosition };
+ std::chrono::milliseconds m_duration{ invalidDuration };
int m_durationQueries = 0;
+
+ qint32 m_currentSessionId{};
+
+ QGObjectHandlerScopedConnection m_deepNotifySourceConnection;
};
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
index 2c6b57e55..dc6975030 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice.cpp
@@ -49,6 +49,29 @@ QGStreamerAudioDeviceInfo::QGStreamerAudioDeviceInfo(GstDevice *d, const QByteAr
preferredFormat.setSampleFormat(f);
}
-QGStreamerAudioDeviceInfo::~QGStreamerAudioDeviceInfo() = default;
+QGStreamerCustomAudioDeviceInfo::QGStreamerCustomAudioDeviceInfo(
+ const QByteArray &gstreamerPipeline, QAudioDevice::Mode mode)
+ : QAudioDevicePrivate{
+ gstreamerPipeline,
+ mode,
+ }
+{
+}
+
+QAudioDevice qMakeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline)
+{
+ auto deviceInfo = std::make_unique<QGStreamerCustomAudioDeviceInfo>(gstreamerPipeline,
+ QAudioDevice::Mode::Input);
+
+ return deviceInfo.release()->create();
+}
+
+QAudioDevice qMakeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline)
+{
+ auto deviceInfo = std::make_unique<QGStreamerCustomAudioDeviceInfo>(gstreamerPipeline,
+ QAudioDevice::Mode::Output);
+
+ return deviceInfo.release()->create();
+}
QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
index dee0c40bc..34d25bceb 100644
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
+++ b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiodevice_p.h
@@ -19,11 +19,11 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qlist.h>
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiodevice_p.h>
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodevice.h>
+#include <QtMultimedia/private/qaudiodevice_p.h>
-#include <common/qgst_handle_types_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_handle_types_p.h>
#include <gst/gst.h>
@@ -33,11 +33,19 @@ class QGStreamerAudioDeviceInfo : public QAudioDevicePrivate
{
public:
QGStreamerAudioDeviceInfo(GstDevice *gstDevice, const QByteArray &device, QAudioDevice::Mode mode);
- ~QGStreamerAudioDeviceInfo();
QGstDeviceHandle gstDevice;
};
+class QGStreamerCustomAudioDeviceInfo : public QAudioDevicePrivate
+{
+public:
+ QGStreamerCustomAudioDeviceInfo(const QByteArray &gstreamerPipeline, QAudioDevice::Mode mode);
+};
+
+QAudioDevice qMakeCustomGStreamerAudioInput(const QByteArray &gstreamerPipeline);
+QAudioDevice qMakeCustomGStreamerAudioOutput(const QByteArray &gstreamerPipeline);
+
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp
deleted file mode 100644
index 5399a3e64..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <QtMultimedia/private/qaudiohelpers_p.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <audio/qgstreameraudiosink_p.h>
-#include <audio/qgstreameraudiodevice_p.h>
-#include <common/qgst_debug_p.h>
-#include <common/qgstappsource_p.h>
-#include <common/qgstpipeline_p.h>
-#include <common/qgstreamermessage_p.h>
-#include <common/qgstutils_p.h>
-
-#include <utility>
-
-QT_BEGIN_NAMESPACE
-
-QMaybe<QPlatformAudioSink *> QGStreamerAudioSink::create(const QAudioDevice &device, QObject *parent)
-{
- auto maybeAppSrc = QGstAppSource::create();
- if (!maybeAppSrc)
- return maybeAppSrc.error();
-
- QGstElement audioconvert = QGstElement::createFromFactory("audioconvert", "conv");
- if (!audioconvert)
- return errorMessageCannotFindElement("audioconvert");
-
- QGstElement volume = QGstElement::createFromFactory("volume", "volume");
- if (!volume)
- return errorMessageCannotFindElement("volume");
-
- return new QGStreamerAudioSink(device, maybeAppSrc.value(), audioconvert, volume, parent);
-}
-
-QGStreamerAudioSink::QGStreamerAudioSink(const QAudioDevice &device, QGstAppSource *appsrc,
- QGstElement audioconvert, QGstElement volume,
- QObject *parent)
- : QPlatformAudioSink(parent),
- m_device(device.id()),
- gstPipeline(QGstPipeline::create("audioSinkPipeline")),
- gstVolume(std::move(volume)),
- m_appSrc(appsrc)
-{
- gstPipeline.installMessageFilter(this);
-
- connect(m_appSrc, &QGstAppSource::bytesProcessed, this, &QGStreamerAudioSink::bytesProcessedByAppSrc);
- connect(m_appSrc, &QGstAppSource::noMoreData, this, &QGStreamerAudioSink::needData);
- gstAppSrc = m_appSrc->element();
-
- QGstElement queue = QGstElement::createFromFactory("queue", "audioSinkQueue");
-
- 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 = QGstElement::createFromDevice(audioInfo->gstDevice, nullptr);
-
- gstPipeline.add(gstAppSrc, queue, /*gstDecodeBin, */ audioconvert, gstVolume, gstOutput);
- qLinkGstElements(gstAppSrc, queue, audioconvert, gstVolume, gstOutput);
-}
-
-QGStreamerAudioSink::~QGStreamerAudioSink()
-{
- close();
- gstPipeline.removeMessageFilter(this);
-
- gstPipeline = {};
- gstVolume = {};
- gstAppSrc = {};
- delete m_appSrc;
- m_appSrc = nullptr;
-}
-
-void QGStreamerAudioSink::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QGStreamerAudioSink::error() const
-{
- return m_errorState;
-}
-
-void QGStreamerAudioSink::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QGStreamerAudioSink::state() const
-{
- return m_deviceState;
-}
-
-void QGStreamerAudioSink::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!m_format.isValid()) {
- setError(QAudio::OpenError);
- return;
- }
-
- m_pullMode = true;
- m_audioSource = device;
-
- if (!open()) {
- m_audioSource = nullptr;
- setError(QAudio::OpenError);
- return;
- }
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QGStreamerAudioSink::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!m_format.isValid()) {
- setError(QAudio::OpenError);
- return nullptr;
- }
-
- m_pullMode = false;
-
- if (!open())
- return nullptr;
-
- m_audioSource = new GStreamerOutputPrivate(this);
- m_audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSource;
-}
-
-#if 0
-static void padAdded(GstElement *element, GstPad *pad, gpointer data)
-{
- GstElement *other = static_cast<GstElement *>(data);
-
- QGString name { gst_pad_get_name(pad)};
- qDebug("A new pad %s was created for %s\n", name, gst_element_get_name(element));
-
- qDebug("element %s will be linked to %s\n",
- gst_element_get_name(element),
- gst_element_get_name(other));
- gst_element_link(element, other);
-}
-#endif
-
-bool QGStreamerAudioSink::processBusMessage(const QGstreamerMessage &message)
-{
- auto *msg = message.message();
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- setState(QAudio::IdleState);
- break;
- case GST_MESSAGE_ERROR: {
- setError(QAudio::IOError);
- QUniqueGErrorHandle error;
- QGString debug;
-
- gst_message_parse_error(msg, &error, &debug);
- qDebug() << "Error:" << error;
-
- break;
- }
- default:
- break;
- }
-
- return true;
-}
-
-bool QGStreamerAudioSink::open()
-{
- if (m_opened)
- return true;
-
- if (gstOutput.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
-// qDebug() << "GST caps:" << gst_caps_to_string(caps);
- m_appSrc->setup(m_audioSource, m_audioSource ? m_audioSource->pos() : 0);
- m_appSrc->setAudioFormat(m_format);
-
- /* run */
- gstPipeline.setState(GST_STATE_PLAYING);
-
- m_opened = true;
-
- m_timeStamp.restart();
- m_bytesProcessed = 0;
-
- return true;
-}
-
-void QGStreamerAudioSink::close()
-{
- if (!m_opened)
- return;
-
- if (!gstPipeline.setStateSync(GST_STATE_NULL))
- qWarning() << "failed to close the audio output stream";
-
- if (!m_pullMode && m_audioSource)
- delete m_audioSource;
- m_audioSource = nullptr;
- m_opened = false;
-}
-
-qint64 QGStreamerAudioSink::write(const char *data, qint64 len)
-{
- if (!len)
- return 0;
- if (m_errorState == QAudio::UnderrunError)
- m_errorState = QAudio::NoError;
-
- m_appSrc->write(data, len);
- return len;
-}
-
-void QGStreamerAudioSink::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-qsizetype QGStreamerAudioSink::bytesFree() const
-{
- if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState)
- return 0;
-
- return m_appSrc->canAcceptMoreData() ? 4096*4 : 0;
-}
-
-void QGStreamerAudioSink::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
- if (!gstAppSrc.isNull())
- gst_app_src_set_max_bytes(GST_APP_SRC(gstAppSrc.element()), value);
-}
-
-qsizetype QGStreamerAudioSink::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QGStreamerAudioSink::processedUSecs() const
-{
- qint64 result = qint64(1000000) * m_bytesProcessed /
- m_format.bytesPerFrame() /
- m_format.sampleRate();
-
- return result;
-}
-
-void QGStreamerAudioSink::resume()
-{
- if (m_deviceState == QAudio::SuspendedState) {
- m_appSrc->resume();
- gstPipeline.setState(GST_STATE_PLAYING);
-
- setState(m_suspendedInState);
- setError(QAudio::NoError);
- }
-}
-
-void QGStreamerAudioSink::setFormat(const QAudioFormat &format)
-{
- m_format = format;
-}
-
-QAudioFormat QGStreamerAudioSink::format() const
-{
- return m_format;
-}
-
-void QGStreamerAudioSink::suspend()
-{
- if (m_deviceState == QAudio::ActiveState || m_deviceState == QAudio::IdleState) {
- m_suspendedInState = m_deviceState;
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- gstPipeline.setState(GST_STATE_PAUSED);
- m_appSrc->suspend();
- // ### elapsed time
- }
-}
-
-void QGStreamerAudioSink::reset()
-{
- stop();
-}
-
-GStreamerOutputPrivate::GStreamerOutputPrivate(QGStreamerAudioSink *audio)
-{
- m_audioDevice = audio;
-}
-
-qint64 GStreamerOutputPrivate::readData(char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
-
- return 0;
-}
-
-qint64 GStreamerOutputPrivate::writeData(const char *data, qint64 len)
-{
- if (m_audioDevice->state() == QAudio::IdleState)
- m_audioDevice->setState(QAudio::ActiveState);
- return m_audioDevice->write(data, len);
-}
-
-void QGStreamerAudioSink::setVolume(qreal vol)
-{
- if (m_volume == vol)
- return;
-
- m_volume = vol;
- if (!gstVolume.isNull())
- gstVolume.set("volume", vol);
-}
-
-qreal QGStreamerAudioSink::volume() const
-{
- return m_volume;
-}
-
-void QGStreamerAudioSink::bytesProcessedByAppSrc(int bytes)
-{
- m_bytesProcessed += bytes;
- setState(QAudio::ActiveState);
- setError(QAudio::NoError);
-}
-
-void QGStreamerAudioSink::needData()
-{
- if (state() != QAudio::StoppedState && state() != QAudio::IdleState) {
- setState(QAudio::IdleState);
- setError(m_audioSource && m_audioSource->atEnd() ? QAudio::NoError : QAudio::UnderrunError);
- }
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qgstreameraudiosink_p.cpp"
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h
deleted file mode 100644
index 1aadb2290..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosink_p.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QAUDIOOUTPUTGSTREAMER_H
-#define QAUDIOOUTPUTGSTREAMER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qfile.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/private/qringbuffer_p.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-#include <private/qmultimediautils_p.h>
-
-#include <common/qgst_p.h>
-#include <common/qgstpipeline_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QGstAppSource;
-
-class QGStreamerAudioSink
- : public QPlatformAudioSink,
- public QGstreamerBusMessageFilter
-{
- friend class GStreamerOutputPrivate;
- Q_OBJECT
-
-public:
- static QMaybe<QPlatformAudioSink *> create(const QAudioDevice &device, QObject *parent);
- ~QGStreamerAudioSink();
-
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesFree() const override;
- void setBufferSize(qsizetype value) override;
- qsizetype bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &format) override;
- QAudioFormat format() const override;
-
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
-private Q_SLOTS:
- void bytesProcessedByAppSrc(int bytes);
- void needData();
-
-private:
- QGStreamerAudioSink(const QAudioDevice &device, QGstAppSource *appsrc, QGstElement audioconvert,
- QGstElement volume, QObject *parent);
-
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- bool processBusMessage(const QGstreamerMessage &message) override;
-
- bool open();
- void close();
- qint64 write(const char *data, qint64 len);
-
-private:
- QByteArray m_device;
- QAudioFormat m_format;
- QAudio::Error m_errorState = QAudio::NoError;
- QAudio::State m_deviceState = QAudio::StoppedState;
- QAudio::State m_suspendedInState = QAudio::SuspendedState;
- bool m_pullMode = true;
- bool m_opened = false;
- QIODevice *m_audioSource = nullptr;
- int m_bufferSize = 0;
- qint64 m_bytesProcessed = 0;
- QElapsedTimer m_timeStamp;
- qreal m_volume = 1.;
- QByteArray pushData;
-
- QGstPipeline gstPipeline;
- QGstElement gstOutput;
- QGstElement gstVolume;
- QGstElement gstAppSrc;
- QGstAppSource *m_appSrc = nullptr;
-};
-
-class GStreamerOutputPrivate : public QIODevice
-{
- friend class QGStreamerAudioSink;
- Q_OBJECT
-
-public:
- explicit GStreamerOutputPrivate(QGStreamerAudioSink *audio);
-
-protected:
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
-
-private:
- QGStreamerAudioSink *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp
deleted file mode 100644
index ba9823d98..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qdebug.h>
-#include <QtCore/qmath.h>
-#include <private/qaudiohelpers_p.h>
-
-#include "qgstreameraudiosource_p.h"
-#include "qgstreameraudiodevice_p.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gst/gst.h>
-Q_DECLARE_OPAQUE_POINTER(GstSample *);
-Q_DECLARE_METATYPE(GstSample *);
-
-QT_BEGIN_NAMESPACE
-
-QGStreamerAudioSource::QGStreamerAudioSource(const QAudioDevice &device, QObject *parent)
- : QPlatformAudioSource(parent),
- m_info(device),
- m_device(device.id())
-{
- qRegisterMetaType<GstSample *>();
-}
-
-QGStreamerAudioSource::~QGStreamerAudioSource()
-{
- close();
-}
-
-void QGStreamerAudioSource::setError(QAudio::Error error)
-{
- if (m_errorState == error)
- return;
-
- m_errorState = error;
- emit errorChanged(error);
-}
-
-QAudio::Error QGStreamerAudioSource::error() const
-{
- return m_errorState;
-}
-
-void QGStreamerAudioSource::setState(QAudio::State state)
-{
- if (m_deviceState == state)
- return;
-
- m_deviceState = state;
- emit stateChanged(state);
-}
-
-QAudio::State QGStreamerAudioSource::state() const
-{
- return m_deviceState;
-}
-
-void QGStreamerAudioSource::setFormat(const QAudioFormat &format)
-{
- if (m_deviceState == QAudio::StoppedState)
- m_format = format;
-}
-
-QAudioFormat QGStreamerAudioSource::format() const
-{
- return m_format;
-}
-
-void QGStreamerAudioSource::start(QIODevice *device)
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!open())
- return;
-
- m_pullMode = true;
- m_audioSink = device;
-
- setState(QAudio::ActiveState);
-}
-
-QIODevice *QGStreamerAudioSource::start()
-{
- setState(QAudio::StoppedState);
- setError(QAudio::NoError);
-
- close();
-
- if (!open())
- return nullptr;
-
- m_pullMode = false;
- m_audioSink = new GStreamerInputPrivate(this);
- m_audioSink->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
-
- setState(QAudio::IdleState);
-
- return m_audioSink;
-}
-
-void QGStreamerAudioSource::stop()
-{
- if (m_deviceState == QAudio::StoppedState)
- return;
-
- close();
-
- setError(QAudio::NoError);
- setState(QAudio::StoppedState);
-}
-
-bool QGStreamerAudioSource::open()
-{
- if (m_opened)
- return true;
-
- const auto *deviceInfo = static_cast<const QGStreamerAudioDeviceInfo *>(m_info.handle());
- if (!deviceInfo->gstDevice) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- gstInput = QGstElement::createFromDevice(deviceInfo->gstDevice);
- if (gstInput.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
- auto gstCaps = QGstUtils::capsForAudioFormat(m_format);
-
- if (gstCaps.isNull()) {
- setError(QAudio::OpenError);
- setState(QAudio::StoppedState);
- return false;
- }
-
-
-#ifdef DEBUG_AUDIO
- qDebug() << "Opening input" << QTime::currentTime();
- qDebug() << "Caps: " << gst_caps_to_string(gstCaps);
-#endif
-
- gstPipeline = QGstPipeline::create("audioSourcePipeline");
-
- auto *gstBus = gst_pipeline_get_bus(gstPipeline.pipeline());
- gst_bus_add_watch(gstBus, &QGStreamerAudioSource::busMessage, this);
- gst_object_unref (gstBus);
-
- gstAppSink = createAppSink();
- gstAppSink.set("caps", gstCaps);
-
- QGstElement conv = QGstElement::createFromFactory("audioconvert", "conv");
- gstVolume = QGstElement::createFromFactory("volume", "volume");
- Q_ASSERT(gstVolume);
- if (m_volume != 1.)
- gstVolume.set("volume", m_volume);
-
- gstPipeline.add(gstInput, gstVolume, conv, gstAppSink);
- qLinkGstElements(gstInput, gstVolume, conv, gstAppSink);
-
- gstPipeline.setState(GST_STATE_PLAYING);
-
- m_opened = true;
-
- m_timeStamp.restart();
- m_elapsedTimeOffset = 0;
- m_bytesWritten = 0;
-
- return true;
-}
-
-void QGStreamerAudioSource::close()
-{
- if (!m_opened)
- return;
-
- gstPipeline.setState(GST_STATE_NULL);
- gstPipeline = {};
- gstVolume = {};
- gstAppSink = {};
- gstInput = {};
-
- if (!m_pullMode && m_audioSink) {
- delete m_audioSink;
- }
- m_audioSink = nullptr;
- m_opened = false;
-}
-
-gboolean QGStreamerAudioSource::busMessage(GstBus *, GstMessage *msg, gpointer user_data)
-{
- QGStreamerAudioSource *input = static_cast<QGStreamerAudioSource *>(user_data);
- switch (GST_MESSAGE_TYPE (msg)) {
- case GST_MESSAGE_EOS:
- input->stop();
- break;
- case GST_MESSAGE_ERROR: {
- input->setError(QAudio::IOError);
- QUniqueGErrorHandle error;
- QGString debug;
-
- gst_message_parse_error (msg, &error, &debug);
- qDebug() << "Error:" << error.get();
-
- break;
- }
- default:
- break;
- }
- return false;
-}
-
-qsizetype QGStreamerAudioSource::bytesReady() const
-{
- return m_buffer.size();
-}
-
-void QGStreamerAudioSource::resume()
-{
- if (m_deviceState == QAudio::SuspendedState || m_deviceState == QAudio::IdleState) {
- gstPipeline.setState(GST_STATE_PLAYING);
- setState(QAudio::ActiveState);
- setError(QAudio::NoError);
- }
-}
-
-void QGStreamerAudioSource::setVolume(qreal vol)
-{
- if (m_volume == vol)
- return;
-
- m_volume = vol;
- if (!gstVolume.isNull())
- gstVolume.set("volume", vol);
-}
-
-qreal QGStreamerAudioSource::volume() const
-{
- return m_volume;
-}
-
-void QGStreamerAudioSource::setBufferSize(qsizetype value)
-{
- m_bufferSize = value;
-}
-
-qsizetype QGStreamerAudioSource::bufferSize() const
-{
- return m_bufferSize;
-}
-
-qint64 QGStreamerAudioSource::processedUSecs() const
-{
- return m_format.durationForBytes(m_bytesWritten);
-}
-
-void QGStreamerAudioSource::suspend()
-{
- if (m_deviceState == QAudio::ActiveState) {
- setError(QAudio::NoError);
- setState(QAudio::SuspendedState);
-
- gstPipeline.setState(GST_STATE_PAUSED);
- }
-}
-
-void QGStreamerAudioSource::reset()
-{
- stop();
- m_buffer.clear();
-}
-
-//#define MAX_BUFFERS_IN_QUEUE 4
-
-QGstAppSink QGStreamerAudioSource::createAppSink()
-{
- QGstAppSink sink = QGstAppSink::create("appsink");
-
- GstAppSinkCallbacks callbacks{};
- callbacks.eos = eos;
- callbacks.new_sample = new_sample;
- sink.setCallbacks(callbacks, this, nullptr);
- // gst_app_sink_set_max_buffers(sink.appSink(), MAX_BUFFERS_IN_QUEUE);
- gst_base_sink_set_sync(sink.baseSink(), FALSE);
-
- return sink;
-}
-
-void QGStreamerAudioSource::newDataAvailable(QGstSampleHandle sample)
-{
- if (m_audioSink) {
- GstBuffer *buffer = gst_sample_get_buffer(sample.get());
- GstMapInfo mapInfo;
- gst_buffer_map(buffer, &mapInfo, GST_MAP_READ);
- const char *bufferData = (const char*)mapInfo.data;
- gsize bufferSize = mapInfo.size;
-
- if (!m_pullMode) {
- // need to store that data in the QBuffer
- m_buffer.append(bufferData, bufferSize);
- m_audioSink->readyRead();
- } else {
- m_bytesWritten += bufferSize;
- m_audioSink->write(bufferData, bufferSize);
- }
-
- gst_buffer_unmap(buffer, &mapInfo);
- }
-}
-
-GstFlowReturn QGStreamerAudioSource::new_sample(GstAppSink *sink, gpointer user_data)
-{
- // "Note that the preroll buffer will also be returned as the first buffer when calling gst_app_sink_pull_buffer()."
- QGStreamerAudioSource *control = static_cast<QGStreamerAudioSource*>(user_data);
-
- QGstSampleHandle sample{
- gst_app_sink_pull_sample(sink),
- QGstSampleHandle::HasRef,
- };
-
- QMetaObject::invokeMethod(control, [control, sample = std::move(sample)]() mutable {
- control->newDataAvailable(std::move(sample));
- });
-
- return GST_FLOW_OK;
-}
-
-void QGStreamerAudioSource::eos(GstAppSink *, gpointer user_data)
-{
- QGStreamerAudioSource *control = static_cast<QGStreamerAudioSource*>(user_data);
- control->setState(QAudio::StoppedState);
-}
-
-GStreamerInputPrivate::GStreamerInputPrivate(QGStreamerAudioSource *audio)
-{
- m_audioDevice = audio;
-}
-
-qint64 GStreamerInputPrivate::readData(char *data, qint64 len)
-{
- if (m_audioDevice->state() == QAudio::IdleState)
- m_audioDevice->setState(QAudio::ActiveState);
- qint64 bytes = m_audioDevice->m_buffer.read(data, len);
- m_audioDevice->m_bytesWritten += bytes;
- return bytes;
-}
-
-qint64 GStreamerInputPrivate::writeData(const char *data, qint64 len)
-{
- Q_UNUSED(data);
- Q_UNUSED(len);
- return 0;
-}
-
-qint64 GStreamerInputPrivate::bytesAvailable() const
-{
- return m_audioDevice->m_buffer.size();
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h b/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h
deleted file mode 100644
index 9021f1ddd..000000000
--- a/src/plugins/multimedia/gstreamer/audio/qgstreameraudiosource_p.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#ifndef QAUDIOINPUTGSTREAMER_H
-#define QAUDIOINPUTGSTREAMER_H
-
-#include <QtCore/qfile.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qelapsedtimer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qmutex.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/private/qringbuffer_p.h>
-
-#include "qaudio.h"
-#include "qaudiodevice.h"
-#include <private/qaudiosystem_p.h>
-
-#include <common/qgstutils_p.h>
-#include <common/qgstpipeline_p.h>
-
-#include <gst/app/gstappsink.h>
-
-QT_BEGIN_NAMESPACE
-
-class GStreamerInputPrivate;
-
-class QGStreamerAudioSource
- : public QPlatformAudioSource
-{
- friend class GStreamerInputPrivate;
-public:
- QGStreamerAudioSource(const QAudioDevice &device, QObject *parent);
- ~QGStreamerAudioSource();
-
- void start(QIODevice *device) override;
- QIODevice *start() override;
- void stop() override;
- void reset() override;
- void suspend() override;
- void resume() override;
- qsizetype bytesReady() const override;
- void setBufferSize(qsizetype value) override;
- qsizetype bufferSize() const override;
- qint64 processedUSecs() const override;
- QAudio::Error error() const override;
- QAudio::State state() const override;
- void setFormat(const QAudioFormat &format) override;
- QAudioFormat format() const override;
-
- void setVolume(qreal volume) override;
- qreal volume() const override;
-
-private:
- void setState(QAudio::State state);
- void setError(QAudio::Error error);
-
- QGstAppSink createAppSink();
- static GstFlowReturn new_sample(GstAppSink *, gpointer user_data);
- static void eos(GstAppSink *, gpointer user_data);
-
- bool open();
- void close();
-
- static gboolean busMessage(GstBus *bus, GstMessage *msg, gpointer user_data);
-
- void newDataAvailable(QGstSampleHandle sample);
-
- QAudioDevice m_info;
- qint64 m_bytesWritten = 0;
- QIODevice *m_audioSink = nullptr;
- QAudioFormat m_format;
- QAudio::Error m_errorState = QAudio::NoError;
- QAudio::State m_deviceState = QAudio::StoppedState;
- qreal m_volume = 1.;
-
- QRingBuffer m_buffer;
- QAtomicInteger<bool> m_pullMode = true;
- bool m_opened = false;
- int m_bufferSize = 0;
- qint64 m_elapsedTimeOffset = 0;
- QElapsedTimer m_timeStamp;
- QByteArray m_device;
- QByteArray m_tempBuffer;
-
- QGstElement gstInput;
- QGstPipeline gstPipeline;
- QGstElement gstVolume;
- QGstAppSink gstAppSink;
-};
-
-class GStreamerInputPrivate : public QIODevice
-{
-public:
- explicit GStreamerInputPrivate(QGStreamerAudioSource *audio);
-
- qint64 readData(char *data, qint64 len) override;
- qint64 writeData(const char *data, qint64 len) override;
- qint64 bytesAvailable() const override;
- bool isSequential() const override { return true; }
-private:
- QGStreamerAudioSource *m_audioDevice;
-};
-
-QT_END_NAMESPACE
-
-#endif