[Telepathy-commits] [telepathy-qt4/master] call example: Added to repository.
Andre Moreira Magalhaes (andrunko)
andre.magalhaes at collabora.co.uk
Fri Mar 13 14:14:34 PDT 2009
This is a simple example to make voice calls, video not supported.
P.s.: Maybe we should move FarsightChannel to the public API.
---
examples/call/Makefile.am | 18 +++-
examples/call/call-handler.cpp | 69 ++++++++++
examples/call/call-handler.h | 55 ++++++++
examples/call/call-roster-widget.cpp | 90 +++++++++++++
examples/call/call-roster-widget.h | 60 +++++++++
examples/call/call-widget.cpp | 234 +++++++++++++++++++++++++++++++++
examples/call/call-widget.h | 81 ++++++++++++
examples/call/call-window.cpp | 170 ++++++++++++++++++++++++
examples/call/call-window.h | 69 ++++++++++
examples/call/farsight-glue.cpp | 238 ++++++++++++++++++++++++++++++++--
examples/call/farsight-glue.h | 45 ++++++-
examples/call/main.cpp | 32 +++++-
12 files changed, 1139 insertions(+), 22 deletions(-)
create mode 100644 examples/call/call-handler.cpp
create mode 100644 examples/call/call-handler.h
create mode 100644 examples/call/call-roster-widget.cpp
create mode 100644 examples/call/call-roster-widget.h
create mode 100644 examples/call/call-widget.cpp
create mode 100644 examples/call/call-widget.h
create mode 100644 examples/call/call-window.cpp
create mode 100644 examples/call/call-window.h
diff --git a/examples/call/Makefile.am b/examples/call/Makefile.am
index 4593521..b042690 100644
--- a/examples/call/Makefile.am
+++ b/examples/call/Makefile.am
@@ -12,14 +12,28 @@ call_LDADD = \
$(QTGUI_LIBS) \
$(QTDBUS_LIBS) \
$(TP_FARSIGHT_LIBS) \
- $(top_builddir)/TelepathyQt4/libtelepathy-qt4.la
+ $(top_builddir)/TelepathyQt4/libtelepathy-qt4.la \
+ $(top_builddir)/examples/roster/libtelepathy-qt4-examples-roster.la
call_SOURCES = \
main.cpp \
+ call-handler.cpp \
+ call-handler.h \
+ call-roster-widget.cpp \
+ call-roster-widget.h \
+ call-widget.cpp \
+ call-widget.h \
+ call-window.cpp \
+ call-window.h \
farsight-glue.cpp \
farsight-glue.h
-nodist_call_SOURCES =
+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-glue.moc.hpp
BUILT_SOURCES = \
$(nodist_call_SOURCES)
diff --git a/examples/call/call-handler.cpp b/examples/call/call-handler.cpp
new file mode 100644
index 0000000..5a821cd
--- /dev/null
+++ b/examples/call/call-handler.cpp
@@ -0,0 +1,69 @@
+/*
+ * This file is part of TelepathyQt4
+ *
+ * Copyright (call) 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 "call-handler.h"
+#include "_gen/call-handler.moc.hpp"
+
+#include "call-widget.h"
+
+#include <TelepathyQt4/Client/Channel>
+#include <TelepathyQt4/Client/Contact>
+
+#include <QDebug>
+
+using namespace Telepathy::Client;
+
+CallHandler::CallHandler(QObject *parent)
+ : QObject(parent)
+{
+}
+
+CallHandler::~CallHandler()
+{
+ foreach (CallWidget *call, mCalls) {
+ call->close();
+ }
+}
+
+void CallHandler::addOutgoingCall(const QSharedPointer<Contact> &contact)
+{
+ CallWidget *call = new CallWidget(contact);
+ mCalls.append(call);
+ connect(call,
+ SIGNAL(destroyed(QObject *)),
+ SLOT(onCallTerminated(QObject *)));
+ call->show();
+}
+
+void CallHandler::addIncomingCall(const ChannelPtr &chan)
+{
+ CallWidget *call = new CallWidget(chan);
+ mCalls.append(call);
+ connect(call,
+ SIGNAL(destroyed(QObject *)),
+ SLOT(onCallTerminated(QObject *)));
+ call->show();
+}
+
+void CallHandler::onCallTerminated(QObject *obj)
+{
+ // Why does obj comes 0x0?
+ mCalls.removeOne((CallWidget *) sender());
+}
diff --git a/examples/call/call-handler.h b/examples/call/call-handler.h
new file mode 100644
index 0000000..f50c81e
--- /dev/null
+++ b/examples/call/call-handler.h
@@ -0,0 +1,55 @@
+/*
+ * 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_call_handler_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_call_handler_h_HEADER_GUARD_
+
+#include <QObject>
+#include <QSharedPointer>
+
+#include <TelepathyQt4/Client/Channel>
+
+namespace Telepathy {
+namespace Client {
+class Contact;
+}
+}
+
+class CallWidget;
+
+class CallHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ CallHandler(QObject *parent = 0);
+ virtual ~CallHandler();
+
+ void addOutgoingCall(const QSharedPointer<Telepathy::Client::Contact> &contact);
+ void addIncomingCall(const Telepathy::Client::ChannelPtr &chan);
+
+private Q_SLOTS:
+ void onCallTerminated(QObject *);
+
+private:
+ QList<CallWidget *> mCalls;
+};
+
+#endif
diff --git a/examples/call/call-roster-widget.cpp b/examples/call/call-roster-widget.cpp
new file mode 100644
index 0000000..1844855
--- /dev/null
+++ b/examples/call/call-roster-widget.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "call-roster-widget.h"
+#include "_gen/call-roster-widget.moc.hpp"
+
+#include "call-handler.h"
+#include "call-widget.h"
+
+#include <examples/roster/roster-item.h>
+
+#include <TelepathyQt4/Client/Connection>
+#include <TelepathyQt4/Client/Contact>
+#include <TelepathyQt4/Client/ContactManager>
+#include <TelepathyQt4/Client/PendingChannel>
+#include <TelepathyQt4/Client/PendingReady>
+#include <TelepathyQt4/Client/StreamedMediaChannel>
+
+#include <QAction>
+#include <QDebug>
+
+using namespace Telepathy::Client;
+
+CallRosterWidget::CallRosterWidget(CallHandler *callHandler, QWidget *parent)
+ : RosterWidget(parent),
+ mCallHandler(callHandler)
+{
+ createActions();
+ setupGui();
+}
+
+CallRosterWidget::~CallRosterWidget()
+{
+}
+
+RosterItem *CallRosterWidget::createItemForContact(const QSharedPointer<Contact> &contact,
+ bool &exists)
+{
+ return RosterWidget::createItemForContact(contact, exists);
+}
+
+void CallRosterWidget::createActions()
+{
+ mCallAction = new QAction(QLatin1String("Call Contact"), this);
+ mCallAction->setEnabled(false);
+ connect(mCallAction,
+ SIGNAL(triggered(bool)),
+ SLOT(onCallActionTriggered(bool)));
+}
+
+void CallRosterWidget::setupGui()
+{
+ QListWidget *list = listWidget();
+ list->insertAction(list->actions().first(), mCallAction);
+}
+
+void CallRosterWidget::updateActions(RosterItem *item)
+{
+ mCallAction->setEnabled(item);
+}
+
+void CallRosterWidget::onCallActionTriggered(bool checked)
+{
+ QList<QListWidgetItem *> selectedItems = listWidget()->selectedItems();
+ if (selectedItems.isEmpty()) {
+ return;
+ }
+
+ Q_ASSERT(selectedItems.size() == 1);
+ RosterItem *item = dynamic_cast<RosterItem*>(selectedItems.first());
+ QSharedPointer<Contact> contact = item->contact();
+ mCallHandler->addOutgoingCall(contact);
+}
diff --git a/examples/call/call-roster-widget.h b/examples/call/call-roster-widget.h
new file mode 100644
index 0000000..45e7fd1
--- /dev/null
+++ b/examples/call/call-roster-widget.h
@@ -0,0 +1,60 @@
+/*
+ * 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_call_roster_widget_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_call_roster_widget_h_HEADER_GUARD_
+
+#include <examples/roster/roster-widget.h>
+
+namespace Telepathy {
+namespace Client {
+class Channel;
+}
+}
+
+class CallHandler;
+class CallWidget;
+
+class CallRosterWidget : public RosterWidget
+{
+ Q_OBJECT
+
+public:
+ CallRosterWidget(CallHandler *callHandler, QWidget *parent = 0);
+ virtual ~CallRosterWidget();
+
+protected:
+ virtual RosterItem *createItemForContact(
+ const QSharedPointer<Telepathy::Client::Contact> &contact,
+ bool &exists);
+ virtual void updateActions(RosterItem *item);
+
+private Q_SLOTS:
+ void onCallActionTriggered(bool);
+
+private:
+ void createActions();
+ void setupGui();
+
+ CallHandler *mCallHandler;
+ QAction *mCallAction;
+};
+
+#endif
diff --git a/examples/call/call-widget.cpp b/examples/call/call-widget.cpp
new file mode 100644
index 0000000..4a43540
--- /dev/null
+++ b/examples/call/call-widget.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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 "call-widget.h"
+#include "_gen/call-widget.moc.hpp"
+
+#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/StreamedMediaChannel>
+
+#include <QAction>
+#include <QDebug>
+#include <QLabel>
+#include <QHBoxLayout>
+#include <QPushButton>
+#include <QStackedWidget>
+#include <QVariantMap>
+
+using namespace Telepathy::Client;
+
+CallWidget::CallWidget(const QSharedPointer<Contact> &contact,
+ QWidget *parent)
+ : QWidget(parent),
+ mContact(contact)
+{
+ setWindowTitle(QString("Call (%1)").arg(mContact->id()));
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ 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 &)));
+}
+
+CallWidget::~CallWidget()
+{
+ if (mChan) {
+ mChan->requestClose();
+ }
+}
+
+void CallWidget::setupGui()
+{
+ QHBoxLayout *mainBox = new QHBoxLayout;
+
+ mStack = new QStackedWidget();
+
+ mLblStatus = new QLabel("Initiating...");
+ mLblStatus->setAlignment(Qt::AlignCenter);
+ mStack->addWidget(mLblStatus);
+
+ QFrame *frame = new QFrame;
+
+ QHBoxLayout *hbox = new QHBoxLayout;
+
+ 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);
+
+ frame->setLayout(hbox);
+
+ mStack->addWidget(frame);
+
+ mStack->setCurrentIndex(0);
+
+ mainBox->addWidget(mStack);
+
+ setLayout(mainBox);
+}
+
+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;
+ }
+
+ PendingChannel *pc = qobject_cast<PendingChannel *>(op);
+
+ mChan = pc->channel();
+
+ connect(mChan->becomeReady(StreamedMediaChannel::FeatureStreams),
+ SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+ SLOT(onChannelReady(Telepathy::Client::PendingOperation*)));
+}
+
+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);
+ 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*)));
+ }
+
+ mTfChan = new FarsightChannel(streamChan, this);
+ connect(mTfChan,
+ SIGNAL(statusChanged(Telepathy::Client::FarsightChannel::Status)),
+ SLOT(onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status)));
+}
+
+void CallWidget::onChannelInvalidated(DBusProxy *proxy,
+ const QString &errorName, const QString &errorMessage)
+{
+ qDebug() << "CallWindow::onChannelInvalidated: channel became invalid:" <<
+ errorName << "-" << errorMessage;
+ mLblStatus->setText("Call terminated");
+ mStack->setCurrentIndex(0);
+}
+
+void CallWidget::onStreamCreated(PendingOperation *op)
+{
+ if (op->isError()) {
+ qWarning() << "CallWidget::onStreamCreated: unable to create audio stream:" <<
+ op->errorName() << "-" << op->errorMessage();
+ mLblStatus->setText("Unable to establish call");
+ mStack->setCurrentIndex(0);
+ return;
+ }
+}
+
+void CallWidget::onTfChannelStatusChanged(FarsightChannel::Status status)
+{
+ if (status == FarsightChannel::StatusDisconnected) {
+ mLblStatus->setText("Call terminated");
+ mStack->setCurrentIndex(0);
+ }
+}
+
+void CallWidget::onBtnAcceptClicked()
+{
+ StreamedMediaChannel *streamChan =
+ qobject_cast<StreamedMediaChannel *>(mChan.data());
+ streamChan->acceptCall();
+
+ mBtnAccept->setText("Call");
+ mBtnAccept->setEnabled(false);
+ mBtnReject->setText("Terminate");
+ mBtnReject->setEnabled(true);
+}
+
+void CallWidget::onBtnRejectClicked()
+{
+ mChan->requestClose();
+
+ mLblStatus->setText("Call terminated");
+ mStack->setCurrentIndex(0);
+}
diff --git a/examples/call/call-widget.h b/examples/call/call-widget.h
new file mode 100644
index 0000000..f3ae945
--- /dev/null
+++ b/examples/call/call-widget.h
@@ -0,0 +1,81 @@
+/*
+ * 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_call_widget_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_call_widget_h_HEADER_GUARD_
+
+#include <QSharedPointer>
+#include <QWidget>
+
+#include <TelepathyQt4/Client/Channel>
+
+#include "farsight-glue.h"
+
+namespace Telepathy {
+namespace Client {
+class Contact;
+class DBusProxy;
+class PendingOperation;
+}
+}
+
+class QLabel;
+class QPushButton;
+class QStackedWidget;
+
+class CallWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CallWidget(const QSharedPointer<Telepathy::Client::Contact> &contact,
+ QWidget *parent = 0);
+ CallWidget(const Telepathy::Client::ChannelPtr &chan,
+ QWidget *parent = 0);
+ virtual ~CallWidget();
+
+ 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 onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status);
+
+ void onBtnAcceptClicked();
+ void onBtnRejectClicked();
+
+private:
+ void createActions();
+ void setupGui();
+
+ Telepathy::Client::ChannelPtr mChan;
+ QSharedPointer<Telepathy::Client::Contact> mContact;
+ Telepathy::Client::FarsightChannel *mTfChan;
+ QPushButton *mBtnAccept;
+ QPushButton *mBtnReject;
+ QLabel *mLblStatus;
+ QStackedWidget *mStack;
+};
+
+#endif
diff --git a/examples/call/call-window.cpp b/examples/call/call-window.cpp
new file mode 100644
index 0000000..a5c6058
--- /dev/null
+++ b/examples/call/call-window.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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 "call-window.h"
+#include "_gen/call-window.moc.hpp"
+
+#include "call-handler.h"
+#include "call-roster-widget.h"
+
+#include <TelepathyQt4/Types>
+#include <TelepathyQt4/Client/Connection>
+#include <TelepathyQt4/Client/ConnectionManager>
+#include <TelepathyQt4/Client/PendingConnection>
+#include <TelepathyQt4/Client/PendingOperation>
+#include <TelepathyQt4/Client/PendingReady>
+#include <TelepathyQt4/Client/StreamedMediaChannel>
+
+#include <QDebug>
+
+using namespace Telepathy::Client;
+
+CallWindow::CallWindow(const QString &username, const QString &password,
+ QWidget *parent)
+ : QMainWindow(parent),
+ mUsername(username),
+ mPassword(password)
+{
+ setWindowTitle("Roster");
+
+ mCM = new ConnectionManager("gabble", this);
+ connect(mCM->becomeReady(),
+ SIGNAL(finished(Telepathy::Client::PendingOperation *)),
+ SLOT(onCMReady(Telepathy::Client::PendingOperation *)));
+
+ mCallHandler = new CallHandler(this);
+
+ setupGui();
+
+ resize(240, 320);
+}
+
+CallWindow::~CallWindow()
+{
+ if (mConn) {
+ mConn->requestDisconnect();
+ }
+}
+
+void CallWindow::setupGui()
+{
+ mRoster = new CallRosterWidget(mCallHandler);
+ setCentralWidget(mRoster);
+}
+
+void CallWindow::onCMReady(Telepathy::Client::PendingOperation *op)
+{
+ if (op->isError()) {
+ qWarning() << "CM cannot become ready";
+ return;
+ }
+
+ qDebug() << "CM ready";
+ QVariantMap params;
+ params.insert("account", QVariant(mUsername));
+ params.insert("password", QVariant(mPassword));
+ PendingConnection *pconn = mCM->requestConnection("jabber", params);
+ connect(pconn,
+ SIGNAL(finished(Telepathy::Client::PendingOperation *)),
+ SLOT(onConnectionCreated(Telepathy::Client::PendingOperation *)));
+}
+
+void CallWindow::onConnectionCreated(Telepathy::Client::PendingOperation *op)
+{
+ if (op->isError()) {
+ qWarning() << "Unable to create connection";
+ return;
+ }
+
+ qDebug() << "Connection created";
+ PendingConnection *pconn =
+ qobject_cast<PendingConnection *>(op);
+ ConnectionPtr conn = pconn->connection();
+ mConn = conn;
+ connect(conn->requestConnect(Connection::FeatureSelfContact),
+ SIGNAL(finished(Telepathy::Client::PendingOperation *)),
+ SLOT(onConnectionConnected(Telepathy::Client::PendingOperation *)));
+ connect(conn.data(),
+ SIGNAL(invalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)),
+ SLOT(onConnectionInvalidated(Telepathy::Client::DBusProxy *, const QString &, const QString &)));
+}
+
+void CallWindow::onConnectionConnected(Telepathy::Client::PendingOperation *op)
+{
+ if (op->isError()) {
+ qWarning() << "Connection cannot become connected";
+ return;
+ }
+
+ PendingReady *pr = qobject_cast<PendingReady *>(op);
+ Connection *conn = qobject_cast<Connection *>(pr->object());
+
+ if (conn->interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_CAPABILITIES)) {
+ Telepathy::CapabilityPair capability = {
+ TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA,
+ Telepathy::ChannelMediaCapabilityAudio |
+ Telepathy::ChannelMediaCapabilityNATTraversalSTUN |
+ Telepathy::ChannelMediaCapabilityNATTraversalGTalkP2P
+ };
+ qDebug() << "CallWindow::onConnectionConnected: advertising capabilities";
+ conn->capabilitiesInterface()->AdvertiseCapabilities(
+ Telepathy::CapabilityPairList() << capability,
+ QStringList());
+ }
+
+ if (conn->interfaces().contains(TELEPATHY_INTERFACE_CONNECTION_INTERFACE_REQUESTS)) {
+ qDebug() << "CallWindow::onConnectionConnected: connecting to Connection.Interface.NewChannels";
+ connect(conn->requestsInterface(),
+ SIGNAL(NewChannels(const Telepathy::ChannelDetailsList&)),
+ SLOT(onNewChannels(const Telepathy::ChannelDetailsList&)));
+ }
+
+ mRoster->addConnection(conn);
+}
+
+void CallWindow::onConnectionInvalidated(DBusProxy *proxy,
+ const QString &errorName, const QString &errorMessage)
+{
+ qDebug() << "CallWindow::onConnectionInvalidated: connection became invalid:" <<
+ errorName << "-" << errorMessage;
+ mRoster->removeConnection(mConn.data());
+ mConn.reset();
+}
+
+void CallWindow::onNewChannels(const Telepathy::ChannelDetailsList &channels)
+{
+ qDebug() << "CallWindow::onNewChannels";
+ foreach (const Telepathy::ChannelDetails &details, channels) {
+ QString channelType = details.properties.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".ChannelType")).toString();
+ bool requested = details.properties.value(QLatin1String(TELEPATHY_INTERFACE_CHANNEL ".Requested")).toBool();
+ qDebug() << "CallWindow::onNewChannels: channelType:" << channelType;
+ qDebug() << "CallWindow::onNewChannels: requested:" << requested;
+
+ if (channelType == TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
+ !requested) {
+ ChannelPtr channel = ChannelPtr(
+ new StreamedMediaChannel(mConn.data(),
+ details.channel.path(),
+ details.properties));
+ mCallHandler->addIncomingCall(channel);
+ qDebug() << "CallWindow::onNewChannels: new call received";
+ }
+ }
+}
diff --git a/examples/call/call-window.h b/examples/call/call-window.h
new file mode 100644
index 0000000..bc1e436
--- /dev/null
+++ b/examples/call/call-window.h
@@ -0,0 +1,69 @@
+/*
+ * 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_call_window_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_call_window_h_HEADER_GUARD_
+
+#include <QMainWindow>
+#include <QSharedPointer>
+
+#include <TelepathyQt4/Client/Connection>
+#include <TelepathyQt4/Types>
+
+namespace Telepathy {
+namespace Client {
+class ConnectionManager;
+class DBusProxy;
+class PendingOperation;
+}
+}
+
+class CallHandler;
+class CallRosterWidget;
+
+class CallWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CallWindow(const QString &username, const QString &password,
+ QWidget *parent = 0);
+ virtual ~CallWindow();
+
+private Q_SLOTS:
+ void onCMReady(Telepathy::Client::PendingOperation *);
+ void onConnectionCreated(Telepathy::Client::PendingOperation *);
+ void onConnectionConnected(Telepathy::Client::PendingOperation *);
+ void onConnectionInvalidated(Telepathy::Client::DBusProxy *,
+ const QString &, const QString &);
+ void onNewChannels(const Telepathy::ChannelDetailsList &);
+
+private:
+ void setupGui();
+
+ Telepathy::Client::ConnectionManager *mCM;
+ Telepathy::Client::ConnectionPtr mConn;
+ QString mUsername;
+ QString mPassword;
+ CallHandler *mCallHandler;
+ CallRosterWidget *mRoster;
+};
+
+#endif
diff --git a/examples/call/farsight-glue.cpp b/examples/call/farsight-glue.cpp
index 00266e5..26cd724 100644
--- a/examples/call/farsight-glue.cpp
+++ b/examples/call/farsight-glue.cpp
@@ -20,6 +20,7 @@
*/
#include "farsight-glue.h"
+#include "_gen/farsight-glue.moc.hpp"
#include <QDebug>
@@ -30,15 +31,57 @@
#include <TelepathyQt4/Client/Connection>
#include <TelepathyQt4/Client/StreamedMediaChannel>
-TfChannel *tfChannelFromQt(const Telepathy::Client::Connection *connection,
- const Telepathy::Client::StreamedMediaChannel *channel)
+namespace Telepathy {
+namespace Client {
+
+struct FarsightChannel::Private
+{
+ Private(FarsightChannel *parent, StreamedMediaChannel *channel);
+ ~Private();
+
+ static gboolean busWatch(GstBus *bus,
+ GstMessage *message, FarsightChannel::Private *self);
+ static void onClosed(TfChannel *tfChannel,
+ FarsightChannel::Private *self);
+ static void onSessionCreated(TfChannel *tfChannel,
+ FsConference *conference, FsParticipant *participant,
+ FarsightChannel::Private *self);
+ static void onStreamCreated(TfChannel *tfChannel,
+ TfStream *stream, FarsightChannel::Private *self);
+ static void onSrcPadAdded(TfStream *stream,
+ GstPad *pad, FsCodec *codec, FarsightChannel::Private *self);
+ static gboolean onRequestResource(TfStream *stream,
+ guint direction, gpointer data);
+
+ FarsightChannel *parent;
+ StreamedMediaChannel *channel;
+ Status status;
+ TfChannel *tfChannel;
+ GstBus *bus;
+ GstElement *pipeline;
+ GstElement *audio_input;
+ GstElement *audio_output;
+};
+
+FarsightChannel::Private::Private(FarsightChannel *parent,
+ StreamedMediaChannel *channel)
+ : parent(parent),
+ channel(channel),
+ status(StatusDisconnected),
+ tfChannel(0),
+ bus(0),
+ pipeline(0),
+ audio_input(0),
+ audio_output(0)
{
TpDBusDaemon *dbus = tp_dbus_daemon_dup(0);
if (!dbus) {
qWarning() << "Unable to connect to D-Bus";
- return 0;
+ return;
}
+ Connection *connection = channel->connection();
+
TpConnection *gconnection = tp_connection_new(dbus,
connection->busName().toAscii(),
connection->objectPath().toAscii(),
@@ -48,28 +91,203 @@ TfChannel *tfChannelFromQt(const Telepathy::Client::Connection *connection,
if (!gconnection) {
qWarning() << "Unable to construct TpConnection";
- return 0;
+ return;
}
TpChannel *gchannel = tp_channel_new(gconnection,
channel->objectPath().toAscii(),
TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA,
- TP_UNKNOWN_HANDLE_TYPE, 0, 0);
+ (TpHandleType) channel->targetHandleType(),
+ channel->targetHandle(),
+ 0);
g_object_unref(gconnection);
gconnection = 0;
if (!gchannel) {
qWarning() << "Unable to construct TpChannel";
- return 0;
+ return;
}
- TfChannel *ret = tf_channel_new(gchannel);
+ tfChannel = tf_channel_new(gchannel);
g_object_unref(gchannel);
gchannel = 0;
- if (!ret) {
+ if (!tfChannel) {
qWarning() << "Unable to construct TfChannel";
- return 0;
+ return;
+ }
+
+ /* Set up the telepathy farsight channel */
+ g_signal_connect(tfChannel, "closed",
+ G_CALLBACK(&FarsightChannel::Private::onClosed), this);
+ g_signal_connect(tfChannel, "session-created",
+ G_CALLBACK(&FarsightChannel::Private::onSessionCreated), this);
+ g_signal_connect(tfChannel, "stream-created",
+ G_CALLBACK(&FarsightChannel::Private::onStreamCreated), this);
+
+ pipeline = gst_pipeline_new (NULL);
+ bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
+
+ audio_input = gst_element_factory_make("gconfaudiosrc", NULL);
+ gst_object_ref(audio_input);
+ gst_object_sink(audio_input);
+
+ audio_output = gst_bin_new("bin");
+ GstElement *resample = gst_element_factory_make("audioresample", NULL);
+ GstElement *audio_sink = gst_element_factory_make("gconfaudiosink", NULL);
+ gst_bin_add_many(GST_BIN(audio_output), resample, audio_sink, NULL);
+ gst_element_link_many(resample, audio_sink, NULL);
+ GstPad *sink = gst_element_get_static_pad(resample, "sink");
+ GstPad *ghost = gst_ghost_pad_new("sink", sink);
+ gst_element_add_pad(GST_ELEMENT(audio_output), ghost);
+ gst_object_unref(G_OBJECT(sink));
+ gst_object_ref(audio_output);
+ gst_object_sink(audio_output);
+
+ gst_element_set_state(pipeline, GST_STATE_PLAYING);
+
+ status = StatusConnecting;
+ emit parent->statusChanged(status);
+}
+
+FarsightChannel::Private::~Private()
+{
+ if (tfChannel) {
+ g_object_unref(tfChannel);
+ tfChannel = 0;
+ }
+
+ if (bus) {
+ g_object_unref(bus);
+ bus = 0;
+ }
+
+ gst_element_set_state(pipeline, GST_STATE_NULL);
+
+ if (pipeline) {
+ g_object_unref(pipeline);
+ pipeline = 0;
+ }
+
+ if (audio_input) {
+ g_object_unref(audio_input);
+ audio_input = 0;
+ }
+
+ if (audio_output) {
+ g_object_unref(audio_output);
+ audio_output = 0;
+ }
+}
+
+gboolean FarsightChannel::Private::busWatch(GstBus *bus,
+ GstMessage *message, FarsightChannel::Private *self)
+{
+ tf_channel_bus_message(self->tfChannel, message);
+ return TRUE;
+}
+
+void FarsightChannel::Private::onClosed(TfChannel *tfChannel,
+ FarsightChannel::Private *self)
+{
+ self->status = StatusDisconnected;
+ emit self->parent->statusChanged(self->status);
+}
+
+void FarsightChannel::Private::onSessionCreated(TfChannel *tfChannel,
+ FsConference *conference, FsParticipant *participant,
+ FarsightChannel::Private *self)
+{
+ gst_bus_add_watch(self->bus,
+ (GstBusFunc) &FarsightChannel::Private::busWatch, self);
+
+ gst_bin_add(GST_BIN(self->pipeline), GST_ELEMENT(conference));
+ gst_element_set_state(GST_ELEMENT(conference), GST_STATE_PLAYING);
+}
+
+void FarsightChannel::Private::onStreamCreated(TfChannel *tfChannel,
+ TfStream *stream, FarsightChannel::Private *self)
+{
+ guint media_type;
+ GstPad *sink;
+
+ g_signal_connect(stream, "src-pad-added",
+ G_CALLBACK(&FarsightChannel::Private::onSrcPadAdded), self);
+ g_signal_connect(stream, "request-resource",
+ G_CALLBACK(&FarsightChannel::Private::onRequestResource), NULL);
+
+ g_object_get(stream, "media-type", &media_type,
+ "sink-pad", &sink, NULL);
+
+ GstPad *pad;
+ switch (media_type) {
+ case TP_MEDIA_STREAM_TYPE_AUDIO:
+ gst_bin_add(GST_BIN(self->pipeline), self->audio_input);
+ gst_element_set_state(self->audio_input, GST_STATE_PLAYING);
+
+ pad = gst_element_get_static_pad(self->audio_input, "src");
+ gst_pad_link(pad, sink);
+ break;
+ case TP_MEDIA_STREAM_TYPE_VIDEO:
+ // TODO
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+
+ gst_object_unref(sink);
+}
+
+void FarsightChannel::Private::onSrcPadAdded(TfStream *stream,
+ GstPad *src, FsCodec *codec, FarsightChannel::Private *self)
+{
+ guint media_type;
+
+ g_object_get(stream, "media-type", &media_type, NULL);
+
+ GstPad *pad;
+ GstElement *element = 0;
+
+ switch (media_type) {
+ case TP_MEDIA_STREAM_TYPE_AUDIO:
+ element = self->audio_output;
+ g_object_ref(element);
+ break;
+ case TP_MEDIA_STREAM_TYPE_VIDEO:
+ // TODO
+ return;
+ break;
+ default:
+ Q_ASSERT(false);
}
- return ret;
+
+ gst_bin_add(GST_BIN(self->pipeline), element);
+
+ pad = gst_element_get_static_pad(element, "sink");
+ gst_element_set_state(element, GST_STATE_PLAYING);
+
+ gst_pad_link(src, pad);
+
+ self->status = StatusConnected;
+ emit self->parent->statusChanged(self->status);
+}
+
+gboolean FarsightChannel::Private::onRequestResource(TfStream *stream,
+ guint direction, gpointer data)
+{
+ return TRUE;
+}
+
+FarsightChannel::FarsightChannel(StreamedMediaChannel *channel, QObject *parent)
+ : QObject(parent),
+ mPriv(new Private(this, channel))
+{
+}
+
+FarsightChannel::~FarsightChannel()
+{
+ delete mPriv;
+}
+
+}
}
diff --git a/examples/call/farsight-glue.h b/examples/call/farsight-glue.h
index 83dc9c6..d802bf3 100644
--- a/examples/call/farsight-glue.h
+++ b/examples/call/farsight-glue.h
@@ -19,19 +19,48 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _TelepathyQt4_examples_call_farsight_h_HEADER_GUARD_
-#define _TelepathyQt4_examples_call_farsight_h_HEADER_GUARD_
+#ifndef _TelepathyQt4_examples_call_farsight_glue_h_HEADER_GUARD_
+#define _TelepathyQt4_examples_call_farsight_glue_h_HEADER_GUARD_
+
+#include <QObject>
#include <telepathy-farsight/channel.h>
namespace Telepathy {
namespace Client {
- class Connection;
- class StreamedMediaChannel;
-} // Client
-} // Telepathy
-TfChannel *tfChannelFromQt(const Telepathy::Client::Connection *connection,
- const Telepathy::Client::StreamedMediaChannel *channel);
+class Connection;
+class StreamedMediaChannel;
+
+class FarsightChannel : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Status {
+ StatusDisconnected = 0,
+ StatusConnecting = 1,
+ StatusConnected = 2
+ };
+
+ FarsightChannel(StreamedMediaChannel *channel, QObject *parent = 0);
+ virtual ~FarsightChannel();
+
+ Status status() const;
+
+ // TODO add a way to change input and output devices
+ // add video support
+
+Q_SIGNALS:
+ void statusChanged(Telepathy::Client::FarsightChannel::Status status);
+
+private:
+ struct Private;
+ friend struct Private;
+ Private *mPriv;
+};
+
+}
+}
#endif
diff --git a/examples/call/main.cpp b/examples/call/main.cpp
index 9877b12..b78a140 100644
--- a/examples/call/main.cpp
+++ b/examples/call/main.cpp
@@ -1,5 +1,33 @@
+#include <glib-object.h>
+#include <gst/gst.h>
+
+#include <TelepathyQt4/Debug>
+#include <TelepathyQt4/Constants>
+#include <TelepathyQt4/Types>
+
+#include <QDebug>
+#include <QtGui>
+
+#include "call-window.h"
+
int main(int argc, char **argv)
{
- // nothing here yet
- return 0;
+ g_type_init();
+ gst_init(&argc, &argv);
+
+ QApplication app(argc, argv);
+
+ if (argc < 3) {
+ qDebug() << "usage: call username password";
+ return 1;
+ }
+
+ Telepathy::registerTypes();
+ Telepathy::enableDebug(true);
+ Telepathy::enableWarnings(true);
+
+ CallWindow w(argv[1], argv[2]);
+ w.show();
+
+ return app.exec();
}
--
1.5.6.5
More information about the telepathy-commits
mailing list