[Telepathy-commits] [telepathy-qt4/master] StreamedMediaChannel: Fixes/improvements.

Andre Moreira Magalhaes (andrunko) andre.magalhaes at collabora.co.uk
Thu Mar 19 16:29:03 PDT 2009


Do not added MediaStream objects to StreamedMediaChannel until they are ready
(have a contact object).
Make MediaStream a ReadyObject and use this to retrieve the contact (reducing
code complexity).
Changed MediaStream to be a QSharedData in order to use it with
QExplitlySharedDataPointer.
Moved MediaStream signals to StreamedMediaChannel and use the
QExplitlySharedDataPointer<MediaStream> in the signals instead of MediaStream *.
Some other fixes.
Changed call example accordingly.
---
 TelepathyQt4/Client/streamed-media-channel.cpp |  369 ++++++++++++++----------
 TelepathyQt4/Client/streamed-media-channel.h   |   41 ++--
 examples/call/call-widget.cpp                  |  178 +++++++-----
 examples/call/call-widget.h                    |   16 +-
 examples/call/call-window.cpp                  |    5 +-
 5 files changed, 346 insertions(+), 263 deletions(-)

diff --git a/TelepathyQt4/Client/streamed-media-channel.cpp b/TelepathyQt4/Client/streamed-media-channel.cpp
index 11ff827..6c71c6f 100644
--- a/TelepathyQt4/Client/streamed-media-channel.cpp
+++ b/TelepathyQt4/Client/streamed-media-channel.cpp
@@ -27,6 +27,7 @@
 #include <TelepathyQt4/Client/Connection>
 #include <TelepathyQt4/Client/ContactManager>
 #include <TelepathyQt4/Client/PendingContacts>
+#include <TelepathyQt4/Client/PendingReady>
 #include <TelepathyQt4/Client/PendingVoidMethodCall>
 
 #include <QHash>
@@ -39,37 +40,16 @@ namespace Client
 struct PendingMediaStreams::Private
 {
     Private(PendingMediaStreams *parent, StreamedMediaChannel *channel)
-        : parent(parent), channel(channel)
+        : parent(parent), channel(channel), streamsReady(0)
     {
     }
 
-    Private(PendingMediaStreams *parent, StreamedMediaChannel *channel,
-            const MediaStreams &streams)
-        : parent(parent), channel(channel), streams(streams)
-    {
-        getContacts();
-    }
-
-    void getContacts();
-
     PendingMediaStreams *parent;
     StreamedMediaChannel *channel;
     MediaStreams streams;
+    uint streamsReady;
 };
 
-void PendingMediaStreams::Private::getContacts()
-{
-    QSet<uint> contactsRequired;
-    foreach (const QSharedPointer<MediaStream> &stream, streams) {
-        contactsRequired |= stream->contactHandle();
-    }
-
-    ContactManager *contactManager = channel->connection()->contactManager();
-    parent->connect(contactManager->contactsForHandles(contactsRequired.toList()),
-            SIGNAL(finished(Telepathy::Client::PendingOperation *)),
-            SLOT(gotContacts(Telepathy::Client::PendingOperation *)));
-}
-
 PendingMediaStreams::PendingMediaStreams(StreamedMediaChannel *channel,
         ContactPtr contact,
         QList<Telepathy::MediaStreamType> types,
@@ -90,14 +70,6 @@ PendingMediaStreams::PendingMediaStreams(StreamedMediaChannel *channel,
             SLOT(gotStreams(QDBusPendingCallWatcher*)));
 }
 
-PendingMediaStreams::PendingMediaStreams(StreamedMediaChannel *channel,
-        const MediaStreams &streams,
-        QObject *parent)
-    : PendingOperation(parent),
-      mPriv(new Private(this, channel, streams))
-{
-}
-
 PendingMediaStreams::~PendingMediaStreams()
 {
     delete mPriv;
@@ -132,64 +104,72 @@ void PendingMediaStreams::gotStreams(QDBusPendingCallWatcher *watcher)
     debug() << "Got reply to StreamedMedia::RequestStreams()";
 
     Telepathy::MediaStreamInfoList list = reply.value();
-    QSharedPointer<MediaStream> stream;
+    MediaStreamPtr stream;
     foreach (const Telepathy::MediaStreamInfo &streamInfo, list) {
-        stream = QSharedPointer<MediaStream>(
-                new MediaStream(mPriv->channel,
-                    streamInfo.identifier,
-                    streamInfo.contact,
-                    (Telepathy::MediaStreamType) streamInfo.type,
-                    (Telepathy::MediaStreamState) streamInfo.state,
-                    (Telepathy::MediaStreamDirection) streamInfo.direction,
-                    (Telepathy::MediaStreamPendingSend) streamInfo.pendingSendFlags));
+        stream = mPriv->channel->lookupStreamById(streamInfo.identifier);
+        if (!stream) {
+            stream = MediaStreamPtr(
+                    new MediaStream(mPriv->channel,
+                        streamInfo.identifier,
+                        streamInfo.contact,
+                        (Telepathy::MediaStreamType) streamInfo.type,
+                        (Telepathy::MediaStreamState) streamInfo.state,
+                        (Telepathy::MediaStreamDirection) streamInfo.direction,
+                        (Telepathy::MediaStreamPendingSend) streamInfo.pendingSendFlags));
+            mPriv->channel->addStream(stream);
+        }
         mPriv->streams.append(stream);
+        connect(mPriv->channel,
+                SIGNAL(streamRemoved(Telepathy::Client::MediaStreamPtr)),
+                SLOT(onStreamRemoved(Telepathy::Client::MediaStreamPtr)));
+        connect(stream->becomeReady(),
+                SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+                SLOT(onStreamReady(Telepathy::Client::PendingOperation*)));
     }
 
-    mPriv->getContacts();
-
     watcher->deleteLater();
 }
 
