2
Copyright (C) 2011 Collabora Ltd.
3
@author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
5
This library is free software; you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published
7
by the Free Software Foundation; either version 2.1 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU Lesser General Public License for more details.
15
You should have received a copy of the GNU Lesser General Public License
16
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
In this example, the pipeline consists of two parts, one for the audio session
21
and one for the video session. Each session part is identical to the other in
22
structure, the only difference being the encoder/decoder elements and the
23
sources/sinks of the audio/video content.
25
Here is a figure that shows the video session part of the pipeline.
27
.------------. .-------. .-------. .----------. .-------.
28
|videotestsrc| |h264enc| |h264pay| | | |udpsink| RTP SEND
29
| src->sink src->sink src->send_rtp send_rtp->sink |
30
'------------' '-------' '-------' | | '-------'
32
.-------. | | .---------. .-------. .-------------.
33
RTP RECV |udpsrc | | | |h264depay| |h264dec| |autovideosink|
34
| src->recv_rtp recv_rtp->sink src->sink src->sink |
35
'-------' | | '---------' '-------' '-------------'
39
| send_rtcp->sink | sync=false
40
.-------. | | '-------' async=false
46
In the two sessions, the gstrtpbin element is common and the sessions are
47
distinguished from the number at the end of rtpbin's pad names.
52
#include <QtGui/QApplication>
53
#include <QtGui/QDialog>
55
#include <QGlib/Connect>
56
#include <QGlib/Error>
58
#include <QGst/Pipeline>
59
#include <QGst/ElementFactory>
61
#include <QGst/Structure>
63
#include <QGst/Message>
65
class VoipExample : public QDialog
69
explicit VoipExample(QWidget *parent = 0);
70
virtual ~VoipExample();
73
void on_startCallButton_clicked();
74
void on_endCallButton_clicked();
76
//keep the rtcp ports in sync with the rtp ports on the UI
77
void on_audioRtpSrcSpinBox_valueChanged(int value) { m_ui.audioRtcpSrcSpinBox->setValue(value + 1); }
78
void on_audioRtpDestSpinBox_valueChanged(int value) { m_ui.audioRtcpDestSpinBox->setValue(value + 1); }
79
void on_videoRtpSrcSpinBox_valueChanged(int value) { m_ui.videoRtcpSrcSpinBox->setValue(value + 1); }
80
void on_videoRtpDestSpinBox_valueChanged(int value) { m_ui.videoRtcpDestSpinBox->setValue(value + 1); }
83
void onRtpBinPadAdded(const QGst::PadPtr & pad);
84
void onBusErrorMessage(const QGst::MessagePtr & msg);
88
QGst::PipelinePtr m_pipeline;
91
VoipExample::VoipExample(QWidget *parent)
97
VoipExample::~VoipExample()
99
//cleanup if the pipeline is still active
101
on_endCallButton_clicked();
105
void VoipExample::on_startCallButton_clicked()
107
m_pipeline = QGst::Pipeline::create();
109
QGst::ElementPtr rtpbin = QGst::ElementFactory::make("gstrtpbin");
111
qFatal("Failed to create gstrtpbin");
113
m_pipeline->add(rtpbin);
116
if (m_ui.audioGroupBox->isChecked()) {
118
QGst::ElementPtr audiosrc;
120
audiosrc = QGst::Bin::fromDescription(
121
"autoaudiosrc ! queue ! audioconvert ! audiorate ! audio/x-raw-int,rate=8000 "
122
"! speexenc ! rtpspeexpay"
124
} catch (const QGlib::Error & error) {
125
qCritical() << error;
126
qFatal("One ore more required elements are missing. Aborting...");
128
m_pipeline->add(audiosrc);
129
audiosrc->link(rtpbin, "send_rtp_sink_1");
131
QGst::ElementPtr rtpudpsink = QGst::ElementFactory::make("udpsink");
133
qFatal("Failed to create udpsink. Aborting...");
135
rtpudpsink->setProperty("host", m_ui.remoteHostLineEdit->text());
136
rtpudpsink->setProperty("port", m_ui.audioRtpDestSpinBox->value());
137
m_pipeline->add(rtpudpsink);
138
rtpbin->link("send_rtp_src_1", rtpudpsink);
141
QGst::ElementPtr rtpudpsrc = QGst::ElementFactory::make("udpsrc");
143
qFatal("Failed to create udpsrc. Aborting...");
145
rtpudpsrc->setProperty("port", m_ui.audioRtpSrcSpinBox->value());
146
rtpudpsrc->setProperty("caps", QGst::Caps::fromString("application/x-rtp,"
147
"media=(string)audio,"
148
"clock-rate=(int)8000,"
149
"encoding-name=(string)SPEEX"));
150
m_pipeline->add(rtpudpsrc);
151
rtpudpsrc->link(rtpbin, "recv_rtp_sink_1");
153
//recv sink will be added when the pad becomes available
156
QGst::ElementPtr rtcpudpsrc = QGst::ElementFactory::make("udpsrc");
157
rtcpudpsrc->setProperty("port", m_ui.audioRtcpSrcSpinBox->value());
158
m_pipeline->add(rtcpudpsrc);
159
rtcpudpsrc->link(rtpbin, "recv_rtcp_sink_1");
161
QGst::ElementPtr rtcpudpsink = QGst::ElementFactory::make("udpsink");
162
rtcpudpsink->setProperty("host", m_ui.remoteHostLineEdit->text());
163
rtcpudpsink->setProperty("port", m_ui.audioRtcpDestSpinBox->value());
164
rtcpudpsink->setProperty("sync", false);
165
rtcpudpsink->setProperty("async", false);
166
m_pipeline->add(rtcpudpsink);
167
rtpbin->link("send_rtcp_src_1", rtcpudpsink);
171
if (m_ui.videoGroupBox->isChecked()) {
173
QGst::ElementPtr videosrc;
175
videosrc = QGst::Bin::fromDescription(
176
"videotestsrc is-live=true ! video/x-raw-yuv,width=320,height=240,framerate=15/1 "
177
"! x264enc tune=zerolatency byte-stream=true bitrate=300 ! rtph264pay"
179
} catch (const QGlib::Error & error) {
180
qCritical() << error;
181
qFatal("One ore more required elements are missing. Aborting...");
183
m_pipeline->add(videosrc);
184
videosrc->link(rtpbin, "send_rtp_sink_2");
186
QGst::ElementPtr rtpudpsink = QGst::ElementFactory::make("udpsink");
188
qFatal("Failed to create udpsink. Aborting...");
190
rtpudpsink->setProperty("host", m_ui.remoteHostLineEdit->text());
191
rtpudpsink->setProperty("port", m_ui.videoRtpDestSpinBox->value());
192
m_pipeline->add(rtpudpsink);
193
rtpbin->link("send_rtp_src_2", rtpudpsink);
196
QGst::ElementPtr rtpudpsrc = QGst::ElementFactory::make("udpsrc");
198
qFatal("Failed to create udpsrc. Aborting...");
200
rtpudpsrc->setProperty("port", m_ui.videoRtpSrcSpinBox->value());
201
rtpudpsrc->setProperty("caps", QGst::Caps::fromString("application/x-rtp,"
202
"media=(string)video,"
203
"clock-rate=(int)90000,"
204
"encoding-name=(string)H264"));
205
m_pipeline->add(rtpudpsrc);
206
rtpudpsrc->link(rtpbin, "recv_rtp_sink_2");
208
//recv sink will be added when the pad becomes available
211
QGst::ElementPtr rtcpudpsrc = QGst::ElementFactory::make("udpsrc");
212
rtcpudpsrc->setProperty("port", m_ui.videoRtcpSrcSpinBox->value());
213
m_pipeline->add(rtcpudpsrc);
214
rtcpudpsrc->link(rtpbin, "recv_rtcp_sink_2");
216
QGst::ElementPtr rtcpudpsink = QGst::ElementFactory::make("udpsink");
217
rtcpudpsink->setProperty("host", m_ui.remoteHostLineEdit->text());
218
rtcpudpsink->setProperty("port", m_ui.videoRtcpDestSpinBox->value());
219
rtcpudpsink->setProperty("sync", false);
220
rtcpudpsink->setProperty("async", false);
221
m_pipeline->add(rtcpudpsink);
222
rtpbin->link("send_rtcp_src_2", rtcpudpsink);
225
//watch for the receiving side src pads
226
QGlib::connect(rtpbin, "pad-added", this, &VoipExample::onRtpBinPadAdded);
229
m_pipeline->bus()->addSignalWatch();
230
QGlib::connect(m_pipeline->bus(), "message::error", this, &VoipExample::onBusErrorMessage);
232
//switch to the video view and connect the video widget
233
m_ui.stackedWidget->setCurrentIndex(1);
234
m_ui.videoWidget->watchPipeline(m_pipeline);
237
m_pipeline->setState(QGst::StatePlaying);
240
void VoipExample::onRtpBinPadAdded(const QGst::PadPtr & pad)
242
QGst::ElementPtr bin;
245
if (pad->caps()->internalStructure(0)->value("media").toString() == QLatin1String("audio")) {
246
bin = QGst::Bin::fromDescription(
247
"rtpspeexdepay ! speexdec ! audioconvert ! autoaudiosink"
250
bin = QGst::Bin::fromDescription(
251
"rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! autovideosink"
254
} catch (const QGlib::Error & error) {
255
qCritical() << error;
256
qFatal("One ore more required elements are missing. Aborting...");
259
m_pipeline->add(bin);
260
bin->syncStateWithParent();
261
pad->link(bin->getStaticPad("sink"));
264
void VoipExample::onBusErrorMessage(const QGst::MessagePtr & msg)
266
qCritical() << "Error from bus:" << msg.staticCast<QGst::ErrorMessage>()->error();
267
on_endCallButton_clicked(); //stop the call
270
void VoipExample::on_endCallButton_clicked()
272
m_pipeline->setState(QGst::StateNull);
273
m_ui.videoWidget->stopPipelineWatch();
274
m_ui.stackedWidget->setCurrentIndex(0);
279
int main(int argc, char *argv[])
281
QApplication app(argc, argv);
282
QGst::init(&argc, &argv);