def initiate(self):
        CallTest.initiate(self)

        q = self.q
        jp = self.jp
        cstream = self.audio_stream
        chan = self.chan

        recv_state = cstream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)["ReceivingState"]
        send_state = cstream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)["SendingState"]
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)

        # These are 0- (for old dialects) or 1- (for new dialects) element lists
        # that can be splatted into expect_many with *
        self.hold_event = jp.rtp_info_event_list("hold")
        self.unhold_event = jp.rtp_info_event_list("unhold")
    
        # Before we have accepted any streams, GetHoldState returns Unheld and
        # unhold is a no-op.
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
        chan.Hold.RequestHold(False)
    
        q.forbid_events(self.hold_event)
        q.forbid_events(self.unhold_event)
    
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
        chan.Hold.RequestHold(False)

        # Before we have any streams, RequestHold(True) should work; because
        # there are no streams, it should take effect at once. It certainly
        # should't send anything to the peer.
        q.forbid_events(self.hold_event)
        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        # If we unhold, it should succeed immediately again, because there are
        # no resources to reclaim.
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        # Put the call back on hold ...
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    def initiate(self):
        CallTest.initiate(self)

        q = self.q
        jp = self.jp
        cstream = self.audio_stream
        chan = self.chan

        recv_state = cstream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)["ReceivingState"]
        send_state = cstream.GetAll(cs.CALL_STREAM_IFACE_MEDIA,
                dbus_interface=dbus.PROPERTIES_IFACE)["SendingState"]
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)

        # These are 0- (for old dialects) or 1- (for new dialects) element lists
        # that can be splatted into expect_many with *
        self.hold_event = jp.rtp_info_event_list("hold")
        self.unhold_event = jp.rtp_info_event_list("unhold")
    
        # Before we have accepted any streams, GetHoldState returns Unheld and
        # unhold is a no-op.
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
        chan.Hold.RequestHold(False)
    
        q.forbid_events(self.hold_event)
        q.forbid_events(self.unhold_event)
    
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
        chan.Hold.RequestHold(False)

        # Before we have any streams, RequestHold(True) should work; because
        # there are no streams, it should take effect at once. It certainly
        # should't send anything to the peer.
        q.forbid_events(self.hold_event)
        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        # If we unhold, it should succeed immediately again, because there are
        # no resources to reclaim.
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_UNHELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        # Put the call back on hold ...
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED])
        q.expect('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED])
        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
Beispiel #3
0
    def connect(self):
        CallTest.connect(self)

        req_pattern = EventPattern('http-request', method='GET',
                path='/create_session')
        req1, req2 = self.q.expect_many(req_pattern, req_pattern)

        if self.params['too-slow'] is not None:
            test_too_slow(req1, req2, too_slow)
            return
Beispiel #4
0
 def pickup(self):
     CallTest.pickup(self)
     self.test_dtmf()
    def pickup(self):
        CallTest.pickup(self)

        # Check the DTMF method does not exist
        call_async(self.q, self.video_content.DTMF, "StartTone", 3)
        self.q.expect("dbus-error", method="StartTone")
Beispiel #6
0
    def pickup(self):
        peer_removes_final_content = self.params['peer-removes-final-content']

        # Remove video content before remote pick the call
        self.video_content.Remove()
        e = self.q.expect('dbus-signal', signal='ContentRemoved')
        assertEquals(e.args[1][0], self.self_handle)
        assertEquals(e.args[1][1], cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED)
        assertEquals(e.args[1][2], '')

        self.initial_video = False
        self.video_content = None
        self.video_content_name = None
        self.video_stream = None

        # ...but before the peer notices, they accept the call.
        CallTest.pickup(self)

        # Gabble sends content-remove for the video stream...
        e = self.q.expect('stream-iq',
                          predicate=self.jp.action_predicate('content-remove'))

        # Only now the remote end removes the video stream; if gabble mistakenly
        # marked it as accepted on session acceptance, it'll crash right about
        # now. If it's good, stream will be really removed, and
        # we can proceed.
        self.stream.send(make_result_iq(self.stream, e.stanza))

        # Actually, we *do* want video!
        content_path = self.chan.AddContent(
            "video1",
            cs.CALL_MEDIA_TYPE_VIDEO,
            cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL,
            dbus_interface=cs.CHANNEL_TYPE_CALL)
        self.q.expect('dbus-signal', signal='ContentAdded')

        self.store_content(content_path, initial=False, incoming=False)

        md = self.jt2.get_call_video_md_dbus()
        self.check_and_accept_offer(self.video_content, md)

        candidates = self.jt2.get_call_remote_transports_dbus()
        self.video_stream.AddCandidates(
            candidates, dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

        e = self.q.expect('stream-iq',
                          predicate=self.jp.action_predicate('content-add'))
        c = e.query.firstChildElement()
        assertEquals('initiator', c['creator'])

        endpoints = self.video_stream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                                          "Endpoints",
                                          dbus_interface=dbus.PROPERTIES_IFACE)
        assertLength(1, endpoints)

        endpoint = self.bus.get_object(self.conn.bus_name, endpoints[0])
        self.enable_endpoint(endpoint)

        # Now, the call draws to a close.
        # We first remove the original stream
        self.audio_content.Remove()
        self.initial_audio = False
        self.audio_content = None
        self.audio_content_name = None
        self.audio_stream = None

        e = self.q.expect('stream-iq',
                          predicate=self.jp.action_predicate('content-remove'))
        content_remove_ack = make_result_iq(self.stream, e.stanza)

        if peer_removes_final_content:
            # The peer removes the final countdo content. From a footnote (!) in
            # XEP 0166:
            #  If the content-remove results in zero content definitions for the
            #  session, the entity that receives the content-remove SHOULD send
            #  a session-terminate action to the other party (since a session
            #  with no content definitions is void).
            # So, Gabble should respond to the content-remove with a
            # session-terminate.
            node = self.jp.SetIq(self.jt2.peer, self.jt2.jid, [
                self.jp.Jingle(
                    self.jt2.sid, self.jt2.peer, 'content-remove',
                    [self.jp.Content(c['name'], c['creator'], c['senders'])])
            ])
            self.stream.send(self.jp.xml(node))

        else:
            # The Telepathy client removes the second stream; Gabble should
            # terminate the session rather than sending a content-remove.
            self.video_content.Remove()
            self.initial_video = False
            self.video_content = None
            self.video_content_name = None
            self.video_stream = None

        st, ended = self.q.expect_many(
            EventPattern(
                'stream-iq',
                predicate=self.jp.action_predicate('session-terminate')),
            # Gabble shouldn't wait for the peer to ack the terminate before
            # considering the call finished.
            EventPattern('dbus-signal', signal='CallStateChanged'))
        assertEquals(ended.args[0], cs.CALL_STATE_ENDED)

        # Only now does the peer ack the content-remove. This serves as a
        # regression test for contents outliving the session; if the content did
        # did't die properly, this crashed Gabble.
        self.stream.send(content_remove_ack)
        sync_stream(self.q, self.stream)

        # The peer can ack the terminate too, just for completeness.
        self.stream.send(make_result_iq(self.stream, st.stanza))
Beispiel #7
0
    def prepare(self):
        events = self.q.expect_many(
                EventPattern('stream-iq', query_ns=ns.GOOGLE_JINGLE_INFO),
                EventPattern('stream-iq', to=None, query_ns='vcard-temp',
                    query_name='vCard'),
                EventPattern('stream-iq', query_ns=ns.ROSTER),
                )

        CallTest.prepare(self, events=events)

        ji_event = events[0]
        listen_port = listen_http(self.q, 0)

        jingleinfo = make_result_iq(self.stream, ji_event.stanza)
        stun = jingleinfo.firstChildElement().addElement('stun')
        server = stun.addElement('server')
        server['host'] = 'resolves-to-1.2.3.4'
        server['udp'] = '12345'

        self.expected_stun_server = '1.2.3.4'
        self.expected_stun_port = 12345

        # This bit is undocumented... but it has the same format as what we get
        # from Google Talk servers:
        # <iq to="censored" from="censored" id="73930208084" type="result">
        #   <query xmlns="google:jingleinfo">
        #     <stun>
        #       <server host="stun.l.google.com" udp="19302"/>
        #       <server host="stun4.l.google.com" udp="19302"/>
        #       <server host="stun3.l.google.com" udp="19302"/>
        #       <server host="stun1.l.google.com" udp="19302"/>
        #       <server host="stun2.l.google.com" udp="19302"/>
        #     </stun>
        #     <relay>
        #       <token>censored</token>
        #       <server host="relay.google.com" udp="19295" tcp="19294"
        #         tcpssl="443"/>
        #     </relay>
        #   </query>
        # </iq>
        relay = jingleinfo.firstChildElement().addElement('relay')
        relay.addElement('token', content='jingle all the way')
        server = relay.addElement('server')
        server['host'] = '127.0.0.1'
        server['udp'] = '11111'
        server['tcp'] = '22222'
        server['tcpssl'] = '443'
        # The special regression-test build of Gabble parses this attribute,
        # because we can't listen on port 80
        server['gabble-test-http-port'] = str(listen_port.getHost().port)
        self.stream.send(jingleinfo)
        jingleinfo = None
    
        # Spoof some jingle info. This is a regression test for
        # <https://bugs.freedesktop.org/show_bug.cgi?id=34048>. We assert that
        # Gabble has ignored this stuff later.
        iq = IQ(self.stream, 'set')
        iq['from'] = "*****@*****.**"
        query = iq.addElement((ns.GOOGLE_JINGLE_INFO, "query"))
    
        stun = query.addElement('stun')
        server = stun.addElement('server')
        server['host'] = '6.6.6.6'
        server['udp'] = '6666'
    
        relay = query.addElement('relay')
        relay.addElement('token', content='mwohahahahaha')
        server = relay.addElement('server')
        server['host'] = '127.0.0.1'
        server['udp'] = '666'
        server['tcp'] = '999'
        server['tcpssl'] = '666'
    
        self.stream.send(iq)
    
        # Force Gabble to process the capabilities
        sync_stream(self.q, self.stream)
Beispiel #8
0
    def pickup(self):

        if self.params['too-slow'] is not None:
            return

        CallTest.pickup(self)

        # The new API for STUN servers etc.
        cstream_props = self.audio_stream.GetAll(
            cs.CALL_STREAM_IFACE_MEDIA, dbus_interface=dbus.PROPERTIES_IFACE)

        assert cstream_props['Transport'] == cs.CALL_STREAM_TRANSPORT_GTALK_P2P
    
        # If Gabble has erroneously paid attention to the contact
        # [email protected] who sent us a google:jingleinfo stanza, this assertion
        # will fail.
        assertEquals([(self.expected_stun_server, self.expected_stun_port)],
            cstream_props['STUNServers'])
    
        credentials_used = {}
        credentials = {}
    
        for relay in cstream_props['RelayInfo']:
            assert relay['ip'] == '127.0.0.1', cstream_props['RelayInfo']
            assert relay['type'] in ('udp', 'tcp', 'tls')
            assert relay['component'] in (1, 2)
    
            if relay['type'] == 'udp':
                assert relay['port'] == 11111, cstream_props['RelayInfo']
            elif relay['type'] == 'tcp':
                assert relay['port'] == 22222, cstream_props['RelayInfo']
            elif relay['type'] == 'tls':
                assert relay['port'] == 443, cstream_props['RelayInfo']
    
            assert relay['username'][:8] == 'UUUUUUUU', \
                    cstream_props['RelayInfo']
            assert relay['password'][:8] == 'PPPPPPPP', \
                    cstream_props['RelayInfo']
            assert relay['password'][8:] == relay['username'][8:], \
                    cstream_props['RelayInfo']
            assert (relay['password'][8:], relay['type']) \
                    not in credentials_used
            credentials_used[(relay['password'][8:], relay['type'])] = 1
            credentials[(relay['component'], relay['type'])] = \
                    relay['password'][8:]
    
        assert (1, 'udp') in credentials
        assert (1, 'tcp') in credentials
        assert (1, 'tls') in credentials
        assert (2, 'udp') in credentials
        assert (2, 'tcp') in credentials
        assert (2, 'tls') in credentials
    
        assert ('0', 'udp') in credentials_used
        assert ('0', 'tcp') in credentials_used
        assert ('0', 'tls') in credentials_used
        assert ('1', 'udp') in credentials_used
        assert ('1', 'tcp') in credentials_used
        assert ('1', 'tls') in credentials_used
    
        # consistency check, since we currently reimplement Get separately
        for k in cstream_props:
            assert cstream_props[k] == self.audio_stream.Get(
                    cs.CALL_STREAM_IFACE_MEDIA, k,
                    dbus_interface=dbus.PROPERTIES_IFACE)
Beispiel #9
0
    def pickup(self):
        CallTest.pickup(self, held=True)

        q = self.q
        stream = self.stream
        chan = self.chan
        audio_cstream = self.audio_stream
        video_cstream = self.video_stream

        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        recv_state = audio_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "ReceivingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = audio_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "SendingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)
    
        recv_state = video_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "ReceivingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = video_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "SendingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)
    
        # Now we decide we do actually want to speak to them, and unhold.
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
    
        # Hooray! Now let's check that Hold works properly once the call's fully
        # established.
    
        # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)
    
        # ---- Test 2: successful hold ----
    
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        # ---- Test 3: GetHoldState returns held and hold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
        chan.Hold.RequestHold(True)
    
        # ---- Test 4: successful unhold ----
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
        # ---- Test 5: GetHoldState returns False and unhold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)
    
        # ---- Test 6: 3 parallel calls to hold ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
    
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            )
    
        # ---- Test 7: 3 parallel calls to unhold ----
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
        # ---- Test 8: hold, then change our minds before s-e has responded ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
    
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.hold_event
            )
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            # Gabble shouldn't send <unhold/> here because s-e might have
            # already relinquished the audio hardware.
            )
    
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        try:
            audio_cstream.CompleteReceivingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException as e:
            assertEquals (cs.INVALID_ARGUMENT, e.get_dbus_name ())
    
        try:
            audio_cstream.CompleteSendingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException as e:
            assertEquals (cs.INVALID_ARGUMENT, e.get_dbus_name ())
    
        try:
            video_cstream.CompleteReceivingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException as e:
            assertEquals (cs.INVALID_ARGUMENT, e.get_dbus_name ())
    
        try:
            video_cstream.CompleteSendingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException as e:
            assertEquals (cs.INVALID_ARGUMENT, e.get_dbus_name ())
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
    
        # --- Test 9: unhold, then change our minds before s-e has responded ----
    
        # Go to state "held" first
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            )
    
        # Actually do test 9
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
    
        # Check that Gabble doesn't send another <hold/>, or send <unhold/>
        # before we change our minds.
        q.forbid_events(self.unhold_event + self.hold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            )
    
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
    
        sync_stream(q, stream)
    
        # ---- Test 10: attempting to unhold fails (both streams) ----
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        audio_cstream.ReportSendingFailure(0, "", "",
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.ReportSendingFailure(0, "", "",
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            )
    
        # ---- Test 11: attempting to unhold fails (audio stream) ----
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        audio_cstream.ReportReceivingFailure(0, "", "",
            dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        sync_stream(q, stream)
    
        # ---- Test 12: attempting to unhold partially fails (video stream) ----
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        video_cstream.ReportReceivingFailure(0, "", "",
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_RESOURCE_NOT_AVAILABLE]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event + self.hold_event)
    
        if self.jp.has_mutable_streams():
            self.mutable_stream_tests()
Beispiel #10
0
 def connect(self):
     assertEquals((cs.HS_HELD, cs.HSR_REQUESTED),
             self.chan.Hold.GetHoldState())
     assertEquals((cs.HS_HELD, cs.HSR_REQUESTED),
             self.chan.Hold.GetHoldState())
     CallTest.connect(self, expect_after_si=self.hold_event)
    def pickup(self):
        jt2 = self.jt2
        jp = self.jp
        q = self.q
        cstream = self.audio_stream
        remote_handle = self.peer_handle
        can_change_direction = self.can_change_direction
        incoming = self.incoming

        # We pickup the call as we need active state to run this test
        CallTest.pickup(self)

        self.test_connect_disconnect_endpoint()

        # FIXME: This should eventually be break down in smaller test methods

        # Turn sending off and on again

        # but first, let's try direction changes requested by the other side

        if can_change_direction:
            content_name = jt2.audio_names[0]
            if incoming:
                jt2.content_modify(content_name, "initiator", "initiator")
            else:
                jt2.content_modify(content_name, "initiator", "responder")
            o = q.expect('dbus-signal', signal='LocalSendingStateChanged')
            assertEquals(cs.CALL_SENDING_STATE_PENDING_STOP_SENDING, o.args[0])

            cstream.SetSending(False,
                    dbus_interface = cs.CALL_STREAM)
            o = q.expect('dbus-signal', signal='SendingStateChanged')
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_STOP, o.args[0])

            cstream.CompleteSendingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
            o = q.expect('dbus-signal', signal='SendingStateChanged',
                    interface = cs.CALL_STREAM_IFACE_MEDIA)
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, o.args[0])

            jt2.content_modify(content_name, "initiator", "both")
            o = q.expect('dbus-signal', signal='LocalSendingStateChanged')
            assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, o.args[0])

            cstream.SetSending(True,
                    dbus_interface = cs.CALL_STREAM)

            ret = q.expect_many(
                    EventPattern('dbus-signal', signal='SendingStateChanged'),
                    EventPattern('dbus-signal',
                        signal='LocalSendingStateChanged'))
            assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START,
                    ret[0].args[0])
            assertEquals(cs.CALL_SENDING_STATE_SENDING, ret[1].args[0])

            cstream.CompleteSendingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STARTED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
            o = q.expect('dbus-signal', signal='SendingStateChanged',
                    interface = cs.CALL_STREAM_IFACE_MEDIA)
            assertEquals(cs.CALL_STREAM_FLOW_STATE_STARTED, o.args[0])

            stream_props = cstream.GetAll(cs.CALL_STREAM,
                    dbus_interface = dbus.PROPERTIES_IFACE)
            assertEquals({remote_handle: cs.CALL_SENDING_STATE_SENDING},
                    stream_props["RemoteMembers"])
            assertEquals(cs.CALL_SENDING_STATE_SENDING,
                    stream_props["LocalSendingState"])

        cstream.SetSending(False,
                dbus_interface = cs.CALL_STREAM)
        ret = q.expect_many(
                EventPattern('dbus-signal', signal='SendingStateChanged'),
                EventPattern('dbus-signal', signal='LocalSendingStateChanged'))
        assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_STOP, ret[0].args[0])
        assertEquals(cs.CALL_SENDING_STATE_NONE, ret[1].args[0])

        cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        o = q.expect('dbus-signal', signal='SendingStateChanged',
                interface = cs.CALL_STREAM_IFACE_MEDIA)
        assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, o.args[0])

        stream_props = cstream.GetAll(cs.CALL_STREAM,
                dbus_interface = dbus.PROPERTIES_IFACE)
        assertEquals({remote_handle: cs.CALL_SENDING_STATE_SENDING},
                stream_props["RemoteMembers"])
        assertEquals(cs.CALL_SENDING_STATE_NONE,
                stream_props["LocalSendingState"])

        # If possible, test the other side asking us to start then stop sending

        if can_change_direction:
            jt2.content_modify(content_name, "initiator", "both")
            o = q.expect('dbus-signal', signal='LocalSendingStateChanged')
            assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, o.args[0])

            if incoming:
                jt2.content_modify(content_name, "initiator", "initiator")
            else:
                jt2.content_modify(content_name, "initiator", "responder")
            o = q.expect('dbus-signal', signal='LocalSendingStateChanged')
            assertEquals(cs.CALL_SENDING_STATE_NONE, o.args[0])

            jt2.content_modify(content_name, "initiator", "both")
            o = q.expect('dbus-signal', signal='LocalSendingStateChanged')
            assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, o.args[0])


        cstream.SetSending(True, dbus_interface = cs.CALL_STREAM)

        ret = q.expect_many(
                EventPattern('dbus-signal', signal='SendingStateChanged'),
                EventPattern('dbus-signal', signal='LocalSendingStateChanged'))
        assertEquals(cs.CALL_STREAM_FLOW_STATE_PENDING_START, ret[0].args[0])
        assertEquals(cs.CALL_SENDING_STATE_SENDING, ret[1].args[0])

        cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)

        stream_props = cstream.GetAll(cs.CALL_STREAM,
                dbus_interface = dbus.PROPERTIES_IFACE)
        assertEquals({remote_handle: cs.CALL_SENDING_STATE_SENDING},
                stream_props["RemoteMembers"])
        assertEquals(cs.CALL_SENDING_STATE_SENDING,
                stream_props["LocalSendingState"])

        # Turn receiving off and on again

        try:
            cstream.RequestReceiving(remote_handle, False,
                    dbus_interface = cs.CALL_STREAM)
            assert can_change_direction
        except dbus.DBusException, e:
            assertEquals(cs.NOT_CAPABLE, e.get_dbus_name())
            assert not can_change_direction