-void PendingMediaStreams::gotContacts(PendingOperation *op)
+void PendingMediaStreams::onStreamRemoved(MediaStreamPtr stream)
 {
-    PendingContacts *pc = qobject_cast<PendingContacts *>(op);
-    Q_ASSERT(pc->isForHandles());
-
-    if (pc->isError()) {
-        warning().nospace() << "Gathering contacts failed: "
-            << pc->errorName() << ": " << pc->errorMessage();
+    if (isFinished()) {
+        return;
     }
 
-    QHash<uint, ContactPtr> contactsForHandles;
-    foreach (const ContactPtr &contact, pc->contacts()) {
-        contactsForHandles.insert(contact->handle()[0], contact);
+    if (mPriv->streams.contains(stream)) {
+        // the stream was removed before becoming ready
+        setFinishedWithError(TELEPATHY_ERROR_CANCELLED, "Stream removed before ready");
     }
+}
 
-    foreach (uint handle, pc->invalidHandles()) {
-        contactsForHandles.insert(handle, ContactPtr());
+void PendingMediaStreams::onStreamReady(PendingOperation *op)
+{
+    if (isFinished()) {
+        return;
     }
 
-    foreach (const QSharedPointer<MediaStream> &stream, mPriv->streams) {
-        stream->setContact(contactsForHandles[stream->contactHandle()]);
-        // make sure the channel has all streams even if StreamAdded was not
-        // emitted
-        mPriv->channel->addStream(stream);
+    if (op->isError()) {
+        setFinishedWithError(op->errorName(), op->errorMessage());
+        return;
     }
 
-    setFinished();
+    mPriv->streamsReady++;
+    if (mPriv->streamsReady == (uint) mPriv->streams.size()) {
+        setFinished();
+    }
 }
 
 struct MediaStream::Private
 {
-    Private(StreamedMediaChannel *channel, uint id,
+    Private(MediaStream *parent, StreamedMediaChannel *channel, uint id,
             uint contactHandle, MediaStreamType type,
             MediaStreamState state, MediaStreamDirection direction,
-            MediaStreamPendingSend pendingSend)
-        : channel(channel), id(id), contactHandle(contactHandle), type(type),
-          state(state), direction(direction), pendingSend(pendingSend)
-    {
-    }
+            MediaStreamPendingSend pendingSend);
 
+    static void introspectContact(Private *self);
+
+    MediaStream *parent;
+    ReadinessHelper *readinessHelper;
     StreamedMediaChannel *channel;
     uint id;
     uint contactHandle;
@@ -200,12 +180,53 @@ struct MediaStream::Private
     MediaStreamPendingSend pendingSend;
 };
 
+MediaStream::Private::Private(MediaStream *parent,
+        StreamedMediaChannel *channel, uint id,
+        uint contactHandle, MediaStreamType type,
+        MediaStreamState state, MediaStreamDirection direction,
+        MediaStreamPendingSend pendingSend)
+    : parent(parent),
+      readinessHelper(parent->readinessHelper()),
+      channel(channel),
+      id(id),
+      contactHandle(contactHandle),
+      type(type),
+      state(state),
+      direction(direction),
+      pendingSend(pendingSend)
+{
+    ReadinessHelper::Introspectables introspectables;
+
+    ReadinessHelper::Introspectable introspectableContact(
+        QSet<uint>() << 0,                                                      // makesSenseForStatuses
+        Features(),                                                             // dependsOnFeatures
+        QStringList(),                                                          // dependsOnInterfaces
+        (ReadinessHelper::IntrospectFunc) &Private::introspectContact,
+        this);
+    introspectables[FeatureContact] = introspectableContact;
+
+    readinessHelper->addIntrospectables(introspectables);
+    readinessHelper->becomeReady(FeatureContact);
+}
+
+void MediaStream::Private::introspectContact(MediaStream::Private *self)
+{
+    ContactManager *contactManager = self->channel->connection()->contactManager();
+    self->parent->connect(
+            contactManager->contactsForHandles(UIntList() << self->contactHandle),
+            SIGNAL(finished(Telepathy::Client::PendingOperation *)),
+            SLOT(gotContact(Telepathy::Client::PendingOperation *)));
+}
+
+const Feature MediaStream::FeatureContact = Feature(MediaStream::staticMetaObject.className(), 0);
+
 MediaStream::MediaStream(StreamedMediaChannel *channel, uint id,
         uint contactHandle, MediaStreamType type,
         MediaStreamState state, MediaStreamDirection direction,
         MediaStreamPendingSend pendingSend)
     : QObject(),
-      mPriv(new Private(channel, id, contactHandle, type,
+      ReadyObject(this, 0, FeatureContact),
+      mPriv(new Private(this, channel, id, contactHandle, type,
                   state, direction, pendingSend))
 {
 }
@@ -374,26 +395,41 @@ uint MediaStream::contactHandle() const
     return mPriv->contactHandle;
 }
 
-void MediaStream::setContact(const ContactPtr &contact)
-{
-    Q_ASSERT(!mPriv->contact || mPriv->contact == contact);
-    mPriv->contact = contact;
-}
-
 void MediaStream::setDirection(Telepathy::MediaStreamDirection direction,
         Telepathy::MediaStreamPendingSend pendingSend)
 {
     mPriv->direction = direction;
     mPriv->pendingSend = pendingSend;
-    emit directionChanged(this, direction, pendingSend);
 }
 
 void MediaStream::setState(Telepathy::MediaStreamState state)
 {
     mPriv->state = state;
-    emit stateChanged(this, state);
 }
 
+void MediaStream::gotContact(PendingOperation *op)
+{
+    PendingContacts *pc = qobject_cast<PendingContacts *>(op);
+    Q_ASSERT(pc->isForHandles());
+
+    if (pc->isError()) {
+        warning().nospace() << "Gathering media stream contact failed: "
+            << pc->errorName() << ": " << pc->errorMessage();
+    }
+
+    QList<ContactPtr> contacts = pc->contacts();
+    UIntList invalidHandles = pc->invalidHandles();
+    if (contacts.size()) {
+        Q_ASSERT(contacts.size() == 1);
+        Q_ASSERT(invalidHandles.size() == 0);
+        mPriv->contact = contacts.first();
+    } else {
+        Q_ASSERT(invalidHandles.size() == 1);
+        warning().nospace() << "Error retrieving media stream contact (invalid handle)";
+    }
+
+    mPriv->readinessHelper->setIntrospectCompleted(FeatureContact, true);
+}
 
 struct StreamedMediaChannel::Private
 {
@@ -408,15 +444,14 @@ struct StreamedMediaChannel::Private
     ReadinessHelper *readinessHelper;
 
     // Introspection
-    bool initialStreamsReceived;
 
-    QHash<uint, QSharedPointer<MediaStream> > streams;
+    QHash<uint, MediaStreamPtr> incompleteStreams;
+    QHash<uint, MediaStreamPtr> streams;
 };
 
 StreamedMediaChannel::Private::Private(StreamedMediaChannel *parent)
     : parent(parent),
-      readinessHelper(parent->readinessHelper()),
-      initialStreamsReceived(false)
+      readinessHelper(parent->readinessHelper())
 {
     ReadinessHelper::Introspectables introspectables;
 
@@ -553,7 +588,7 @@ PendingOperation *StreamedMediaChannel::acceptCall()
 PendingOperation *StreamedMediaChannel::removeStreams(MediaStreams streams)
 {
     Telepathy::UIntList ids;
-    foreach (const QSharedPointer<MediaStream> &stream, streams) {
+    foreach (const MediaStreamPtr &stream, streams) {
         ids << stream->id();
     }
     return removeStreams(ids);
@@ -603,51 +638,56 @@ void StreamedMediaChannel::gotStreams(QDBusPendingCallWatcher *watcher)
     debug() << "Got reply to StreamedMedia::ListStreams()";
 
     Telepathy::MediaStreamInfoList list = reply.value();
-    foreach (const Telepathy::MediaStreamInfo &streamInfo, list) {
-        mPriv->streams.insert(streamInfo.identifier,
-                QSharedPointer<MediaStream>(
-                    new MediaStream(this,
-                        streamInfo.identifier,
-                        streamInfo.contact,
-                        (Telepathy::MediaStreamType) streamInfo.type,
-                        (Telepathy::MediaStreamState) streamInfo.state,
-                        (Telepathy::MediaStreamDirection) streamInfo.direction,
-                        (Telepathy::MediaStreamPendingSend) streamInfo.pendingSendFlags)));
+    if (list.size() > 0) {
+        foreach (const Telepathy::MediaStreamInfo &streamInfo, list) {
+            if (!lookupStreamById(streamInfo.identifier)) {
+                addStream(MediaStreamPtr(
+                            new MediaStream(this,
+                                streamInfo.identifier,
+                                streamInfo.contact,
+                                (Telepathy::MediaStreamType) streamInfo.type,
+                                (Telepathy::MediaStreamState) streamInfo.state,
+                                (Telepathy::MediaStreamDirection) streamInfo.direction,
+                                (Telepathy::MediaStreamPendingSend) streamInfo.pendingSendFlags)));
+            }
+        }
+    } else {
+        mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
     }
-    PendingMediaStreams *pms = new PendingMediaStreams(this,
-            mPriv->streams.values(), this);
-    connect(pms,
-            SIGNAL(finished(Telepathy::Client::PendingOperation *)),
-            SLOT(onStreamsReady(Telepathy::Client::PendingOperation *)));
 
     watcher->deleteLater();
 }
 
-void StreamedMediaChannel::onStreamsReady(PendingOperation *op)
+void StreamedMediaChannel::onStreamReady(PendingOperation *op)
 {
+    PendingReady *pr = qobject_cast<PendingReady*>(op);
+    MediaStreamPtr stream = MediaStreamPtr(qobject_cast<MediaStream*>(pr->object()));
+
     if (op->isError()) {
-        mPriv->streams.clear();
-        mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, false,
-                op->errorName(), op->errorMessage());
+        mPriv->incompleteStreams.remove(stream->id());
+        // let's not fail because a stream could not become ready
+        if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) {
+            mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
+        }
         return;
     }
 
-    mPriv->initialStreamsReceived = true;
-    mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
-}
-
-void StreamedMediaChannel::onNewStreamReady(PendingOperation *op)
-{
-    PendingMediaStreams *pms = qobject_cast<PendingMediaStreams *>(op);
-
-    if (op->isError()) {
+    // the stream was removed before become ready
+    if (!mPriv->incompleteStreams.contains(stream->id())) {
+        if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) {
+            mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
+        }
         return;
     }
 
-    Q_ASSERT(pms->streams().size() == 1);
+    mPriv->incompleteStreams.remove(stream->id());
+    mPriv->streams.insert(stream->id(), stream);
+
+    if (!isReady(FeatureStreams) && mPriv->incompleteStreams.size() == 0) {
+        mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
+    }
 
-    if (mPriv->initialStreamsReceived) {
-        QSharedPointer<MediaStream> stream = pms->streams().first();
+    if (isReady(FeatureStreams)) {
         emit streamAdded(stream);
     }
 }
@@ -655,26 +695,21 @@ void StreamedMediaChannel::onNewStreamReady(PendingOperation *op)
 void StreamedMediaChannel::onStreamAdded(uint streamId,
         uint contactHandle, uint streamType)
 {
-    if (mPriv->streams.contains(streamId)) {
+    if (lookupStreamById(streamId)) {
         debug() << "Received StreamedMediaChannel.StreamAdded for an existing "
             "stream, ignoring";
         return;
     }
 
-    QSharedPointer<MediaStream> stream = QSharedPointer<MediaStream>(
+    MediaStreamPtr stream = MediaStreamPtr(
             new MediaStream(this, streamId,
                 contactHandle,
                 (Telepathy::MediaStreamType) streamType,
                 // TODO where to get this info from?
-                Telepathy::MediaStreamStateConnected,
-                (Telepathy::MediaStreamDirection) (Telepathy::MediaStreamDirectionSend | Telepathy::MediaStreamDirectionReceive),
+                Telepathy::MediaStreamStateDisconnected,
+                Telepathy::MediaStreamDirectionNone,
                 (Telepathy::MediaStreamPendingSend) 0));
-    mPriv->streams.insert(streamId, stream);
-    PendingMediaStreams *pms = new PendingMediaStreams(this,
-            MediaStreams() << stream, this);
-    connect(pms,
-            SIGNAL(finished(Telepathy::Client::PendingOperation *)),
-            SLOT(onNewStreamReady(Telepathy::Client::PendingOperation *)));
+    addStream(stream);
 }
 
 void StreamedMediaChannel::onStreamRemoved(uint streamId)
@@ -682,32 +717,43 @@ void StreamedMediaChannel::onStreamRemoved(uint streamId)
     debug() << "StreamedMediaChannel::onStreamRemoved: stream" <<
         streamId << "removed";
 
-    if (mPriv->initialStreamsReceived) {
-        Q_ASSERT(mPriv->streams.contains(streamId));
+    MediaStreamPtr stream = lookupStreamById(streamId);
+    Q_ASSERT(stream);
+    bool incomplete = mPriv->incompleteStreams.contains(streamId);
+    if (incomplete) {
+        mPriv->incompleteStreams.remove(streamId);
+    } else {
+        mPriv->streams.remove(streamId);
+    }
+
+    // the stream was added/removed before become ready
+    if (!isReady(FeatureStreams) &&
+        mPriv->streams.size() == 0 &&
+        mPriv->incompleteStreams.size() == 0) {
+        mPriv->readinessHelper->setIntrospectCompleted(FeatureStreams, true);
     }
 
-    if (mPriv->streams.contains(streamId)) {
-        QSharedPointer<MediaStream> stream = mPriv->streams[streamId];
-        emit stream->removed(stream.data());
-        mPriv->streams.remove(streamId);
+    if (isReady(FeatureStreams) && !incomplete) {
+        emit streamRemoved(stream);
     }
 }
 
 void StreamedMediaChannel::onStreamDirectionChanged(uint streamId,
-        uint streamDirection, uint pendingFlags)
+        uint streamDirection, uint streamPendingFlags)
 {
     debug() << "StreamedMediaChannel::onStreamDirectionChanged: stream" <<
         streamId << "direction changed to" << streamDirection;
 
-    if (mPriv->initialStreamsReceived) {
-        Q_ASSERT(mPriv->streams.contains(streamId));
-    }
-
-    if (mPriv->streams.contains(streamId)) {
-        QSharedPointer<MediaStream> stream = mPriv->streams[streamId];
-        stream->setDirection(
+    MediaStreamPtr stream = lookupStreamById(streamId);
+    Q_ASSERT(stream);
+    stream->setDirection(
+            (Telepathy::MediaStreamDirection) streamDirection,
+            (Telepathy::MediaStreamPendingSend) streamPendingFlags);
+    if (isReady(FeatureStreams) &&
+        !mPriv->incompleteStreams.contains(stream->id())) {
+        emit streamDirectionChanged(stream,
                 (Telepathy::MediaStreamDirection) streamDirection,
-                (Telepathy::MediaStreamPendingSend) pendingFlags);
+                (Telepathy::MediaStreamPendingSend) streamPendingFlags);
     }
 }
 
@@ -717,13 +763,13 @@ void StreamedMediaChannel::onStreamStateChanged(uint streamId,
     debug() << "StreamedMediaChannel::onStreamStateChanged: stream" <<
         streamId << "state changed to" << streamState;
 
-    if (mPriv->initialStreamsReceived) {
-        Q_ASSERT(mPriv->streams.contains(streamId));
-    }
-
-    if (mPriv->streams.contains(streamId)) {
-        QSharedPointer<MediaStream> stream = mPriv->streams[streamId];
-        stream->setState((Telepathy::MediaStreamState) streamState);
+    MediaStreamPtr stream = lookupStreamById(streamId);
+    Q_ASSERT(stream);
+    stream->setState((Telepathy::MediaStreamState) streamState);
+    if (isReady(FeatureStreams) &&
+        !mPriv->incompleteStreams.contains(stream->id())) {
+        emit streamStateChanged(stream,
+                (Telepathy::MediaStreamState) streamState);
     }
 }
 
@@ -733,29 +779,32 @@ void StreamedMediaChannel::onStreamError(uint streamId,
     debug() << "StreamedMediaChannel::onStreamError: stream" <<
         streamId << "error:" << errorCode << "-" << errorMessage;
 
-    if (mPriv->initialStreamsReceived) {
-        Q_ASSERT(mPriv->streams.contains(streamId));
-    }
-
-    if (mPriv->streams.contains(streamId)) {
-        QSharedPointer<MediaStream> stream = mPriv->streams[streamId];
-        emit stream->error(stream.data(),
-                (Telepathy::MediaStreamError) errorCode,
-                errorMessage);
+    MediaStreamPtr stream = lookupStreamById(streamId);
+    Q_ASSERT(stream);
+    if (isReady(FeatureStreams) &&
+        !mPriv->incompleteStreams.contains(stream->id())) {
+        emit streamError(stream,
+            (Telepathy::MediaStreamError) errorCode,
+            errorMessage);
     }
 }
 
-void StreamedMediaChannel::addStream(const QSharedPointer<MediaStream> &stream)
+void StreamedMediaChannel::addStream(const MediaStreamPtr &stream)
 {
-    if (mPriv->streams.contains(stream->id())) {
-        return;
-    }
-
-    mPriv->streams.insert(stream->id(), stream);
+    mPriv->incompleteStreams.insert(stream->id(), stream);
+    connect(stream->becomeReady(),
+            SIGNAL(finished(Telepathy::Client::PendingOperation*)),
+            SLOT(onStreamReady(Telepathy::Client::PendingOperation*)));
+}
 
-    if (mPriv->initialStreamsReceived) {
-        emit streamAdded(stream);
+MediaStreamPtr StreamedMediaChannel::lookupStreamById(uint streamId)
+{
+    if (mPriv->streams.contains(streamId)) {
+        return mPriv->streams.value(streamId);
+    } else if (mPriv->incompleteStreams.contains(streamId)) {
+        return mPriv->incompleteStreams.value(streamId);
     }
+    return MediaStreamPtr();
 }
 
 } // Telepathy::Client
diff --git a/TelepathyQt4/Client/streamed-media-channel.h b/TelepathyQt4/Client/streamed-media-channel.h
index 25b0bd5..f28700b 100644
--- a/TelepathyQt4/Client/streamed-media-channel.h
+++ b/TelepathyQt4/Client/streamed-media-channel.h
@@ -36,7 +36,8 @@ namespace Client
 class StreamedMediaChannel;
 class MediaStream;
 
-typedef QList<QSharedPointer<MediaStream> > MediaStreams;
+typedef QExplicitlySharedDataPointer<MediaStream> MediaStreamPtr;
+typedef QList<MediaStreamPtr> MediaStreams;
 
 class PendingMediaStreams : public PendingOperation
 {
@@ -50,7 +51,8 @@ public:
 
 private Q_SLOTS:
     void gotStreams(QDBusPendingCallWatcher *);
-    void gotContacts(Telepathy::Client::PendingOperation *);
+    void onStreamRemoved(Telepathy::Client::MediaStreamPtr);
+    void onStreamReady(Telepathy::Client::PendingOperation *);
 
 private:
     friend class StreamedMediaChannel;
@@ -68,7 +70,9 @@ private:
     Private *mPriv;
 };
 
-class MediaStream : public QObject
+class MediaStream : public QObject,
+                    private ReadyObject,
+                    public QSharedData
 {
     Q_OBJECT
     Q_DISABLE_COPY(MediaStream)
@@ -97,21 +101,15 @@ public:
     PendingOperation *requestStreamDirection(
             bool send, bool receive);
 
-Q_SIGNALS:
-    void removed(Telepathy::Client::MediaStream *stream);
-    void directionChanged(Telepathy::Client::MediaStream *stream,
-            Telepathy::MediaStreamDirection direction,
-            Telepathy::MediaStreamPendingSend pendingSend);
-    void stateChanged(Telepathy::Client::MediaStream *stream,
-            Telepathy::MediaStreamState);
-    void error(Telepathy::Client::MediaStream *stream,
-            Telepathy::MediaStreamError errorCode,
-            const QString &errorMessage);
+private Q_SLOTS:
+    void gotContact(Telepathy::Client::PendingOperation *op);
 
 private:
     friend class PendingMediaStreams;
     friend class StreamedMediaChannel;
 
+    static const Feature FeatureContact;
+
     MediaStream(StreamedMediaChannel *channel, uint id,
             uint contactHandle, MediaStreamType type,
             MediaStreamState state, MediaStreamDirection direction,
@@ -158,12 +156,20 @@ public:
             QList<Telepathy::MediaStreamType> types);
 
 Q_SIGNALS:
-    void streamAdded(const QSharedPointer<Telepathy::Client::MediaStream> &stream);
+    void streamAdded(const Telepathy::Client::MediaStreamPtr &stream);
+    void streamRemoved(const Telepathy::Client::MediaStreamPtr &stream);
+    void streamDirectionChanged(const Telepathy::Client::MediaStreamPtr &stream,
+            Telepathy::MediaStreamDirection direction,
+            Telepathy::MediaStreamPendingSend pendingSend);
+    void streamStateChanged(const Telepathy::Client::MediaStreamPtr &stream,
+            Telepathy::MediaStreamState);
+    void streamError(const Telepathy::Client::MediaStreamPtr &stream,
+            Telepathy::MediaStreamError errorCode,
+            const QString &errorMessage);
 
 private Q_SLOTS:
     void gotStreams(QDBusPendingCallWatcher *);
-    void onStreamsReady(Telepathy::Client::PendingOperation *);
-    void onNewStreamReady(Telepathy::Client::PendingOperation *);
+    void onStreamReady(Telepathy::Client::PendingOperation *);
     void onStreamAdded(uint, uint, uint);
     void onStreamRemoved(uint);
     void onStreamDirectionChanged(uint, uint, uint);
@@ -173,7 +179,8 @@ private Q_SLOTS:
 private:
     friend class PendingMediaStreams;
 
-    void addStream(const QSharedPointer<MediaStream> &stream);
+    void addStream(const MediaStreamPtr &stream);
+    MediaStreamPtr lookupStreamById(uint streamId);
 
     struct Private;
     friend struct Private;
diff --git a/examples/call/call-widget.cpp b/examples/call/call-widget.cpp
index 0bb220a..c12b6e3 100644
--- a/examples/call/call-widget.cpp
+++ b/examples/call/call-widget.cpp
@@ -176,26 +176,38 @@ void CallWidget::onChannelReady(PendingOperation *op)
         return;
     }
 
-#if 1
+    connect(mChan,
+            SIGNAL(streamAdded(const Telepathy::Client::MediaStreamPtr &)),
+            SLOT(onStreamAdded(const Telepathy::Client::MediaStreamPtr &)));
+    connect(mChan,
+            SIGNAL(streamRemoved(const Telepathy::Client::MediaStreamPtr &)),
+            SLOT(onStreamRemoved(const Telepathy::Client::MediaStreamPtr &)));
+    connect(mChan,
+            SIGNAL(streamDirectionChanged(const Telepathy::Client::MediaStreamPtr &,
+                                          Telepathy::MediaStreamDirection,
+                                          Telepathy::MediaStreamPendingSend)),
+            SLOT(onStreamDirectionChanged(const Telepathy::Client::MediaStreamPtr &,
+                                          Telepathy::MediaStreamDirection,
+                                          Telepathy::MediaStreamPendingSend)));
+    connect(mChan,
+            SIGNAL(streamStateChanged(const Telepathy::Client::MediaStreamPtr &,
+                                      Telepathy::MediaStreamState)),
+            SLOT(onStreamStateChanged(const Telepathy::Client::MediaStreamPtr &,
+                                      Telepathy::MediaStreamState)));
+
     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());
+    if (streams.size() > 0) {
+        foreach (const MediaStreamPtr &stream, streams) {
+            qDebug() << "  type:" <<
+                (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video");
+            qDebug() << "  direction:" << stream->direction();
+            qDebug() << "  state:" << stream->state();
+
+            onStreamDirectionChanged(stream, stream->direction(),
+                    stream->pendingSend());
+            onStreamStateChanged(stream, stream->state());
+        }
     }
 
     mBtnSendAudio->setEnabled(true);
@@ -224,57 +236,78 @@ void CallWidget::onStreamCreated(PendingOperation *op)
         qWarning() << "CallWidget::onStreamCreated: unable to create stream:" <<
             op->errorName() << "-" << op->errorMessage();
 
+        QPushButton *btn = 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);
+            btn = mBtnSendAudio;
+        } else if (!streamForType(Telepathy::MediaStreamTypeVideo)) {
+            btn = mBtnSendVideo;
+        } else {
+            Q_ASSERT(false);
         }
+
+        btn->blockSignals(true);
+        btn->setChecked(false);
+        btn->blockSignals(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());
+    // do nothing as streamAdded signal will be emitted
 }
 
-void CallWidget::onStreamAdded(const QSharedPointer<MediaStream> &stream)
+void CallWidget::onStreamAdded(const MediaStreamPtr &stream)
 {
-    connectStreamSignals(stream);
+    qDebug() << "CallWidget::onStreamAdded:" <<
+        (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
+        "stream created";
+    qDebug() << " direction:" << stream->direction();
+    qDebug() << " state:" << stream->state();
+
     updateStreamDirection(stream);
-    onStreamDirectionChanged(stream.data(), stream->direction(),
+    onStreamDirectionChanged(stream, stream->direction(),
             stream->pendingSend());
-    onStreamStateChanged(stream.data(), stream->state());
+    onStreamStateChanged(stream, stream->state());
 }
 
-void CallWidget::onStreamRemoved(MediaStream *stream)
+void CallWidget::onStreamRemoved(const MediaStreamPtr &stream)
 {
+    qDebug() << "CallWidget::onStreamRemoved:" <<
+        (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
+        "stream removed";
     if (stream->type() == Telepathy::MediaStreamTypeAudio) {
+        mBtnSendAudio->blockSignals(true);
         mBtnSendAudio->setChecked(false);
+        mBtnSendAudio->blockSignals(false);
+        mLblAudioDirection->setText(QLatin1String("Direction: None"));
+        mLblAudioState->setText(QLatin1String("State: Disconnected"));
     } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
+        mBtnSendVideo->blockSignals(true);
         mBtnSendVideo->setChecked(false);
+        mBtnSendVideo->blockSignals(false);
+        mLblVideoDirection->setText(QLatin1String("Direction: None"));
+        mLblVideoState->setText(QLatin1String("State: Disconnected"));
     }
 }
 
-void CallWidget::onStreamDirectionChanged(MediaStream *stream,
+void CallWidget::onStreamDirectionChanged(const MediaStreamPtr &stream,
         Telepathy::MediaStreamDirection direction,
         Telepathy::MediaStreamPendingSend pendingSend)
 {
-    qDebug() << "CallWidget::onStreamDirectionChanged: stream " <<
+    qDebug() << "CallWidget::onStreamDirectionChanged:" <<
         (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
-        "direction changed to" << direction;
+        "stream direction changed to" << direction;
 
-    QLabel *lbl;
+    QLabel *lbl = 0;
+    QPushButton *btn = 0;
     if (stream->type() == Telepathy::MediaStreamTypeAudio) {
         lbl = mLblAudioDirection;
-    } else {
+        btn = mBtnSendAudio;
+    } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
         lbl = mLblVideoDirection;
+        btn = mBtnSendVideo;
+    } else {
+        Q_ASSERT(false);
     }
 
     if (direction == Telepathy::MediaStreamDirectionSend) {
@@ -286,22 +319,27 @@ void CallWidget::onStreamDirectionChanged(MediaStream *stream,
     } else {
         lbl->setText(QLatin1String("Direction: None"));
     }
+
+    btn->blockSignals(true);
+    btn->setChecked(direction & Telepathy::MediaStreamDirectionSend);
+    btn->blockSignals(false);
 }
 
-void CallWidget::onStreamStateChanged(MediaStream *stream,
+void CallWidget::onStreamStateChanged(const MediaStreamPtr &stream,
         Telepathy::MediaStreamState state)
 {
-    qDebug() << "CallWidget::onStreamStateChanged: stream " <<
+    qDebug() << "CallWidget::onStreamStateChanged:" <<
         (stream->type() == Telepathy::MediaStreamTypeAudio ? "Audio" : "Video") <<
-        "state changed to" << state;
+        "stream state changed to" << state;
 
-    QLabel *lbl;
+    QLabel *lbl = 0;
     if (stream->type() == Telepathy::MediaStreamTypeAudio) {
         lbl = mLblAudioState;
-    } else {
+    } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
         lbl = mLblVideoState;
+    } else {
+        Q_ASSERT(false);
     }
-
     if (state == Telepathy::MediaStreamStateDisconnected) {
         lbl->setText(QLatin1String("State: Disconnected"));
     } else if (state == Telepathy::MediaStreamStateConnecting) {
@@ -335,7 +373,7 @@ void CallWidget::onBtnHangupClicked()
 
 void CallWidget::onBtnSendAudioToggled(bool checked)
 {
-    QSharedPointer<MediaStream> stream =
+    MediaStreamPtr stream =
         streamForType(Telepathy::MediaStreamTypeAudio);
     qDebug() << "CallWidget::onBtnSendAudioToggled: checked:" << checked;
     if (!stream) {
@@ -354,7 +392,7 @@ void CallWidget::onBtnSendAudioToggled(bool checked)
 
 void CallWidget::onBtnSendVideoToggled(bool checked)
 {
-    QSharedPointer<MediaStream> stream =
+    MediaStreamPtr stream =
         streamForType(Telepathy::MediaStreamTypeVideo);
     qDebug() << "CallWidget::onBtnSendVideoToggled: checked:" << checked;
     if (!stream) {
@@ -371,54 +409,42 @@ void CallWidget::onBtnSendVideoToggled(bool checked)
     }
 }
 
-QSharedPointer<MediaStream> CallWidget::streamForType(Telepathy::MediaStreamType type) const
+MediaStreamPtr CallWidget::streamForType(Telepathy::MediaStreamType type) const
 {
     MediaStreams streams = mChan->streams();
-    foreach (const QSharedPointer<MediaStream> &stream, streams) {
+    foreach (const MediaStreamPtr &stream, streams) {
         if (stream->type() == type) {
             return stream;
         }
     }
-    return QSharedPointer<MediaStream>();
+    return MediaStreamPtr();
 }
 
-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)
+void CallWidget::updateStreamDirection(const MediaStreamPtr &stream)
 {
     bool checked = false;
     if (stream->type() == Telepathy::MediaStreamTypeAudio) {
         checked = mBtnSendAudio->isChecked();
     } else if (stream->type() == Telepathy::MediaStreamTypeVideo) {
         checked = mBtnSendVideo->isChecked();
+    } else {
+        Q_ASSERT(false);
     }
 
-    qDebug() << "CallWidget::updateStreamDirection: current stream direction:" <<
-        stream->direction() << "- checked:" << checked;
+    qDebug() << "CallWidget::updateStreamDirection: updating" <<
+        (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video") <<
+        "stream direction";
 
     if (checked) {
         if (!(stream->direction() & Telepathy::MediaStreamDirectionSend)) {
             int dir = stream->direction() | Telepathy::MediaStreamDirectionSend;
             stream->requestStreamDirection((Telepathy::MediaStreamDirection) dir);
-            qDebug() << "CallWidget::updateStreamDirection: start sending " <<
+            qDebug() << "CallWidget::updateStreamDirection: start sending" <<
                 (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video");
+        } else {
+            qDebug() << "CallWidget::updateStreamDirection:" <<
+                (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video") <<
+                "stream updated";
         }
     } else {
         if (stream->direction() & Telepathy::MediaStreamDirectionSend) {
@@ -426,6 +452,10 @@ void CallWidget::updateStreamDirection(const QSharedPointer<MediaStream> &stream
             qDebug() << "CallWidget::updateStreamDirection: stop sending " <<
                 (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video");
             stream->requestStreamDirection((Telepathy::MediaStreamDirection) dir);
+        } else {
+            qDebug() << "CallWidget::updateStreamDirection:" <<
+                (stream->type() == Telepathy::MediaStreamTypeAudio ? "audio" : "video") <<
+                "stream updated";
         }
     }
 }
diff --git a/examples/call/call-widget.h b/examples/call/call-widget.h
index 1c0b365..e54961e 100644
--- a/examples/call/call-widget.h
+++ b/examples/call/call-widget.h
@@ -21,11 +21,11 @@
 #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 <TelepathyQt4/Client/Contact>
+#include <TelepathyQt4/Client/StreamedMediaChannel>
 #include <TelepathyQt4/Constants>
 
 #include "farsight-channel.h"
@@ -36,7 +36,6 @@ class DBusProxy;
 class MediaStream;
 class PendingMediaStreams;
 class PendingOperation;
-class StreamedMediaChannel;
 }
 }
 
@@ -62,12 +61,12 @@ private Q_SLOTS:
     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 *,
+    void onStreamAdded(const Telepathy::Client::MediaStreamPtr &);
+    void onStreamRemoved(const Telepathy::Client::MediaStreamPtr &);
+    void onStreamDirectionChanged(const Telepathy::Client::MediaStreamPtr &,
             Telepathy::MediaStreamDirection,
             Telepathy::MediaStreamPendingSend);
-    void onStreamStateChanged(Telepathy::Client::MediaStream *,
+    void onStreamStateChanged(const Telepathy::Client::MediaStreamPtr &,
             Telepathy::MediaStreamState);
     void onTfChannelStatusChanged(Telepathy::Client::FarsightChannel::Status);
 
@@ -79,9 +78,8 @@ private:
     void createActions();
     void setupGui();
 
-    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);
+    Telepathy::Client::MediaStreamPtr streamForType(Telepathy::MediaStreamType type) const;
+    void updateStreamDirection(const Telepathy::Client::MediaStreamPtr &stream);
 
     void callEnded(const QString &message);
 
diff --git a/examples/call/call-window.cpp b/examples/call/call-window.cpp
index 1e3962f..d3f6dd6 100644
--- a/examples/call/call-window.cpp
+++ b/examples/call/call-window.cpp
@@ -155,8 +155,8 @@ void CallWindow::onNewChannels(const Telepathy::ChannelDetailsList &channels)
     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;
+        qDebug() << " channelType:" << channelType;
+        qDebug() << " requested  :" << requested;
 
         if (channelType == TELEPATHY_INTERFACE_CHANNEL_TYPE_STREAMED_MEDIA &&
             !requested) {
@@ -164,7 +164,6 @@ void CallWindow::onNewChannels(const Telepathy::ChannelDetailsList &channels)
                         details.channel.path(),
                         details.properties);
             mCallHandler->addIncomingCall(channel);
-            qDebug() << "CallWindow::onNewChannels: new call received";
         }
     }
 }
-- 
1.5.6.5




More information about the telepathy-commits mailing list