~phablet-team/phablet-extras/qt-gstreamer

« back to all changes in this revision

Viewing changes to examples/voip/main.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2012-06-15 15:03:26 UTC
  • mfrom: (1.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20120615150326-pkmdog620pkytcgt
Tags: 0.10.2-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Enable unit tests.
    + Build-depend on gstreamer0.10-plugins-base.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2011 Collabora Ltd.
 
3
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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/>.
 
17
*/
 
18
 
 
19
/*
 
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.
 
24
 
 
25
    Here is a figure that shows the video session part of the pipeline.
 
26
 
 
27
.------------.   .-------.    .-------.      .----------.     .-------.
 
28
|videotestsrc|   |h264enc|    |h264pay|      |          |     |udpsink|      RTP SEND
 
29
|          src->sink    src->sink   src->send_rtp send_rtp->sink      |
 
30
'------------'   '-------'    '-------'      |          |     '-------'
 
31
                                             | rtpbin   |
 
32
                              .-------.      |          |     .---------.   .-------.   .-------------.
 
33
                RTP RECV      |udpsrc |      |          |     |h264depay|   |h264dec|   |autovideosink|
 
34
                              |      src->recv_rtp recv_rtp->sink     src->sink   src->sink           |
 
35
                              '-------'      |          |     '---------'   '-------'   '-------------'
 
36
                                             |          |
 
37
                                             |          |     .-------.
 
38
                                             |          |     |udpsink|  RTCP
 
39
                                             |    send_rtcp->sink     | sync=false
 
40
                              .-------.      |          |     '-------' async=false
 
41
                    RTCP      |udpsrc |      |          |
 
42
                              |     src->recv_rtcp      |
 
43
                              '-------'      |          |
 
44
                                             '----------'
 
45
 
 
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.
 
48
*/
 
49
 
 
50
#include "ui_voip.h"
 
51
 
 
52
#include <QtGui/QApplication>
 
53
#include <QtGui/QDialog>
 
54
 
 
55
#include <QGlib/Connect>
 
56
#include <QGlib/Error>
 
57
#include <QGst/Init>
 
58
#include <QGst/Pipeline>
 
59
#include <QGst/ElementFactory>
 
60
#include <QGst/Pad>
 
61
#include <QGst/Structure>
 
62
#include <QGst/Bus>
 
63
#include <QGst/Message>
 
64
 
 
65
class VoipExample : public QDialog
 
66
{
 
67
    Q_OBJECT
 
68
public:
 
69
    explicit VoipExample(QWidget *parent = 0);
 
70
    virtual ~VoipExample();
 
71
 
 
72
private Q_SLOTS:
 
73
    void on_startCallButton_clicked();
 
74
    void on_endCallButton_clicked();
 
75
 
 
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); }
 
81
 
 
82
private:
 
83
    void onRtpBinPadAdded(const QGst::PadPtr & pad);
 
84
    void onBusErrorMessage(const QGst::MessagePtr & msg);
 
85
 
 
86
private:
 
87
    Ui::VoipExample m_ui;
 
88
    QGst::PipelinePtr m_pipeline;
 
89
};
 
90
 
 
91
VoipExample::VoipExample(QWidget *parent)
 
92
    : QDialog(parent)
 
93
{
 
94
    m_ui.setupUi(this);
 
95
}
 
96
 
 
97
VoipExample::~VoipExample()
 
98
{
 
99
    //cleanup if the pipeline is still active
 
100
    if (m_pipeline) {
 
101
        on_endCallButton_clicked();
 
102
    }
 
103
}
 
104
 
 
105
void VoipExample::on_startCallButton_clicked()
 
106
{
 
107
    m_pipeline = QGst::Pipeline::create();
 
108
 
 
109
    QGst::ElementPtr rtpbin = QGst::ElementFactory::make("gstrtpbin");
 
110
    if (!rtpbin) {
 
111
        qFatal("Failed to create gstrtpbin");
 
112
    }
 
113
    m_pipeline->add(rtpbin);
 
114
 
 
115
    //audio content
 
116
    if (m_ui.audioGroupBox->isChecked()) {
 
117
        //sending side
 
118
        QGst::ElementPtr audiosrc;
 
119
        try {
 
120
            audiosrc = QGst::Bin::fromDescription(
 
121
                "autoaudiosrc ! queue ! audioconvert ! audiorate ! audio/x-raw-int,rate=8000 "
 
122
                "! speexenc ! rtpspeexpay"
 
123
            );
 
124
        } catch (const QGlib::Error & error) {
 
125
            qCritical() << error;
 
126
            qFatal("One ore more required elements are missing. Aborting...");
 
127
        }
 
128
        m_pipeline->add(audiosrc);
 
129
        audiosrc->link(rtpbin, "send_rtp_sink_1");
 
130
 
 
131
        QGst::ElementPtr rtpudpsink = QGst::ElementFactory::make("udpsink");
 
132
        if (!rtpudpsink) {
 
133
            qFatal("Failed to create udpsink. Aborting...");
 
134
        }
 
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);
 
139
 
 
140
        //receiving side
 
141
        QGst::ElementPtr rtpudpsrc = QGst::ElementFactory::make("udpsrc");
 
142
        if (!rtpudpsrc) {
 
143
            qFatal("Failed to create udpsrc. Aborting...");
 
144
        }
 
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");
 
152
 
 
153
        //recv sink will be added when the pad becomes available
 
154
 
 
155
        //rtcp connection
 
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");
 
160
 
 
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);
 
