1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <qgstreameraudiooutput_p.h> |
5 | #include <qgstreameraudiodevice_p.h> |
6 | #include <qaudiodevice.h> |
7 | #include <qaudiooutput.h> |
8 | |
9 | #include <QtCore/qloggingcategory.h> |
10 | #include <QtNetwork/qnetworkaccessmanager.h> |
11 | #include <QtNetwork/qnetworkreply.h> |
12 | |
13 | #include <sys/types.h> |
14 | #include <sys/stat.h> |
15 | #include <fcntl.h> |
16 | |
17 | #include <utility> |
18 | |
19 | static Q_LOGGING_CATEGORY(qLcMediaAudioOutput, "qt.multimedia.audiooutput" ) |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | QMaybe<QPlatformAudioOutput *> QGstreamerAudioOutput::create(QAudioOutput *parent) |
24 | { |
25 | QGstElement audioconvert("audioconvert" , "audioConvert" ); |
26 | if (!audioconvert) |
27 | return errorMessageCannotFindElement(element: "audioconvert" ); |
28 | |
29 | QGstElement audioresample("audioresample" , "audioResample" ); |
30 | if (!audioresample) |
31 | return errorMessageCannotFindElement(element: "audioresample" ); |
32 | |
33 | QGstElement volume("volume" , "volume" ); |
34 | if (!volume) |
35 | return errorMessageCannotFindElement(element: "volume" ); |
36 | |
37 | QGstElement autoaudiosink("autoaudiosink" , "autoAudioSink" ); |
38 | if (!autoaudiosink) |
39 | return errorMessageCannotFindElement(element: "autoaudiosink" ); |
40 | |
41 | return new QGstreamerAudioOutput(audioconvert, audioresample, volume, autoaudiosink, parent); |
42 | } |
43 | |
44 | QGstreamerAudioOutput::QGstreamerAudioOutput(QGstElement audioconvert, QGstElement audioresample, |
45 | QGstElement volume, QGstElement autoaudiosink, |
46 | QAudioOutput *parent) |
47 | : QObject(parent), |
48 | QPlatformAudioOutput(parent), |
49 | gstAudioOutput("audioOutput" ), |
50 | audioConvert(std::move(audioconvert)), |
51 | audioResample(std::move(audioresample)), |
52 | audioVolume(std::move(volume)), |
53 | audioSink(std::move(autoaudiosink)) |
54 | { |
55 | audioQueue = QGstElement("queue" , "audioQueue" ); |
56 | gstAudioOutput.add(e1: audioQueue, e2: audioConvert, e3: audioResample, e4: audioVolume, e5: audioSink); |
57 | audioQueue.link(n1: audioConvert, n2: audioResample, n3: audioVolume, n4: audioSink); |
58 | |
59 | gstAudioOutput.addGhostPad(child: audioQueue, name: "sink" ); |
60 | } |
61 | |
62 | QGstreamerAudioOutput::~QGstreamerAudioOutput() |
63 | { |
64 | gstAudioOutput.setStateSync(GST_STATE_NULL); |
65 | } |
66 | |
67 | void QGstreamerAudioOutput::setVolume(float vol) |
68 | { |
69 | audioVolume.set(property: "volume" , d: vol); |
70 | } |
71 | |
72 | void QGstreamerAudioOutput::setMuted(bool muted) |
73 | { |
74 | audioVolume.set(property: "mute" , b: muted); |
75 | } |
76 | |
77 | void QGstreamerAudioOutput::setPipeline(const QGstPipeline &pipeline) |
78 | { |
79 | gstPipeline = pipeline; |
80 | } |
81 | |
82 | void QGstreamerAudioOutput::setAudioDevice(const QAudioDevice &info) |
83 | { |
84 | if (info == m_audioOutput) |
85 | return; |
86 | qCDebug(qLcMediaAudioOutput) << "setAudioOutput" << info.description() << info.isNull(); |
87 | m_audioOutput = info; |
88 | |
89 | QGstElement newSink; |
90 | #if QT_CONFIG(pulseaudio) |
91 | auto id = m_audioOutput.id(); |
92 | newSink = QGstElement("pulsesink" , "audiosink" ); |
93 | if (!newSink.isNull()) |
94 | newSink.set(property: "device" , str: id.constData()); |
95 | else |
96 | qCWarning(qLcMediaAudioOutput) << "Invalid audio device" ; |
97 | #else |
98 | auto *deviceInfo = static_cast<const QGStreamerAudioDeviceInfo *>(m_audioOutput.handle()); |
99 | if (deviceInfo && deviceInfo->gstDevice) |
100 | newSink = gst_device_create_element(deviceInfo->gstDevice , "audiosink" ); |
101 | else |
102 | qCWarning(qLcMediaAudioOutput) << "Invalid audio device" ; |
103 | #endif |
104 | |
105 | if (newSink.isNull()) { |
106 | qCWarning(qLcMediaAudioOutput) << "Failed to create a gst element for the audio device, using a default audio sink" ; |
107 | newSink = QGstElement("autoaudiosink" , "audiosink" ); |
108 | } |
109 | |
110 | audioVolume.staticPad(name: "src" ).doInIdleProbe(work: [&](){ |
111 | audioVolume.unlink(next: audioSink); |
112 | gstAudioOutput.remove(element: audioSink); |
113 | gstAudioOutput.add(element: newSink); |
114 | newSink.syncStateWithParent(); |
115 | audioVolume.link(next: newSink); |
116 | }); |
117 | |
118 | audioSink.setStateSync(GST_STATE_NULL); |
119 | audioSink = newSink; |
120 | } |
121 | |
122 | QT_END_NAMESPACE |
123 | |
124 | #include "moc_qgstreameraudiooutput_p.cpp" |
125 | |