diff options
| author | Will Thompson <will.thompson@collabora.co.uk> | 2011-06-16 17:07:55 +0100 |
|---|---|---|
| committer | Will Thompson <will.thompson@collabora.co.uk> | 2011-06-16 17:07:57 +0100 |
| commit | 052ca8131c8e145714372db249efd9bd04c70f94 (patch) | |
| tree | b60274ba51c9901724c038a30b1ac714f0cf45f1 | |
| parent | e8e2d23490846ebabb7c640bb905b7549883b3af (diff) | |
| parent | a88dd5529d038f32b3c01b9eb6109eaa10e88604 (diff) | |
Merge branch 'gtalk-jingle-workarounds' into telepathy-gabble-0.12
These aren't perfect, but they'll do for now.
https://bugs.freedesktop.org/show_bug.cgi?id=38352
| -rw-r--r-- | src/jingle-content.c | 16 | ||||
| -rw-r--r-- | src/jingle-media-rtp.c | 4 | ||||
| -rw-r--r-- | src/jingle-session.c | 27 | ||||
| -rw-r--r-- | src/jingle-session.h | 3 | ||||
| -rw-r--r-- | src/jingle-transport-iface.c | 2 | ||||
| -rw-r--r-- | src/media-channel.c | 4 | ||||
| -rw-r--r-- | src/presence-cache.c | 1 | ||||
| -rw-r--r-- | tests/twisted/Makefile.am | 1 | ||||
| -rw-r--r-- | tests/twisted/jingle/incoming-gmail-modern-jingle.py | 179 |
9 files changed, 223 insertions, 14 deletions
diff --git a/src/jingle-content.c b/src/jingle-content.c index 25167d32f..b8ebefd60 100644 --- a/src/jingle-content.c +++ b/src/jingle-content.c @@ -507,6 +507,8 @@ gabble_jingle_content_parse_add (GabbleJingleContent *c, GabbleJingleTransportIface *trans = NULL; JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); + priv->created_by_us = FALSE; + desc_node = lm_message_node_get_child_any_ns (content_node, "description"); trans_node = lm_message_node_get_child_any_ns (content_node, "transport"); creator = lm_message_node_get_attribute (content_node, "creator"); @@ -549,6 +551,19 @@ gabble_jingle_content_parse_add (GabbleJingleContent *c, } else { + if (creator == NULL && + gabble_jingle_session_peer_has_quirk (c->session, + QUIRK_GOOGLE_WEBMAIL_CLIENT)) + { + if (gabble_jingle_content_creator_is_initiator (c)) + creator = "initiator"; + else + creator = "responder"; + + DEBUG ("Working around GMail omitting creator=''; assuming '%s'", + creator); + } + if ((trans_node == NULL) || (creator == NULL) || (name == NULL)) { SET_BAD_REQ ("missing required content attributes or elements"); @@ -577,7 +592,6 @@ gabble_jingle_content_parse_add (GabbleJingleContent *c, priv->transport_ns = g_strdup (ns); } - priv->created_by_us = FALSE; if (senders == NULL) priv->senders = get_default_senders (c); else diff --git a/src/jingle-media-rtp.c b/src/jingle-media-rtp.c index 0e21a4fc0..5b1a9775b 100644 --- a/src/jingle-media-rtp.c +++ b/src/jingle-media-rtp.c @@ -337,7 +337,9 @@ static void transport_created (GabbleJingleContent *content, dialect = gabble_jingle_session_get_dialect (content->session); if (priv->media_type == JINGLE_MEDIA_TYPE_VIDEO && - JINGLE_IS_GOOGLE_DIALECT (dialect)) + (JINGLE_IS_GOOGLE_DIALECT (dialect) || + gabble_jingle_session_peer_has_quirk (content->session, + QUIRK_GOOGLE_WEBMAIL_CLIENT))) { jingle_transport_google_set_component_name (gtrans, "video_rtp", 1); jingle_transport_google_set_component_name (gtrans, "video_rtcp", 2); diff --git a/src/jingle-session.c b/src/jingle-session.c index 539c0d162..f20c2d631 100644 --- a/src/jingle-session.c +++ b/src/jingle-session.c @@ -631,6 +631,21 @@ static void set_state (GabbleJingleSession *sess, JingleState state, JingleReason termination_reason, const gchar *text); static GabbleJingleContent *_get_any_content (GabbleJingleSession *session); +gboolean +gabble_jingle_session_peer_has_quirk ( + GabbleJingleSession *self, + const gchar *quirk) +{ + GabbleJingleSessionPrivate *priv = self->priv; + GabblePresence *presence = gabble_presence_cache_get ( + priv->conn->presence_cache, self->peer); + + return (presence != NULL && + priv->peer_resource != NULL && + gabble_presence_resource_has_caps (presence, priv->peer_resource, + gabble_capability_set_predicate_has, quirk)); +} + static gboolean lookup_content (GabbleJingleSession *sess, const gchar *name, @@ -668,13 +683,8 @@ lookup_content (GabbleJingleSession *sess, * of the moon, and get kind of confused in the process), and we try to * pick globally-unique content names. */ - GabblePresence *presence = gabble_presence_cache_get ( - priv->conn->presence_cache, sess->peer); - - if (creator == NULL && presence != NULL && - priv->peer_resource != NULL && - gabble_presence_resource_has_caps (presence, priv->peer_resource, - gabble_capability_set_predicate_has, + if (creator == NULL && + gabble_jingle_session_peer_has_quirk (sess, QUIRK_OMITS_CONTENT_CREATORS)) { DEBUG ("working around missing 'creator' attribute"); @@ -2355,7 +2365,8 @@ gabble_jingle_session_get_remote_ringing (GabbleJingleSession *sess) gboolean gabble_jingle_session_can_modify_contents (GabbleJingleSession *sess) { - return !JINGLE_IS_GOOGLE_DIALECT (sess->priv->dialect); + return !JINGLE_IS_GOOGLE_DIALECT (sess->priv->dialect) && + !gabble_jingle_session_peer_has_quirk (sess, QUIRK_GOOGLE_WEBMAIL_CLIENT); } JingleDialect diff --git a/src/jingle-session.h b/src/jingle-session.h index f2a1fb83a..5c80b6c7a 100644 --- a/src/jingle-session.h +++ b/src/jingle-session.h @@ -107,6 +107,9 @@ const gchar *gabble_jingle_session_get_sid (GabbleJingleSession *sess); JingleDialect gabble_jingle_session_get_dialect (GabbleJingleSession *sess); gboolean gabble_jingle_session_can_modify_contents (GabbleJingleSession *sess); +gboolean gabble_jingle_session_peer_has_quirk ( + GabbleJingleSession *self, + const gchar *quirk); typedef void (*JingleReplyHandler) (GObject *, gboolean success, LmMessage *reply); diff --git a/src/jingle-transport-iface.c b/src/jingle-transport-iface.c index 76dd29d15..8c9861ec5 100644 --- a/src/jingle-transport-iface.c +++ b/src/jingle-transport-iface.c @@ -107,7 +107,7 @@ gabble_jingle_transport_iface_can_accept (GabbleJingleTransportIface *self) if (state != JINGLE_TRANSPORT_STATE_CONNECTED) return FALSE; - /* Only Raw UDP *needs* contents in order to accept. */ + /* Only Raw UDP *needs* candidates in order to accept. */ if (m != NULL) return m (self); else diff --git a/src/media-channel.c b/src/media-channel.c index 4e2341a57..136c785c5 100644 --- a/src/media-channel.c +++ b/src/media-channel.c @@ -450,9 +450,7 @@ gabble_media_channel_constructor (GType type, guint n_props, /* If this is a Google session, let's set ImmutableStreams */ if (priv->session != NULL) { - JingleDialect d = gabble_jingle_session_get_dialect (priv->session); - - priv->immutable_streams = JINGLE_IS_GOOGLE_DIALECT (d); + priv->immutable_streams = !gabble_jingle_session_can_modify_contents (priv->session); } /* If there's no session yet, but we know who the peer will be, and we have * presence for them, we can set ImmutableStreams using the same algorithm as diff --git a/src/presence-cache.c b/src/presence-cache.c index b8d818c1d..6132ed68d 100644 --- a/src/presence-cache.c +++ b/src/presence-cache.c @@ -1007,6 +1007,7 @@ _parse_node (GabblePresence *presence, DEBUG ("Client is Google Web Client"); gabble_capability_set_add (cap_set, QUIRK_GOOGLE_WEBMAIL_CLIENT); + gabble_capability_set_add (cap_set, QUIRK_OMITS_CONTENT_CREATORS); gabble_presence_set_capabilities (presence, resource, cap_set, serial); gabble_capability_set_free (cap_set); } diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index 65c110c78..311deb77d 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -159,6 +159,7 @@ TWISTED_JINGLE_TESTS = \ jingle/hold-av.py \ jingle/incoming-basics.py \ jingle/incoming-call-stream-error.py \ + jingle/incoming-gmail-modern-jingle.py \ jingle/initial-audio-video.py \ jingle/misuse.py \ jingle/stun-server.py \ diff --git a/tests/twisted/jingle/incoming-gmail-modern-jingle.py b/tests/twisted/jingle/incoming-gmail-modern-jingle.py new file mode 100644 index 000000000..6ff285880 --- /dev/null +++ b/tests/twisted/jingle/incoming-gmail-modern-jingle.py @@ -0,0 +1,179 @@ +""" +Tests workarounds for calls with the GMail client, which supports a (currently +quirky) variation on the theme of modern Jingle. +""" + +from servicetest import EventPattern, wrap_channel, make_channel_proxy, assertEquals +from gabbletest import elem, elem_iq, exec_test +from jingletest2 import JingleTest2, JingleProtocol031 +import ns +import constants as cs +from twisted.words.xish import xpath + +class GMail(JingleTest2): + remote_caps = { + 'ext': 'pmuc-v1 sms-v1 camera-v1 video-v1 voice-v1', + 'ver': '1.1', + 'node': 'http://mail.google.com/xmpp/client/caps', + } + +def test(q, bus, conn, stream): + peer = 'foo@gmail.com/gmail.7E1F07D0' + self = 'test@localhost/test' + jp = JingleProtocol031() + jt = GMail(jp, conn, q, stream, 'test@localhost', peer) + jt.prepare(send_roster=False) + + sid = 'c1025763497' + si = elem_iq(stream, 'set', from_=peer, to=self)( + elem(ns.JINGLE, 'jingle', action='session-initiate', sid=sid, initiator=peer)( + elem('content', name='video')( + elem(ns.JINGLE_RTP, 'description', media='video')( + elem('payload-type', id='99', name='H264-SVC')( + elem('parameter', name='width', value='320'), + elem('parameter', name='height', value='200'), + elem('parameter', name='framerate', value='30'), + ), + # ... other codecs elided ... + elem('encryption'), + ), + elem(ns.GOOGLE_P2P, 'transport'), + ), + elem('content', name='audio')( + elem(ns.JINGLE_RTP, 'description', media='audio')( + elem('payload-type', id='103', name='ISAC', clockrate='16000')( + elem('parameter', name='bitrate', value='32000'), + ), + # ... other codecs elided ... + elem('encryption'), + ), + elem(ns.GOOGLE_P2P, 'transport'), + ) + ), + elem(ns.GOOGLE_SESSION, 'session', action='initiate', sid='c1025763497', initiator=peer)( + elem(ns.GOOGLE_SESSION_VIDEO, 'description')( + elem('payload-type', id='99', name='H264-SVC', width='320', height='200', framerate='30'), + # ... other codecs elided ... + elem(ns.JINGLE_RTP, 'encryption')( + elem(ns.GOOGLE_SESSION_VIDEO, 'usage'), + ), + elem(ns.GOOGLE_SESSION_PHONE, 'payload-type', id='103', name='ISAC', bitrate='32000', clockrate='16000'), + # ... other codecs elided ... + elem(ns.JINGLE_RTP, 'encryption')( + elem(ns.GOOGLE_SESSION_PHONE, 'usage'), + ), + ), + ), + ) + stream.send(si) + + nc, nsh = q.expect_many( + EventPattern('dbus-signal', signal='NewChannels'), + EventPattern('dbus-signal', signal='NewSessionHandler'), + ) + + path, properties = nc.args[0][0] + + # It's an audio+video call + assert properties[cs.INITIAL_AUDIO] + assert properties[cs.INITIAL_VIDEO] + # Google can't add and remove streams on the fly. We special-case GMail. + assert properties[cs.IMMUTABLE_STREAMS] + + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia') + session_handler = make_channel_proxy(conn, nsh.args[0], 'Media.SessionHandler') + session_handler.Ready() + + path, _, _, _ = q.expect('dbus-signal', signal='NewStreamHandler').args + stream1 = make_channel_proxy(conn, path, 'Media.StreamHandler') + path, _, _, _ = q.expect('dbus-signal', signal='NewStreamHandler').args + stream2 = make_channel_proxy(conn, path, 'Media.StreamHandler') + + stream1.Ready([]) + stream2.Ready([]) + + # Audio rtcp + stream.send( + elem_iq(stream, from_=peer, to=self, type='set')( + elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( + elem('content', name='audio')( + elem(ns.GOOGLE_P2P, 'transport')( + elem('candidate', address='172.22.64.192', port='54335', + name='rtcp', username='+wJqkmRVYotCz+Rd', + password='POWPzg5Pks4+ywAz', preference='1', protocol='udp', + generation='0', network='1', type='local') + ) + ) + ) + ) + ) + q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream1.object_path) + + # audio rtp + stream.send( + elem_iq(stream, from_=peer, to=self, type='set')( + elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( + elem('content', name='audio')( + elem(ns.GOOGLE_P2P, 'transport')( + elem('candidate', address='172.22.64.192', port='54337', + name='rtp', username='F7rgdWcCgH3Q/HgE', + password='ioh2IDwd3iZEZHzM', preference='1', protocol='udp', + generation='0', network='1', type='local') + ) + ) + ) + ) + ) + q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream1.object_path) + + # video rtcp: note the weird name='' field which Gabble has to work around + stream.send( + elem_iq(stream, from_=peer, to=self, type='set')( + elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( + elem('content', name='video')( + elem(ns.GOOGLE_P2P, 'transport')( + elem('candidate', address='172.22.64.192', port='54339', + name='video_rtcp', username='fnLduEIu6VHsSOqh', + password='IYeNu/HWzMpx2zrS', preference='1', protocol='udp', + generation='0', network='1', type='local') + ) + ) + ) + ) + ) + q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream2.object_path) + + # video rtp: ditto + stream.send( + elem_iq(stream, from_=peer, to=self, type='set')( + elem(ns.JINGLE, 'jingle', action='transport-info', sid=sid)( + elem('content', name='video')( + elem(ns.GOOGLE_P2P, 'transport')( + elem('candidate', address='172.22.64.192', port='54341', + name='video_rtp', username='mZVBFdQ2LyAP6oyE', + password='3uoyCHP8zwE+/Ylw', preference='1', protocol='udp', + generation='0', network='1', type='local') + ) + ) + ) + ) + ) + q.expect('dbus-signal', signal='AddRemoteCandidate', path=stream2.object_path) + + # Test that we're sending with name='video_rtp' as well, but only for the video stream. + stream1.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) + e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) + candidate = xpath.queryForNodes( + '/iq/jingle/content[@name="audio"]/transport/candidate', + e.stanza)[0] + assertEquals('rtp', candidate['name']) + + stream2.NewNativeCandidate("fake", jt.get_remote_transports_dbus()) + e = q.expect('stream-iq', predicate=jp.action_predicate('transport-info')) + candidate = xpath.queryForNodes( + '/iq/jingle/content[@name="video"]/transport/candidate', + e.stanza)[0] + assertEquals('video_rtp', candidate['name']) + +if __name__ == '__main__': + exec_test(test) |