168
    }
 
169
 
 
170
    //video content
 
171
    if (m_ui.videoGroupBox->isChecked()) {
 
172
        //sending side
 
173
        QGst::ElementPtr videosrc;
 
174
        try {
 
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"
 
178
            );
 
179
        } catch (const QGlib::Error & error) {
 
180
            qCritical() << error;
 
181
            qFatal("One ore more required elements are missing. Aborting...");
 
182
        }
 
183
        m_pipeline->add(videosrc);
 
184
        videosrc->link(rtpbin, "send_rtp_sink_2");
 
185
 
 
186
        QGst::ElementPtr rtpudpsink = QGst::ElementFactory::make("udpsink");
 
187
        if (!rtpudpsink) {
 
188
            qFatal("Failed to create udpsink. Aborting...");
 
189
        }
 
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);
 
194
 
 
195
        //receiving side
 
196
        QGst::ElementPtr rtpudpsrc = QGst::ElementFactory::make("udpsrc");
 
197
        if (!rtpudpsrc) {
 
198
            qFatal("Failed to create udpsrc. Aborting...");
 
199
        }
 
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");
 
207
 
 
208
        //recv sink will be added when the pad becomes available
 
209
 
 
210
        //rtcp connection
 
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");
 
215
 
 
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);
 
223
    }
 
224
 
 
225
    //watch for the receiving side src pads
 
226
    QGlib::connect(rtpbin, "pad-added", this, &VoipExample::onRtpBinPadAdded);
 
227
 
 
228
    //watch the bus
 
229
    m_pipeline->bus()->addSignalWatch();
 
230
    QGlib::connect(m_pipeline->bus(), "message::error", this, &VoipExample::onBusErrorMessage);
 
231
 
 
232
    //switch to the video view and connect the video widget
 
233
    m_ui.stackedWidget->setCurrentIndex(1);
 
234
    m_ui.videoWidget->watchPipeline(m_pipeline);
 
235
 
 
236
    //go!
 
237
    m_pipeline->setState(QGst::StatePlaying);
 
238
}
 
239
 
 
240
void VoipExample::onRtpBinPadAdded(const QGst::PadPtr & pad)
 
241
{
 
242
    QGst::ElementPtr bin;
 
243
 
 
244
    try {
 
245
        if (pad->caps()->internalStructure(0)->value("media").toString() == QLatin1String("audio")) {
 
246
            bin = QGst::Bin::fromDescription(
 
247
                "rtpspeexdepay ! speexdec ! audioconvert ! autoaudiosink"
 
248
            );
 
249
        } else {
 
250
            bin = QGst::Bin::fromDescription(
 
251
                "rtph264depay ! ffdec_h264 ! ffmpegcolorspace ! autovideosink"
 
252
            );
 
253
        }
 
254
    } catch (const QGlib::Error & error) {
 
255
        qCritical() << error;
 
256
        qFatal("One ore more required elements are missing. Aborting...");
 
257
    }
 
258
 
 
259
    m_pipeline->add(bin);
 
260
    bin->syncStateWithParent();
 
261
    pad->link(bin->getStaticPad("sink"));
 
262
}
 
263
 
 
264
void VoipExample::onBusErrorMessage(const QGst::MessagePtr & msg)
 
265
{
 
266
    qCritical() << "Error from bus:" << msg.staticCast<QGst::ErrorMessage>()->error();
 
267
    on_endCallButton_clicked(); //stop the call
 
268
}
 
269
 
 
270
void VoipExample::on_endCallButton_clicked()
 
271
{
 
272
    m_pipeline->setState(QGst::StateNull);
 
273
    m_ui.videoWidget->stopPipelineWatch();
 
274
    m_ui.stackedWidget->setCurrentIndex(0);
 
275
    m_pipeline.clear();
 
276
}
 
277
 
 
278
 
 
279
int main(int argc, char *argv[])
 
280
{
 
281
    QApplication app(argc, argv);
 
282
    QGst::init(&argc, &argv);
 
283
 
 
284
    VoipExample gui;
 
285
    gui.show();
 
286
 
 
287
    return app.exec();
 
288
}
 
289
 
 
290
#include "main.moc"