Beispiel #12
0
 def pickup(self):
     CallTest.pickup(self)
     self.test_dtmf()
    def pickup(self):
        CallTest.pickup(self, held=True)

        q = self.q
        stream = self.stream
        chan = self.chan
        cstream = self.audio_stream

        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())

        recv_state = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                                 "ReceivingState",
                                 dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                                 "SendingState",
                                 dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals(cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)

        # Now we decide we do actually want to speak to them, and unhold.
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # Hooray! Now let's check that Hold works properly once the call's fully
        # established.

        # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)

        # ---- Test 2: successful hold ----

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
        )

        # ---- Test 3: GetHoldState returns held and hold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
        chan.Hold.RequestHold(True)

        # ---- Test 4: successful unhold ----

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # ---- Test 5: GetHoldState returns False and unhold is a no-op ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)

        # ---- Test 6: 3 parallel calls to hold ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state

        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STOPPED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STOPPED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_HELD, cs.HSR_REQUESTED]),
        )

        # ---- Test 7: 3 parallel calls to unhold ----

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
        )

        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        cstream.CompleteReceivingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        cstream.CompleteSendingStateChange(
            cs.CALL_STREAM_FLOW_STATE_STARTED,
            dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_STARTED],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event)

        # ---- Test 8: hold, then change our minds before s-e has responded ----

        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state

        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            *self.hold_event)

        q.forbid_events(self.unhold_event)

        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal',
                         signal='HoldStateChanged',
                         args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal',
                         signal='SendingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal',
                         signal='ReceivingStateChanged',
                         args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                         interface=cs.CALL_STREAM_IFACE_MEDIA),
            # Gabble shouldn't send <unhold/> here because s-e might have
            # already relinquished the audio hardware.
        )

        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)

        try:
            cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException, e:
            assertEquals(cs.INVALID_ARGUMENT, e.get_dbus_name())
 def connect(self):
     assertEquals((cs.HS_HELD, cs.HSR_REQUESTED),
             self.chan.Hold.GetHoldState())
     assertEquals((cs.HS_HELD, cs.HSR_REQUESTED),
             self.chan.Hold.GetHoldState())
     CallTest.connect(self, expect_after_si=self.hold_event)
