[Telepathy-commits] [telepathy-qt4/master] call example: Added VideoWidget.
Andre Moreira Magalhaes (andrunko)
andre.magalhaes at collabora.co.uk
Tue Mar 17 02:13:14 PDT 2009
---
examples/call/Makefile.am | 9 +-
examples/call/call-handler.cpp | 113 +++++++++-
examples/call/call-handler.h | 8 +-
examples/call/call-widget.cpp | 449 ++++++++++++++++++++++++++----------
examples/call/call-widget.h | 52 +++-
examples/call/call-window.cpp | 6 +-
examples/call/farsight-channel.cpp | 70 +++++-
examples/call/farsight-channel.h | 9 +-
examples/call/main.cpp | 4 +
examples/call/video-widget.cpp | 166 +++++++++++++
examples/call/video-widget.h | 57 +++++
11 files changed, 792 insertions(+), 151 deletions(-)
create mode 100644 examples/call/video-widget.cpp
create mode 100644 examples/call/video-widget.h
diff --git a/examples/call/Makefile.am b/examples/call/Makefile.am
index b81af42..16204d9 100644
--- a/examples/call/Makefile.am
+++ b/examples/call/Makefile.am
@@ -1,5 +1,6 @@
AM_CXXFLAGS = \
$(ERROR_CXXFLAGS) \
+ $(GST_CFLAGS) \
$(QTCORE_CFLAGS) \
$(QTGUI_CFLAGS) \
$(QTDBUS_CFLAGS) \
@@ -9,6 +10,7 @@ AM_CXXFLAGS = \
noinst_PROGRAMS = call
call_LDADD = \
+ $(GST_LIBS) \
$(QTGUI_LIBS) \
$(QTDBUS_LIBS) \
$(TP_FARSIGHT_LIBS) \
@@ -26,14 +28,17 @@ call_SOURCES = \
call-window.cpp \
call-window.h \
farsight-channel.cpp \
- farsight-channel.h
+ farsight-channel.h \
+ video-widget.cpp \
+ video-widget.h
nodist_call_SOURCES = \
_gen/call-handler.moc.hpp \
_gen/call-roster-widget.moc.hpp \
_gen/call-widget.moc.hpp \
_gen/call-window.moc.hpp \
- _gen/farsight-channel.moc.hpp
+ _gen/farsight-channel.moc.hpp \
+ _gen/video-widget.moc.hpp
BUILT_SOURCES = \
$(nodist_call_SOURCES)
diff --git a/examples/call/call-handler.cpp b/examples/call/call-handler.cpp
index 5a821cd..b2edfcd 100644
--- a/examples/call/call-handler.cpp
+++ b/examples/call/call-handler.cpp
@@ -24,9 +24,16 @@
#include "call-widget.h"
#include <TelepathyQt4/Client/Channel>
+#include <TelepathyQt4/Client/Connection>
#include <TelepathyQt4/Client/Contact>
+#include <TelepathyQt4/Client/ContactManager>
+#include <TelepathyQt4/Client/PendingChannel>
+#include <TelepathyQt4/Client/PendingReady>
+#include <TelepathyQt4/Client/ReferencedHandles>
+#include <TelepathyQt4/Client/StreamedMediaChannel>
#include <QDebug>
+#include <QMessageBox>
using namespace Telepathy::Client;
@@ -44,7 +51,72 @@ CallHandler::~CallHandler()
void CallHandler::addOutgoingCall(const QSharedPointer<Contact> &contact)
{
- CallWidget *call = new CallWidget(contact);
+ QVariantMap request;
+ request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType"),
+ TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA);
+ request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"),
+ Telepathy::HandleTypeContact);
+ request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandle"),
+ contact->handle()[0]);
+
+ Connection *conn = contact->manager()->connection();
+ connect(conn->ensureChannel(request),
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onOutgoingChannelCreated(Telepathy::Client::PendingOperation*)));
+}
+
+void CallHandler::addIncomingCall(StreamedMediaChannel *chan)
+{
+ mChannels.append(chan);
+ connect(chan->becomeReady(),
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onIncomingChannelReady(Telepathy::Client::PendingOperation*)));
+}
+
+void CallHandler::onOutgoingChannelCreated(PendingOperation *op)
+{
+ if (op->isError()) {
+ qWarning() << "CallHandler::onOutgoingChannelCreated: channel cannot be created:" <<
+ op->errorName() << "-" << op->errorMessage();
+
+ QMessageBox msgBox;
+ msgBox.setText(QString("Unable to call (%1)").arg(op->errorMessage()));
+ msgBox.exec();
+ return;
+ }
+
+ PendingChannel *pc = qobject_cast<PendingChannel *>(op);
+
+ StreamedMediaChannel *chan = new StreamedMediaChannel(pc->connection(),
+ pc->objectPath(), pc->immutableProperties());
+ mChannels.append(chan);
+ connect(chan->becomeReady(),
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onOutgoingChannelReady(Telepathy::Client::PendingOperation*)));
+}
+
+void CallHandler::onOutgoingChannelReady(PendingOperation *op)
+{
+ PendingReady *pr = qobject_cast<PendingReady *>(op);
+ StreamedMediaChannel *chan = qobject_cast<StreamedMediaChannel *>(pr->object());
+
+ if (op->isError()) {
+ qWarning() << "CallHandler::onOutgoingChannelReady: channel cannot become ready:" <<
+ op->errorName() << "-" << op->errorMessage();
+
+ mChannels.removeOne(chan);
+
+ QMessageBox msgBox;
+ msgBox.setText(QString("Unable to call (%1)").arg(op->errorMessage()));
+ msgBox.exec();
+ return;
+ }
+
+ ContactManager *cm = chan->connection()->contactManager();
+ QSharedPointer<Contact> contact = cm->lookupContactByHandle(chan->targetHandle());
+ Q_ASSERT(contact);
+
+ CallWidget *call = new CallWidget(chan, contact);
mCalls.append(call);
connect(call,
SIGNAL(destroyed(QObject *)),
@@ -52,9 +124,37 @@ void CallHandler::addOutgoingCall(const QSharedPointer<Contact> &contact)
call->show();
}
-void CallHandler::addIncomingCall(const ChannelPtr &chan)
+void CallHandler::onIncomingChannelReady(PendingOperation *op)
{
- CallWidget *call = new CallWidget(chan);
+ PendingReady *pr = qobject_cast<PendingReady *>(op);
+ StreamedMediaChannel *chan = qobject_cast<StreamedMediaChannel *>(pr->object());
+
+ if (op->isError()) {
+ // ignore - channel cannot be ready
+ qWarning() << "CallHandler::onIncomingChannelReady: channel cannot become ready:" <<
+ op->errorName() << "-" << op->errorMessage();
+
+ mChannels.removeOne(chan);
+ return;
+ }
+
+ QSharedPointer<Contact> contact = chan->initiatorContact();
+
+ QMessageBox msgBox;
+ msgBox.setText("Incoming call");
+ msgBox.setInformativeText(QString("%1 is calling you, do you want to answer?").arg(contact->id()));
+ msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ msgBox.setDefaultButton(QMessageBox::Yes);
+ int ret = msgBox.exec();
+
+ if (ret == QMessageBox::No) {
+ chan->requestClose();
+ return;
+ }
+
+ chan->acceptCall();
+
+ CallWidget *call = new CallWidget(chan, contact);
mCalls.append(call);
connect(call,
SIGNAL(destroyed(QObject *)),
@@ -64,6 +164,9 @@ void CallHandler::addIncomingCall(const ChannelPtr &chan)
void CallHandler::onCallTerminated(QObject *obj)
{
- // Why does obj comes 0x0?
- mCalls.removeOne((CallWidget *) sender());
+ CallWidget *call = (CallWidget *) obj;
+ StreamedMediaChannel *chan = call->channel();
+ mCalls.removeOne(call);
+ mChannels.removeOne(chan);
+ delete chan;
}
diff --git a/examples/call/call-handler.h b/examples/call/call-handler.h
index f50c81e..e202215 100644
--- a/examples/call/call-handler.h
+++ b/examples/call/call-handler.h
@@ -29,6 +29,8 @@
namespace Telepathy {
namespace Client {
class Contact;
+class PendingOperation;
+class StreamedMediaChannel;
}
}
@@ -43,12 +45,16 @@ public:
virtual ~CallHandler();
void addOutgoingCall(const QSharedPointer<Telepathy::Client::Contact> &contact);
- void addIncomingCall(const Telepathy::Client::ChannelPtr &chan);
+ void addIncomingCall(Telepathy::Client::StreamedMediaChannel *chan);
private Q_SLOTS:
+ void onOutgoingChannelCreated(Telepathy::Client::PendingOperation *);
+ void onOutgoingChannelReady(Telepathy::Client::PendingOperation *);
+ void onIncomingChannelReady(Telepathy::Client::PendingOperation *);
void onCallTerminated(QObject *);
private:
+ QList<Telepathy::Client::StreamedMediaChannel *> mChannels;
QList<CallWidget *> mCalls;
};
diff --git a/examples/call/call-widget.cpp b/examples/call/call-widget.cpp
index 4a43540..284c96c 100644
--- a/examples/call/call-widget.cpp
+++ b/examples/call/call-widget.cpp
@@ -21,6 +21,8 @@
#include "call-widget.h"
#include "_gen/call-widget.moc.hpp"
+#include "video-widget.h"
+
#include <TelepathyQt4/Client/Channel>
#include <TelepathyQt4/Client/Connection>
#include <TelepathyQt4/Client/Contact>
@@ -29,20 +31,24 @@
#include <TelepathyQt4/Client/PendingReady>
#include <TelepathyQt4/Client/StreamedMediaChannel>
-#include <QAction>
#include <QDebug>
-#include <QLabel>
#include <QHBoxLayout>
+#include <QLabel>
#include <QPushButton>
-#include <QStackedWidget>
-#include <QVariantMap>
+#include <QStatusBar>
+#include <QVBoxLayout>
using namespace Telepathy::Client;
-CallWidget::CallWidget(const QSharedPointer<Contact> &contact,
+CallWidget::CallWidget(StreamedMediaChannel *chan,
+ const QSharedPointer<Contact> &contact,
QWidget *parent)
: QWidget(parent),
- mContact(contact)
+ mChan(chan),
+ mContact(contact),
+ mTfChan(new FarsightChannel(chan, this)),
+ mPmsAudio(0),
+ mPmsVideo(0)
{
setWindowTitle(QString("Call (%1)").arg(mContact->id()));
@@ -50,37 +56,16 @@ CallWidget::CallWidget(const QSharedPointer<Contact> &contact,
setupGui();
- QVariantMap request;
- request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType"),
- TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA);
- request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandleType"),
- Telepathy::HandleTypeContact);
- request.insert(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".TargetHandle"),
- contact->handle()[0]);
-
- Connection *conn = contact->manager()->connection();
- connect(conn->ensureChannel(request),
- SIGNAL(finished(Telepathy::Client::PendingOperation*)),
- SLOT(onChannelCreated(Telepathy::Client::PendingOperation*)));
-}
-
-CallWidget::CallWidget(const ChannelPtr &chan,
- QWidget *parent)
- : QWidget(parent),
- mChan(chan)
-{
- setWindowTitle(QString("Call"));
-
- setAttribute(Qt::WA_DeleteOnClose);
-
- setupGui();
-
connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams),
SIGNAL(finished(Telepathy::Client::PendingOperation*)),
SLOT(onChannelReady(Telepathy::Client::PendingOperation*)));
- connect(mChan.data(),
- SIGNAL(invalidated(DBusProxy *, const QString &, const QString &)),
- SLOT(onChannelInvalidated(DBusProxy *, const QString &, const QString &)));
+ connect(mChan,
+ SIGNAL(invalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)),
+ SLOT(onChannelInvalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)));
+
+ connect(mTfChan,
+ SIGNAL(statusChanged(Telepathy::Client::FarsightChannel::Status)),
+ SLOT(onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status)));
}
CallWidget::~CallWidget()
@@ -92,59 +77,93 @@ CallWidget::~CallWidget()
void CallWidget::setupGui()
{
- QHBoxLayout *mainBox = new QHBoxLayout;
+ QVBoxLayout *mainBox = new QVBoxLayout;
- mStack = new QStackedWidget();
+ // buttons
+ QHBoxLayout *btnBox = new QHBoxLayout;
- mLblStatus = new QLabel("Initiating...");
- mLblStatus->setAlignment(Qt::AlignCenter);
- mStack->addWidget(mLblStatus);
+ mBtnHangup = new QPushButton("Hangup");
+ connect(mBtnHangup,
+ SIGNAL(clicked(bool)),
+ SLOT(onBtnHangupClicked()));
+ btnBox->addWidget(mBtnHangup);
- QFrame *frame = new QFrame;
+ mBtnSendAudio = new QPushButton("Send Audio");
+ mBtnSendAudio->setCheckable(true);
+ mBtnSendAudio->setChecked(true);
+ mBtnSendAudio->setEnabled(false);
+ connect(mBtnSendAudio,
+ SIGNAL(toggled(bool)),
+ SLOT(onBtnSendAudioToggled(bool)));
+ btnBox->addWidget(mBtnSendAudio);
- QHBoxLayout *hbox = new QHBoxLayout;
+ mBtnSendVideo = new QPushButton("Send Video");
+ mBtnSendVideo->setCheckable(true);
+ mBtnSendVideo->setChecked(false);
+ mBtnSendVideo->setEnabled(false);
+ connect(mBtnSendVideo,
+ SIGNAL(toggled(bool)),
+ SLOT(onBtnSendVideoToggled(bool)));
+ btnBox->addWidget(mBtnSendVideo);
- mBtnAccept = new QPushButton("Call");
- mBtnAccept->setEnabled(false);
- connect(mBtnAccept,
- SIGNAL(clicked(bool)),
- SLOT(onBtnAcceptClicked()));
- hbox->addWidget(mBtnAccept);
- mBtnReject = new QPushButton("Terminate");
- mBtnReject->setEnabled(false);
- connect(mBtnReject,
- SIGNAL(clicked(bool)),
- SLOT(onBtnRejectClicked()));
- hbox->addWidget(mBtnReject);
+ mainBox->addLayout(btnBox);
- frame->setLayout(hbox);
+ // video
+ QHBoxLayout *videoBox = new QHBoxLayout;
- mStack->addWidget(frame);
+ VideoWidget *videoWidget = mTfChan->videoWidget();
+ videoWidget->setMinimumSize(320, 240);
+ videoBox->addWidget(videoWidget);
- mStack->setCurrentIndex(0);
+ QVBoxLayout *previewBox = new QVBoxLayout;
- mainBox->addWidget(mStack);
+ VideoWidget *videoPreview = mTfChan->videoPreview();
+ videoPreview->setFixedSize(160, 120);
+ previewBox->addWidget(videoPreview);
- setLayout(mainBox);
-}
+ previewBox->addStretch(1);
-void CallWidget::onChannelCreated(PendingOperation *op)
-{
- if (op->isError()) {
- qWarning() << "CallWidget::onChannelCreated: channel cannot be created:" <<
- op->errorName() << "-" << op->errorMessage();
- mLblStatus->setText("Unable to establish call");
- mStack->setCurrentIndex(0);
- return;
- }
+ videoBox->addLayout(previewBox);
- PendingChannel *pc = qobject_cast<PendingChannel *>(op);
+ mainBox->addLayout(videoBox);
- mChan = pc->channel();
+ // stream status
+ QFrame *frame = new QFrame;
+ frame->setFrameStyle(QFrame::Box | QFrame::Sunken);
- connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams),
- SIGNAL(finished(Telepathy::Client::PendingOperation*)),
- SLOT(onChannelReady(Telepathy::Client::PendingOperation*)));
+ QVBoxLayout *streamBox = new QVBoxLayout;
+
+ QLabel *lbl = new QLabel(QLatin1String("<b>Streams</b>"));
+ streamBox->addWidget(lbl);
+ streamBox->addSpacing(4);
+
+ lbl = new QLabel(QLatin1String("<b>Audio</b>"));
+ streamBox->addWidget(lbl);
+ mLblAudioDirection = new QLabel(QLatin1String("Direction: None"));
+ streamBox->addWidget(mLblAudioDirection);
+ mLblAudioState = new QLabel(QLatin1String("State: Disconnected"));
+ streamBox->addWidget(mLblAudioState);
+ streamBox->addSpacing(4);
+
+ lbl = new QLabel(QLatin1String("<b>Video</b>"));
+ streamBox->addWidget(lbl);
+ mLblVideoDirection = new QLabel(QLatin1String("Direction: None"));
+ streamBox->addWidget(mLblVideoDirection);
+ mLblVideoState = new QLabel(QLatin1String("State: Disconnected"));
+ streamBox->addWidget(mLblVideoState);
+
+ streamBox->addStretch(1);
+ frame->setLayout(streamBox);
+
+ videoBox->addSpacing(4);
+ frame->setLayout(streamBox);
+ videoBox->addWidget(frame);
+
+ // status bar
+ mStatusBar = new QStatusBar;
+ mainBox->addWidget(mStatusBar);
+
+ setLayout(mainBox);
}
void CallWidget::onChannelReady(PendingOperation *op)
@@ -152,37 +171,37 @@ void CallWidget::onChannelReady(PendingOperation *op)
if (op->isError()) {
qWarning() << "CallWidget::onChannelReady: channel cannot become ready:" <<
op->errorName() << "-" << op->errorMessage();
- mLblStatus->setText("Unable to establish call");
- mStack->setCurrentIndex(0);
+ mChan->requestClose();
+ callEnded(QLatin1String("Unable to establish call"));
return;
}
- mStack->setCurrentIndex(1);
-
- StreamedMediaChannel *streamChan =
- qobject_cast<StreamedMediaChannel *>(mChan.data());
- if (streamChan->awaitingLocalAnswer()) {
- mBtnAccept->setText("Accept");
- mBtnAccept->setEnabled(true);
- mBtnReject->setText("Reject");
- mBtnReject->setEnabled(true);
- } else {
- mBtnAccept->setText("Call");
- mBtnAccept->setEnabled(false);
- mBtnReject->setText("Terminate");
- mBtnReject->setEnabled(true);
-
- PendingMediaStreams *pms =
- streamChan->requestStream(mContact, Telepathy::MediaStreamTypeAudio);
- connect(pms,
- SIGNAL(finished(Telepathy::Client::PendingOperation*)),
- SLOT(onStreamCreated(Telepathy::Client::PendingOperation*)));
+#if 1
+ MediaStreams streams = mChan->streams();
+ qDebug() << "CallWidget::onChannelReady: number of streams:" << streams.size();
+ qDebug() << " streams:";
+ foreach (const QSharedPointer<MediaStream> &stream, streams) {
+ qDebug() << " " <<
+ (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video");
+ }
+#endif
+
+ connect(mChan,
+ SIGNAL(streamAdded(const QSharedPointer<Telepathy::Client::MediaStream> &)),
+ SLOT(onStreamAdded(const QSharedPointer<Telepathy::Client::MediaStream> &)));
+
+ QSharedPointer<MediaStream> stream = streamForType(Telepathy::MediaStreamTypeAudio);
+ if (stream) {
+ connectStreamSignals(stream);
+ onStreamDirectionChanged(stream.data(), stream->direction(),
+ stream->pendingSend());
+ onStreamStateChanged(stream.data(), stream->state());
}
- mTfChan = new FarsightChannel(streamChan, this);
- connect(mTfChan,
- SIGNAL(statusChanged(Telepathy::Client::FarsightChannel::Status)),
- SLOT(onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status)));
+ mBtnSendAudio->setEnabled(true);
+ mBtnSendVideo->setEnabled(true);
+
+ onBtnSendAudioToggled(mBtnSendAudio->isChecked());
}
void CallWidget::onChannelInvalidated(DBusProxy *proxy,
@@ -190,45 +209,237 @@ void CallWidget::onChannelInvalidated(DBusProxy *proxy,
{
qDebug() << "CallWindow::onChannelInvalidated: channel became invalid:" <<
errorName << "-" << errorMessage;
- mLblStatus->setText("Call terminated");
- mStack->setCurrentIndex(0);
+ callEnded(errorMessage);
}
void CallWidget::onStreamCreated(PendingOperation *op)
{
+ if (op == mPmsAudio) {
+ mPmsAudio = 0;
+ } else if (op == mPmsVideo) {
+ mPmsVideo = 0;
+ }
+
if (op->isError()) {
- qWarning() << "CallWidget::onStreamCreated: unable to create audio stream:" <<
+ qWarning() << "CallWidget::onStreamCreated: unable to create stream:" <<
op->errorName() << "-" << op->errorMessage();
- mLblStatus->setText("Unable to establish call");
- mStack->setCurrentIndex(0);
+
+ // we cannot create the stream for some reason, update buttons
+ if (!streamForType(Telepathy::MediaStreamTypeAudio)) {
+ mBtnSendAudio->setChecked(false);
+ }
+ if (!streamForType(Telepathy::MediaStreamTypeVideo)) {
+ mBtnSendVideo->setChecked(false);
+ }
return;
}
+
+ PendingMediaStreams *pms = qobject_cast<PendingMediaStreams *>(op);
+ Q_ASSERT(pms->streams().size() == 1);
+ QSharedPointer<MediaStream> stream = pms->streams().first();
+ connectStreamSignals(stream);
+ updateStreamDirection(stream);
+ onStreamDirectionChanged(stream.data(), stream->direction(),
+ stream->pendingSend());
+ onStreamStateChanged(stream.data(), stream->state());
}
-void CallWidget::onTfChannelStatusChanged(FarsightChannel::Status status)
+void CallWidget::onStreamAdded(const QSharedPointer<MediaStream> &stream)
+{
+ connectStreamSignals(stream);
+ updateStreamDirection(stream);
+ onStreamDirectionChanged(stream.data(), stream->direction(),
+ stream->pendingSend());
+ onStreamStateChanged(stream.data(), stream->state());
+}
+
+void CallWidget::onStreamRemoved(MediaStream *stream)
+{
+ if (stream->type() == Telepathy::MediaStreamTypeAudio) {
+ mBtnSendAudio->setChecked(false);
+ } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
+ mBtnSendVideo->setChecked(false);
+ }
+}
+
+void CallWidget::onStreamDirectionChanged(MediaStream *stream,
+ Telepathy::MediaStreamDirection direction,
+ Telepathy::MediaStreamPendingSend pendingSend)
{
- if (status == FarsightChannel::StatusDisconnected) {
- mLblStatus->setText("Call terminated");
- mStack->setCurrentIndex(0);
+ qDebug() << "CallWidget::onStreamDirectionChanged: stream " <<
+ (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
+ "direction changed to" << direction;
+
+ QLabel *lbl;
+ if (stream->type() == Telepathy::MediaStreamTypeAudio) {
+ lbl = mLblAudioDirection;
+ } else {
+ lbl = mLblVideoDirection;
+ }
+
+ if (direction == Telepathy::MediaStreamDirectionSend) {
+ lbl->setText(QLatin1String("Direction: Sending"));
+ } else if (direction == Telepathy::MediaStreamDirectionReceive) {
+ lbl->setText(QLatin1String("Direction: Receiving"));
+ } else if (direction == (Telepathy::MediaStreamDirectionSend | Telepathy::MediaStreamDirectionReceive)) {
+ lbl->setText(QLatin1String("Direction: Sending/Receiving"));
+ } else {
+ lbl->setText(QLatin1String("Direction: None"));
}
}
-void CallWidget::onBtnAcceptClicked()
+void CallWidget::onStreamStateChanged(MediaStream *stream,
+ Telepathy::MediaStreamState state)
{
- StreamedMediaChannel *streamChan =
- qobject_cast<StreamedMediaChannel *>(mChan.data());
- streamChan->acceptCall();
+ qDebug() << "CallWidget::onStreamStateChanged: stream " <<
+ (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
+ "state changed to" << state;
- mBtnAccept->setText("Call");
- mBtnAccept->setEnabled(false);
- mBtnReject->setText("Terminate");
- mBtnReject->setEnabled(true);
+ QLabel *lbl;
+ if (stream->type() == Telepathy::MediaStreamTypeAudio) {
+ lbl = mLblAudioState;
+ } else {
+ lbl = mLblVideoState;
+ }
+
+ if (state == Telepathy::MediaStreamStateDisconnected) {
+ lbl->setText(QLatin1String("State: Disconnected"));
+ } else if (state == Telepathy::MediaStreamStateConnecting) {
+ lbl->setText(QLatin1String("State: Connecting"));
+ } else if (state == Telepathy::MediaStreamStateConnected) {
+ lbl->setText(QLatin1String("State: Connected"));
+ }
+}
+
+void CallWidget::onTfChannelStatusChanged(FarsightChannel::Status status)
+{
+ switch (status) {
+ case FarsightChannel::StatusConnecting:
+ mStatusBar->showMessage("Connecting...");
+ break;
+ case FarsightChannel::StatusConnected:
+ mStatusBar->showMessage("Connected");
+ break;
+ case FarsightChannel::StatusDisconnected:
+ mChan->requestClose();
+ callEnded("Call terminated");
+ break;
+ }
}
-void CallWidget::onBtnRejectClicked()
+void CallWidget::onBtnHangupClicked()
{
mChan->requestClose();
+ callEnded("Call terminated");
+}
- mLblStatus->setText("Call terminated");
- mStack->setCurrentIndex(0);
+void CallWidget::onBtnSendAudioToggled(bool checked)
+{
+ QSharedPointer<MediaStream> stream =
+ streamForType(Telepathy::MediaStreamTypeAudio);
+ qDebug() << "CallWidget::onBtnSendAudioToggled: checked:" << checked;
+ if (!stream) {
+ if (mPmsAudio) {
+ return;
+ }
+ qDebug() << "CallWidget::onBtnSendAudioToggled: creating audio stream";
+ mPmsAudio = mChan->requestStream(mContact, Telepathy::MediaStreamTypeAudio);
+ connect(mPmsAudio,
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onStreamCreated(Telepathy::Client::PendingOperation*)));
+ } else {
+ updateStreamDirection(stream);
+ }
+}
+
+void CallWidget::onBtnSendVideoToggled(bool checked)
+{
+ QSharedPointer<MediaStream> stream =
+ streamForType(Telepathy::MediaStreamTypeVideo);
+ qDebug() << "CallWidget::onBtnSendVideoToggled: checked:" << checked;
+ if (!stream) {
+ if (mPmsVideo) {
+ return;
+ }
+ qDebug() << "CallWidget::onBtnSendVideoToggled: creating video stream";
+ mPmsVideo = mChan->requestStream(mContact, Telepathy::MediaStreamTypeVideo);
+ connect(mPmsVideo,
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onStreamCreated(Telepathy::Client::PendingOperation*)));
+ } else {
+ updateStreamDirection(stream);
+ }
+}
+
+QSharedPointer<MediaStream> CallWidget::streamForType(Telepathy::MediaStreamType type) const
+{
+ MediaStreams streams = mChan->streams();
+ foreach (const QSharedPointer<MediaStream> &stream, streams) {
+ if (stream->type() == type) {
+ return stream;
+ }
+ }
+ return QSharedPointer<MediaStream>();
+}
+
+void CallWidget::connectStreamSignals(const QSharedPointer<MediaStream> &stream)
+{
+ connect(stream.data(),
+ SIGNAL(removed(Telepathy::Client::MediaStream *)),
+ SLOT(onStreamRemoved(Telepathy::Client::MediaStream *)));
+ connect(stream.data(),
+ SIGNAL(directionChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamDirection,
+ Telepathy::MediaStreamPendingSend)),
+ SLOT(onStreamDirectionChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamDirection,
+ Telepathy::MediaStreamPendingSend)));
+ connect(stream.data(),
+ SIGNAL(stateChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamState)),
+ SLOT(onStreamStateChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamState)));
+}
+
+void CallWidget::updateStreamDirection(const QSharedPointer<MediaStream> &stream)
+{
+ bool checked = false;
+ if (stream->type() == Telepathy::MediaStreamTypeAudio) {
+ checked = mBtnSendAudio->isChecked();
+ } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
+ checked = mBtnSendVideo->isChecked();
+ }
+
+ qDebug() << "CallWidget::updateStreamDirection: current stream direction:" <<
+ stream->direction() << "- checked:" << checked;
+
+ if (checked) {
+ if (!(stream->direction() & Telepathy::MediaStreamDirectionSend)) {
+ int dir = stream->direction() | Telepathy::MediaStreamDirectionSend;
+ stream->requestStreamDirection((Telepathy::MediaStreamDirection) dir);
+ qDebug() << "CallWidget::updateStreamDirection: start sending " <<
+ (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video");
+ }
+ } else {
+ if (stream->direction() & Telepathy::MediaStreamDirectionSend) {
+ int dir = stream->direction() & ~Telepathy::MediaStreamDirectionSend;
+ qDebug() << "CallWidget::updateStreamDirection: stop sending " <<
+ (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video");
+ stream->requestStreamDirection((Telepathy::MediaStreamDirection) dir);
+ }
+ }
+}
+
+void CallWidget::callEnded(const QString &message)
+{
+ mStatusBar->showMessage(message);
+ disconnect(mChan,
+ SIGNAL(invalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)),
+ this,
+ SLOT(onChannelInvalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)));
+ disconnect(mTfChan,
+ SIGNAL(statusChanged(Telepathy::Client::FarsightChannel::Status)),
+ this,
+ SLOT(onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status)));
+ setEnabled(false);
}
diff --git a/examples/call/call-widget.h b/examples/call/call-widget.h
index d283832..f6eef6c 100644
--- a/examples/call/call-widget.h
+++ b/examples/call/call-widget.h
@@ -25,6 +25,7 @@
#include <QWidget>
#include <TelepathyQt4/Client/Channel>
+#include <TelepathyQt4/Constants>
#include "farsight-channel.h"
@@ -32,50 +33,75 @@ namespace Telepathy {
namespace Client {
class Contact;
class DBusProxy;
+class MediaStream;
+class PendingMediaStreams;
class PendingOperation;
+class StreamedMediaChannel;
}
}
class QLabel;
class QPushButton;
-class QStackedWidget;
+class QStatusBar;
class CallWidget : public QWidget
{
Q_OBJECT
public:
- CallWidget(const QSharedPointer<Telepathy::Client::Contact> &contact,
- QWidget *parent = 0);
- CallWidget(const Telepathy::Client::ChannelPtr &chan,
+ CallWidget(Telepathy::Client::StreamedMediaChannel *channel,
+ const QSharedPointer<Telepathy::Client::Contact> &contact,
QWidget *parent = 0);
virtual ~CallWidget();
+ Telepathy::Client::StreamedMediaChannel *channel() const { return mChan; }
QSharedPointer<Telepathy::Client::Contact> contact() const { return mContact; }
- Telepathy::Client::ChannelPtr channel() const { return mChan; }
private Q_SLOTS:
- void onChannelCreated(Telepathy::Client::PendingOperation *);
void onChannelReady(Telepathy::Client::PendingOperation *);
void onChannelInvalidated(Telepathy::Client::DBusProxy *,
const QString &, const QString &);
void onStreamCreated(Telepathy::Client::PendingOperation *);
+ void onStreamAdded(const QSharedPointer<Telepathy::Client::MediaStream> &);
+ void onStreamRemoved(Telepathy::Client::MediaStream *);
+ void onStreamDirectionChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamDirection,
+ Telepathy::MediaStreamPendingSend);
+ void onStreamStateChanged(Telepathy::Client::MediaStream *,
+ Telepathy::MediaStreamState);
void onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status);
- void onBtnAcceptClicked();
- void onBtnRejectClicked();
+ void onBtnHangupClicked();
+ void onBtnSendAudioToggled(bool);
+ void onBtnSendVideoToggled(bool);
private:
void createActions();
void setupGui();
- Telepathy::Client::ChannelPtr mChan;
+ QSharedPointer<Telepathy::Client::MediaStream> streamForType(Telepathy::MediaStreamType type) const;
+ void connectStreamSignals(const QSharedPointer<Telepathy::Client::MediaStream> &stream);
+ void updateStreamDirection(const QSharedPointer<Telepathy::Client::MediaStream> &stream);
+
+ void callEnded(const QString &message);
+
+ Telepathy::Client::StreamedMediaChannel *mChan;
QSharedPointer<Telepathy::Client::Contact> mContact;
Telepathy::Client::FarsightChannel *mTfChan;
- QPushButton *mBtnAccept;
- QPushButton *mBtnReject;
- QLabel *mLblStatus;
- QStackedWidget *mStack;
+
+ Telepathy::Client::PendingMediaStreams *mPmsAudio;
+ Telepathy::Client::PendingMediaStreams *mPmsVideo;
+
+ QPushButton *mBtnHangup;
+ QPushButton *mBtnSendAudio;
+ QPushButton *mBtnSendVideo;
+
+ QLabel *mLblAudioDirection;
+ QLabel *mLblVideoDirection;
+ QLabel *mLblAudioState;
+ QLabel *mLblVideoState;
+
+ QStatusBar *mStatusBar;
};
#endif
diff --git a/examples/call/call-window.cpp b/examples/call/call-window.cpp
index a5c6058..1e3962f 100644
--- a/examples/call/call-window.cpp
+++ b/examples/call/call-window.cpp
@@ -120,6 +120,7 @@ void CallWindow::onConnectionConnected(Telepathy::Client::PendingOperation *op)
Telepathy::CapabilityPair capability = {
TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA,
Telepathy::ChannelMediaCapabilityAudio |
+ Telepathy::ChannelMediaCapabilityVideo |
Telepathy::ChannelMediaCapabilityNATTraversalSTUN |
Telepathy::ChannelMediaCapabilityNATTraversalGTalkP2P
};
@@ -159,10 +160,9 @@ void CallWindow::onNewChannels(const Telepathy::ChannelDetailsList &channels)
if (channelType == TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
!requested) {
- ChannelPtr channel = ChannelPtr(
- new StreamedMediaChannel(mConn.data(),
+ StreamedMediaChannel *channel = new StreamedMediaChannel(mConn.data(),
details.channel.path(),
- details.properties));
+ details.properties);
mCallHandler->addIncomingCall(channel);
qDebug() << "CallWindow::onNewChannels: new call received";
}
diff --git a/examples/call/farsight-channel.cpp b/examples/call/farsight-channel.cpp
index 1d4b8d3..d8d8fe8 100644
--- a/examples/call/farsight-channel.cpp
+++ b/examples/call/farsight-channel.cpp
@@ -22,6 +22,8 @@
#include "farsight-channel.h"
#include "_gen/farsight-channel.moc.hpp"
+#include "video-widget.h"
+
#include <QDebug>
#include <telepathy-farsight/channel.h>
@@ -61,6 +63,10 @@ struct FarsightChannel::Private
GstElement *pipeline;
GstElement *audioInput;
GstElement *audioOutput;
+ GstElement *videoInput;
+ GstElement *videoTee;
+ VideoWidget *videoPreview;
+ VideoWidget *videoOutput;
};
FarsightChannel::Private::Private(FarsightChannel *parent,
@@ -72,7 +78,11 @@ FarsightChannel::Private::Private(FarsightChannel *parent,
bus(0),
pipeline(0),
audioInput(0),
- audioOutput(0)
+ audioOutput(0),
+ videoInput(0),
+ videoTee(0),
+ videoPreview(0),
+ videoOutput(0)
{
TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
if (!dbus) {
@@ -128,13 +138,13 @@ FarsightChannel::Private::Private(FarsightChannel *parent,
pipeline = gst_pipeline_new(NULL);
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
- audioInput = gst_element_factory_make("gconfaudiosrc", NULL);
+ audioInput = gst_element_factory_make("autoaudiosrc", NULL);
gst_object_ref(audioInput);
gst_object_sink(audioInput);
- audioOutput = gst_bin_new("bin");
+ audioOutput = gst_bin_new("audio-output-bin");
GstElement *resample = gst_element_factory_make("audioresample", NULL);
- GstElement *audioSink = gst_element_factory_make("gconfaudiosink", NULL);
+ GstElement *audioSink = gst_element_factory_make("autoaudiosink", NULL);
gst_bin_add_many(GST_BIN(audioOutput), resample, audioSink, NULL);
gst_element_link_many(resample, audioSink, NULL);
GstPad *sink = gst_element_get_static_pad(resample, "sink");
@@ -144,6 +154,42 @@ FarsightChannel::Private::Private(FarsightChannel *parent,
gst_object_ref(audioOutput);
gst_object_sink(audioOutput);
+ videoInput = gst_bin_new("video-input-bin");
+ GstElement *scale = gst_element_factory_make("videoscale", NULL);
+ GstElement *rate = gst_element_factory_make("videorate", NULL);
+ GstElement *colorspace = gst_element_factory_make("ffmpegcolorspace", NULL);
+ GstElement *capsfilter = gst_element_factory_make("capsfilter", NULL);
+ GstCaps *caps = gst_caps_new_simple("video/x-raw-yuv",
+ "width", G_TYPE_INT, 320,
+ "height", G_TYPE_INT, 240,
+ NULL);
+ g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
+ GstElement *videoSrc = gst_element_factory_make("autovideosrc", NULL);
+ // GstElement *videoSrc = gst_element_factory_make("videotestsrc", NULL);
+ gst_bin_add_many(GST_BIN(videoInput), videoSrc, scale, rate,
+ colorspace, capsfilter, NULL);
+ gst_element_link_many(videoSrc, scale, rate, colorspace, capsfilter, NULL);
+ GstPad *src = gst_element_get_static_pad(capsfilter, "src");
+ ghost = gst_ghost_pad_new("src", src);
+ Q_ASSERT(gst_element_add_pad(GST_ELEMENT(videoInput), ghost));
+ gst_object_unref(G_OBJECT(src));
+ gst_object_ref(audioInput);
+ gst_object_sink(audioInput);
+
+ videoTee = gst_element_factory_make("tee", NULL);
+ gst_object_ref(videoTee);
+ gst_object_sink(videoTee);
+
+ videoPreview = new VideoWidget(bus);
+ GstElement *videoPreviewElement = videoPreview->element();
+
+ gst_bin_add_many(GST_BIN(pipeline), videoInput, videoTee,
+ videoPreviewElement, NULL);
+ gst_element_link_many(videoInput, videoTee,
+ videoPreviewElement, NULL);
+
+ videoOutput = new VideoWidget(bus);
+
gst_element_set_state(pipeline, GST_STATE_PLAYING);
status = StatusConnecting;
@@ -229,7 +275,8 @@ void FarsightChannel::Private::onStreamCreated(TfChannel *tfChannel,
gst_pad_link(pad, sink);
break;
case TP_MEDIA_STREAM_TYPE_VIDEO:
- // TODO
+ pad = gst_element_get_request_pad(self->videoTee, "src%d");
+ gst_pad_link(pad, sink);
break;
default:
Q_ASSERT(false);
@@ -254,8 +301,7 @@ void FarsightChannel::Private::onSrcPadAdded(TfStream *stream,
g_object_ref(element);
break;
case TP_MEDIA_STREAM_TYPE_VIDEO:
- // TODO
- return;
+ element = self->videoOutput->element();
break;
default:
Q_ASSERT(false);
@@ -289,5 +335,15 @@ FarsightChannel::~FarsightChannel()
delete mPriv;
}
+VideoWidget *FarsightChannel::videoPreview() const
+{
+ return mPriv->videoPreview;
+}
+
+VideoWidget *FarsightChannel::videoWidget() const
+{
+ return mPriv->videoOutput;
+}
+
}
}
diff --git a/examples/call/farsight-channel.h b/examples/call/farsight-channel.h
index bf68f8d..7de1f3e 100644
--- a/examples/call/farsight-channel.h
+++ b/examples/call/farsight-channel.h
@@ -23,6 +23,7 @@
#define _TelepathyQt4_examples_call_farsight_channel_h_HEADER_GUARD_
#include <QObject>
+#include <QMetaType>
#include <telepathy-farsight/channel.h>
@@ -31,10 +32,12 @@ namespace Client {
class Connection;
class StreamedMediaChannel;
+class VideoWidget;
class FarsightChannel : public QObject
{
Q_OBJECT
+ Q_ENUMS(Status)
public:
enum Status {
@@ -48,8 +51,10 @@ public:
Status status() const;
+ VideoWidget *videoPreview() const;
+ VideoWidget *videoWidget() const;
+
// TODO add a way to change input and output devices
- // add video support
Q_SIGNALS:
void statusChanged(Telepathy::Client::FarsightChannel::Status status);
@@ -63,4 +68,6 @@ private:
}
}
+Q_DECLARE_METATYPE(Telepathy::Client::FarsightChannel::Status)
+
#endif
diff --git a/examples/call/main.cpp b/examples/call/main.cpp
index b78a140..1bec37c 100644
--- a/examples/call/main.cpp
+++ b/examples/call/main.cpp
@@ -9,6 +9,7 @@
#include <QtGui>
#include "call-window.h"
+#include "farsight-channel.h"
int main(int argc, char **argv)
{
@@ -22,9 +23,12 @@ int main(int argc, char **argv)
return 1;
}
+ app.setAttribute(Qt::AA_NativeWindows);
+
Telepathy::registerTypes();
Telepathy::enableDebug(true);
Telepathy::enableWarnings(true);
+ qRegisterMetaType<Telepathy::Client::FarsightChannel::Status>();
CallWindow w(argv[1], argv[2]);
w.show();
diff --git a/examples/call/video-widget.cpp b/examples/call/video-widget.cpp
new file mode 100644
index 0000000..14c2da9
--- /dev/null
+++ b/examples/call/video-widget.cpp
@@ -0,0 +1,166 @@
+/*
+ * This file is part of TelepathyQt4
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "video-widget.h"
+#include "_gen/video-widget.moc.hpp"
+
+#include <QApplication>
+#include <QDebug>
+#include <QPainter>
+#include <QThread>
+
+#include <gst/interfaces/xoverlay.h>
+#include <gst/farsight/fs-element-added-notifier.h>
+
+extern void qt_x11_set_global_double_buffer(bool);
+
+namespace Telepathy {
+namespace Client {
+
+struct VideoWidget::Private {
+ Private(VideoWidget *parent, GstBus *bus);
+ ~Private();
+
+ static void onElementAdded(FsElementAddedNotifier *notifier,
+ GstBin *bin, GstElement *element,
+ Private *self);
+ static void onSyncMessage(GstBus *bus, GstMessage *message,
+ Private *self);
+
+ VideoWidget *parent;
+ GstBus *bus;
+ FsElementAddedNotifier *notifier;
+ GstElement *sink;
+ GstElement *overlay;
+};
+
+VideoWidget::Private::Private(VideoWidget *parent, GstBus *bus)
+ : parent(parent),
+ bus((GstBus *) gst_object_ref(bus)),
+ overlay(0)
+{
+ notifier = fs_element_added_notifier_new();
+ g_signal_connect(notifier, "element-added",
+ G_CALLBACK(&VideoWidget::Private::onElementAdded),
+ this);
+
+ sink = gst_element_factory_make("autovideosink", NULL);
+ gst_object_ref(sink);
+ gst_object_sink(sink);
+
+ fs_element_added_notifier_add(notifier, GST_BIN(sink));
+ gst_bus_enable_sync_message_emission(bus);
+
+ g_signal_connect(bus, "sync-message",
+ G_CALLBACK(&VideoWidget::Private::onSyncMessage),
+ this);
+}
+
+VideoWidget::Private::~Private()
+{
+ g_object_unref(bus);
+ g_object_unref(sink);
+}
+
+void VideoWidget::Private::onElementAdded(FsElementAddedNotifier *notifier,
+ GstBin *bin, GstElement *element, VideoWidget::Private *self)
+{
+ if (!self->overlay && GST_IS_X_OVERLAY(element)) {
+ self->overlay = element;
+ QMetaObject::invokeMethod(self->parent, "windowExposed", Qt::QueuedConnection);
+ }
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(element),
+ "force-aspect-ratio")) {
+ g_object_set(G_OBJECT(element), "force-aspect-ratio", TRUE, NULL);
+ }
+}
+
+void VideoWidget::Private::onSyncMessage(GstBus *bus, GstMessage *message,
+ VideoWidget::Private *self)
+{
+ if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_ELEMENT) {
+ return;
+ }
+
+ if (GST_MESSAGE_SRC(message) != (GstObject *) self->overlay) {
+ return;
+ }
+
+ const GstStructure *s = gst_message_get_structure (message);
+
+ if (gst_structure_has_name(s, "prepare-xwindow-id") && self->overlay) {
+ QMetaObject::invokeMethod(self->parent, "setOverlay", Qt::QueuedConnection);
+ }
+}
+
+VideoWidget::VideoWidget(GstBus *bus, QWidget *parent)
+ : QWidget(parent),
+ mPriv(new Private(this, bus))
+{
+ qt_x11_set_global_double_buffer(false);
+
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::black);
+ setPalette(palette);
+ setAutoFillBackground(true);
+}
+
+VideoWidget::~VideoWidget()
+{
+ delete mPriv;
+}
+
+GstElement *VideoWidget::element() const
+{
+ return mPriv->sink;
+}
+
+bool VideoWidget::eventFilter(QEvent *ev)
+{
+ if (ev->type() == QEvent::Show) {
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ setOverlay();
+ }
+ return false;
+}
+
+void VideoWidget::setOverlay()
+{
+ if (mPriv->overlay && GST_IS_X_OVERLAY(mPriv->overlay)) {
+ WId windowId = winId();
+ QApplication::syncX();
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(mPriv->overlay),
+ windowId);
+ }
+ windowExposed();
+}
+
+void VideoWidget::windowExposed()
+{
+ QApplication::syncX();
+ if (mPriv->overlay && GST_IS_X_OVERLAY(mPriv->overlay)) {
+ gst_x_overlay_expose(GST_X_OVERLAY(mPriv->overlay));
+ }
+}
+
+}
+}
diff --git a/examples/call/video-widget.h b/examples/call/video-widget.h
new file mode 100644
index 0000000..de1b130
--- /dev/null
+++ b/examples/call/video-widget.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of TelepathyQt4
+ *
+ * Copyright (C) 2009 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _TelepathyQt4_examples_call_video_widget_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_video_widget_h_HEADER_GUARD_
+
+#include <QWidget>
+
+#include <gst/gst.h>
+
+namespace Telepathy {
+namespace Client {
+
+class VideoWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ VideoWidget(GstBus *bus, QWidget *parent = 0);
+ virtual ~VideoWidget();
+
+ GstElement *element() const;
+
+protected:
+ bool eventFilter(QEvent *ev);
+
+private Q_SLOTS:
+ void setOverlay();
+ void windowExposed();
+
+private:
+ struct Private;
+ friend struct Private;
+ Private *mPriv;
+};
+
+} // Telepathy::Client
+} // Telepathy
+
+#endif
--
1.5.6.5
More information about the telepathy-commits
mailing list