Beispiel #15
0
    def pickup(self):
        CallTest.pickup(self)

        # Check the DTMF method does not exist
        call_async(self.q, self.video_content.DTMF, 'StartTone', 3)
        self.q.expect('dbus-error', method='StartTone')
    def pickup(self):
        CallTest.pickup(self, held=True)

        q = self.q
        stream = self.stream
        chan = self.chan
        audio_cstream = self.audio_stream
        video_cstream = self.video_stream

        assertEquals((cs.HS_HELD, cs.HSR_REQUESTED), chan.Hold.GetHoldState())
    
        recv_state = audio_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "ReceivingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = audio_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "SendingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)
    
        recv_state = video_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "ReceivingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, recv_state)
        send_state = video_cstream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "SendingState", dbus_interface=dbus.PROPERTIES_IFACE)
        assertEquals (cs.CALL_STREAM_FLOW_STATE_STOPPED, send_state)
    
        # Now we decide we do actually want to speak to them, and unhold.
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
    
        # Hooray! Now let's check that Hold works properly once the call's fully
        # established.
    
        # ---- Test 1: GetHoldState returns unheld and unhold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)
    
        # ---- Test 2: successful hold ----
    
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                         args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                         interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
    
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            )
    
        # ---- Test 3: GetHoldState returns held and hold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_HELD, hold_state
        chan.Hold.RequestHold(True)
    
        # ---- Test 4: successful unhold ----
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
        # ---- Test 5: GetHoldState returns False and unhold is a no-op ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
        chan.Hold.RequestHold(False)
    
        # ---- Test 6: 3 parallel calls to hold ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
    
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            *self.hold_event
            )
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STOPPED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STOPPED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_HELD, cs.HSR_REQUESTED]),
            )
    
        # ---- Test 7: 3 parallel calls to unhold ----
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-return', method='RequestHold', value=()),
            )
    
        # Ensure that if Gabble sent the <unhold/> stanza too early it's already
        # arrived.
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        audio_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        audio_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteReceivingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        video_cstream.CompleteSendingStateChange(
                cs.CALL_STREAM_FLOW_STATE_STARTED,
                dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_UNHELD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_STARTED],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.unhold_event
            )
    
        # ---- Test 8: hold, then change our minds before s-e has responded ----
    
        hold_state = chan.Hold.GetHoldState()
        assert hold_state[0] == cs.HS_UNHELD, hold_state
    
        call_async(q, chan.Hold, 'RequestHold', True)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_HOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_STOP],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            *self.hold_event
            )
    
        q.forbid_events(self.unhold_event)
    
        call_async(q, chan.Hold, 'RequestHold', False)
        q.expect_many(
            EventPattern('dbus-signal', signal='HoldStateChanged',
                args=[cs.HS_PENDING_UNHOLD, cs.HSR_REQUESTED]),
            EventPattern('dbus-signal', signal='SendingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            EventPattern('dbus-signal', signal='ReceivingStateChanged',
                args = [cs.CALL_STREAM_FLOW_STATE_PENDING_START],
                interface = cs.CALL_STREAM_IFACE_MEDIA),
            # Gabble shouldn't send <unhold/> here because s-e might have
            # already relinquished the audio hardware.
            )
    
        sync_stream(q, stream)
        q.unforbid_events(self.unhold_event)
    
        try:
            audio_cstream.CompleteReceivingStateChange(
                    cs.CALL_STREAM_FLOW_STATE_STOPPED,
                    dbus_interface = cs.CALL_STREAM_IFACE_MEDIA)
        except dbus.DBusException, e:
            assertEquals (cs.INVALID_ARGUMENT, e.get_dbus_name ())
    def pickup(self):
        peer_removes_final_content = self.params['peer-removes-final-content']

        # Remove video content before remote pick the call
        self.video_content.Remove()
        e = self.q.expect('dbus-signal', signal='ContentRemoved')
        assertEquals(e.args[1][0], self.self_handle)
        assertEquals(e.args[1][1], cs.CALL_STATE_CHANGE_REASON_USER_REQUESTED)
        assertEquals(e.args[1][2], '')

        self.initial_video = False
        self.video_content = None
        self.video_content_name = None
        self.video_stream = None

        # ...but before the peer notices, they accept the call.
        CallTest.pickup(self)

        # Gabble sends content-remove for the video stream...
        e = self.q.expect('stream-iq',
                predicate=self.jp.action_predicate('content-remove'))

        # Only now the remote end removes the video stream; if gabble mistakenly
        # marked it as accepted on session acceptance, it'll crash right about
        # now. If it's good, stream will be really removed, and
        # we can proceed.
        self.stream.send(make_result_iq(self.stream, e.stanza))
    
        # Actually, we *do* want video!
        content_path = self.chan.AddContent(
            "video1", cs.CALL_MEDIA_TYPE_VIDEO,
            cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL,
            dbus_interface=cs.CHANNEL_TYPE_CALL);
        self.q.expect('dbus-signal', signal='ContentAdded')

        self.store_content(content_path, initial=False, incoming=False)

        md = self.jt2.get_call_video_md_dbus()
        self.check_and_accept_offer(self.video_content, md)

        candidates = self.jt2.get_call_remote_transports_dbus()
        self.video_stream.AddCandidates(candidates,
                dbus_interface=cs.CALL_STREAM_IFACE_MEDIA)

        e = self.q.expect('stream-iq',
                predicate=self.jp.action_predicate('content-add'))
        c = e.query.firstChildElement()
        assertEquals('initiator', c['creator'])

        endpoints = self.video_stream.Get(cs.CALL_STREAM_IFACE_MEDIA,
                "Endpoints", dbus_interface=dbus.PROPERTIES_IFACE)
        assertLength(1, endpoints)

        endpoint = self.bus.get_object(self.conn.bus_name, endpoints[0])
        self.enable_endpoint(endpoint)

        # Now, the call draws to a close.
        # We first remove the original stream
        self.audio_content.Remove()
        self.initial_audio = False
        self.audio_content = None
        self.audio_content_name = None
        self.audio_stream = None
    
        e = self.q.expect('stream-iq',
                predicate=self.jp.action_predicate('content-remove'))
        content_remove_ack = make_result_iq(self.stream, e.stanza)
    
        if peer_removes_final_content:
            # The peer removes the final countdo content. From a footnote (!) in
            # XEP 0166:
            #  If the content-remove results in zero content definitions for the
            #  session, the entity that receives the content-remove SHOULD send
            #  a session-terminate action to the other party (since a session
            #  with no content definitions is void).
            # So, Gabble should respond to the content-remove with a
            # session-terminate.
            node = self.jp.SetIq(self.jt2.peer, self.jt2.jid, [
                self.jp.Jingle(self.jt2.sid, self.jt2.peer, 'content-remove', [
                    self.jp.Content(c['name'], c['creator'], c['senders']) ]) ])
            self.stream.send(self.jp.xml(node))

        else:
            # The Telepathy client removes the second stream; Gabble should
            # terminate the session rather than sending a content-remove.
            self.video_content.Remove()
            self.initial_video = False
            self.video_content = None
            self.video_content_name = None
            self.video_stream = None

        st, ended = self.q.expect_many(
            EventPattern('stream-iq',
                predicate=self.jp.action_predicate('session-terminate')),
            # Gabble shouldn't wait for the peer to ack the terminate before
            # considering the call finished.
            EventPattern('dbus-signal', signal='CallStateChanged'))
        assertEquals(ended.args[0], cs.CALL_STATE_ENDED)
    
        # Only now does the peer ack the content-remove. This serves as a
        # regression test for contents outliving the session; if the content did
        # did't die properly, this crashed Gabble.
        self.stream.send(content_remove_ack)
        sync_stream(self.q, self.stream)
 
        # The peer can ack the terminate too, just for completeness.
        self.stream.send(make_result_iq(self.stream, st.stanza))