diff options
author | Olivier CrĂȘte <olivier.crete@collabora.com> | 2012-01-31 14:36:12 +0000 |
---|---|---|
committer | Olivier CrĂȘte <olivier.crete@collabora.com> | 2012-02-10 13:34:39 +0100 |
commit | 6dc51e5bbe1c9a2a46e489967a94d366b35fe65e (patch) | |
tree | 0d34033c724551a3a9f23500ddba7a344cc121bd /tests | |
parent | ac815e6d8072d1cb2cf5e27ea8516d125809e473 (diff) |
Port to Call1
Diffstat (limited to 'tests')
-rw-r--r-- | tests/twisted/Makefile.am | 1 | ||||
-rw-r--r-- | tests/twisted/constants.py | 88 | ||||
-rw-r--r-- | tests/twisted/sofiatest.py | 2 | ||||
-rw-r--r-- | tests/twisted/voip/dtmf.py | 160 | ||||
-rw-r--r-- | tests/twisted/voip/incoming-basics.py | 279 | ||||
-rw-r--r-- | tests/twisted/voip/outgoing-basics.py | 359 | ||||
-rw-r--r-- | tests/twisted/voip/voip_test.py | 124 |
7 files changed, 444 insertions, 569 deletions
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index 74645c2..816c77d 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -12,7 +12,6 @@ TWISTED_TESTS = \ text/initiate-requestotron.py \ voip/incoming-basics.py \ voip/outgoing-basics.py \ - voip/dtmf.py \ $(NULL) TESTS = diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py index c590b3d..e13197a 100644 --- a/tests/twisted/constants.py +++ b/tests/twisted/constants.py @@ -27,14 +27,13 @@ CHANNEL_IFACE_TUBE = CHANNEL + ".Interface.Tube" CHANNEL_IFACE_SASL_AUTH = CHANNEL + ".Interface.SaslAuthentication.DRAFT" CHANNEL_IFACE_CONFERENCE = CHANNEL + '.Interface.Conference' -CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call.DRAFT" +CHANNEL_TYPE_CALL = CHANNEL + ".Type.Call1" CHANNEL_TYPE_CONTACT_LIST = CHANNEL + ".Type.ContactList" CHANNEL_TYPE_CONTACT_SEARCH = CHANNEL + ".Type.ContactSearch" CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text" CHANNEL_TYPE_TUBES = CHANNEL + ".Type.Tubes" CHANNEL_TYPE_STREAM_TUBE = CHANNEL + ".Type.StreamTube" CHANNEL_TYPE_DBUS_TUBE = CHANNEL + ".Type.DBusTube" -CHANNEL_TYPE_STREAMED_MEDIA = CHANNEL + ".Type.StreamedMedia" CHANNEL_TYPE_TEXT = CHANNEL + ".Type.Text" CHANNEL_TYPE_FILE_TRANSFER = CHANNEL + ".Type.FileTransfer" CHANNEL_TYPE_SERVER_AUTHENTICATION = \ @@ -56,35 +55,46 @@ INITIATOR_HANDLE = CHANNEL + '.InitiatorHandle' INITIATOR_ID = CHANNEL + '.InitiatorID' INTERFACES = CHANNEL + '.Interfaces' -INITIAL_AUDIO = CHANNEL_TYPE_STREAMED_MEDIA + '.InitialAudio' -INITIAL_VIDEO = CHANNEL_TYPE_STREAMED_MEDIA + '.InitialVideo' -IMMUTABLE_STREAMS = CHANNEL_TYPE_STREAMED_MEDIA + '.ImmutableStreams' - -CALL_INITIAL_AUDIO = CHANNEL_TYPE_CALL + '.InitialAudio' -CALL_INITIAL_VIDEO = CHANNEL_TYPE_CALL + '.InitialVideo' -CALL_MUTABLE_CONTENTS = CHANNEL_TYPE_CALL + '.MutableContents' +INITIAL_AUDIO = CHANNEL_TYPE_CALL + '.InitialAudio' +INITIAL_VIDEO = CHANNEL_TYPE_CALL + '.InitialVideo' +INITIAL_AUDIO_NAME = CHANNEL_TYPE_CALL + '.InitialAudioName' +INITIAL_VIDEO_NAME = CHANNEL_TYPE_CALL + '.InitialVideoName' +INITIAL_TRANSPORT = CHANNEL_TYPE_CALL + '.InitialTransport' +MUTABLE_CONTENTS = CHANNEL_TYPE_CALL + '.MutableContents' DTMF_INITIAL_TONES = CHANNEL_IFACE_DTMF + '.InitialTones' -CALL_CONTENT = 'org.freedesktop.Telepathy.Call.Content.DRAFT' +CALL_CONTENT = 'org.freedesktop.Telepathy.Call1.Content' CALL_CONTENT_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call.Content.Interface.Media.DRAFT' + 'org.freedesktop.Telepathy.Call1.Content.Interface.Media' -CALL_CONTENT_CODECOFFER = \ - 'org.freedesktop.Telepathy.Call.Content.CodecOffer.DRAFT' +CALL_CONTENT_MEDIA_DESCRIPTION = \ + 'org.freedesktop.Telepathy.Call1.Content.MediaDescription' -CALL_STREAM = 'org.freedesktop.Telepathy.Call.Stream.DRAFT' +CALL_STREAM = 'org.freedesktop.Telepathy.Call1.Stream' CALL_STREAM_IFACE_MEDIA = \ - 'org.freedesktop.Telepathy.Call.Stream.Interface.Media.DRAFT' + 'org.freedesktop.Telepathy.Call1.Stream.Interface.Media' + +CALL_STREAM_ENDPOINT = 'org.freedesktop.Telepathy.Call1.Stream.Endpoint' -CALL_STREAM_ENDPOINT = 'org.freedesktop.Telepathy.Call.Stream.Endpoint.DRAFT' + +CALL_STREAM_ENDPOINT_STATE_CONNECTING = 0 +CALL_STREAM_ENDPOINT_STATE_PROVISIONALLY_CONNECTED = 1 +CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED = 2 +CALL_STREAM_ENDPOINT_STATE_EXHAUSTED_CANDIDATES = 3 +CALL_STREAM_ENDPOINT_STATE_FAILED = 4 CALL_MEDIA_TYPE_AUDIO = 0 CALL_MEDIA_TYPE_VIDEO = 1 -CALL_STREAM_TRANSPORT_RAW_UDP = 0 -CALL_STREAM_TRANSPORT_ICE = 1 -CALL_STREAM_TRANSPORT_GOOGLE = 2 + +MEDIA_STREAM_BASE_PROTO_UDP = 0 +MEDIA_STREAM_BASE_PROTO_TCP = 1 + +CALL_STREAM_TRANSPORT_UNKNOWN = 0 +CALL_STREAM_TRANSPORT_RAW_UDP = 1 +CALL_STREAM_TRANSPORT_ICE = 2 + CALL_STATE_UNKNOWN = 0 CALL_STATE_PENDING_INITIATOR = 1 @@ -96,12 +106,17 @@ CALL_MEMBER_FLAG_RINGING = 1 CALL_MEMBER_FLAG_HELD = 2 CALL_DISPOSITION_NONE = 0 -CALL_DISPOSITION_EARLY_MEDIA = 1 -CALL_DISPOSITION_INITIAL = 2 +CALL_DISPOSITION_INITIAL = 1 CALL_SENDING_STATE_NONE = 0 CALL_SENDING_STATE_PENDING_SEND = 1 CALL_SENDING_STATE_SENDING = 2 +CALL_SENDING_STATE_PENDING_STOP_SENDING = 3 + +CALL_STREAM_FLOW_STATE_STOPPED = 0 +CALL_STREAM_FLOW_STATE_PENDING_START = 1 +CALL_STREAM_FLOW_STATE_PENDING_STOP = 2 +CALL_STREAM_FLOW_STATE_STARTED = 3 SUBSCRIPTION_STATE_UNKNOWN = 0 SUBSCRIPTION_STATE_NO = 1 @@ -293,10 +308,24 @@ HSR_NONE = 0 HSR_REQUESTED = 1 HSR_RESOURCE_NOT_AVAILABLE = 2 -CALL_STATE_RINGING = 1 -CALL_STATE_QUEUED = 2 -CALL_STATE_HELD = 4 -CALL_STATE_FORWARDED = 8 +CALL_STATE_UNKNOWN = 0, +CALL_STATE_PENDING_INITIATOR = 1 +CALL_STATE_INITIALISING = 2 +CALL_STATE_INITIALISED = 3 +CALL_STATE_ACCEPTED = 4 +CALL_STATE_ACTIVE = 5 +CALL_STATE_ENDED = 6 + + +CALL_MEMBER_FLAG_RINGING = 1 +CALL_MEMBER_FLAG_HELD = 2 + +CALL_FLAG_LOCALLY_HELD = 1 +CALL_FLAG_LOCALLY_MUTED = 2 +CALL_FLAG_LOCALLY_RINGING = 4 +CALL_FLAG_LOCALLY_QUEUED = 8 +CALL_FLAG_FORWARDED = 16 +CALL_FLAG_CLEARING = 32 CONN_STATUS_CONNECTED = 0 CONN_STATUS_CONNECTING = 1 @@ -401,3 +430,12 @@ TLS_CERT_STATE_REJECTED = 2 TLS_REJECT_REASON_UNKNOWN = 0 TLS_REJECT_REASON_UNTRUSTED = 1 + + +CALL_CONTENT_PACKETIZATION_RTP = 0 +CALL_CONTENT_PACKETIZATION_RAW = 1 +CALL_CONTENT_PACKETIZATION_MSN_WEBCAM = 2 + +CALL_SCR_UNKNOWN = 0 +CALL_SCR_PROGRESS_MADE = 1 +CALL_SCR_USER_REQUESTED = 2 diff --git a/tests/twisted/sofiatest.py b/tests/twisted/sofiatest.py index 38276d2..ad85947 100644 --- a/tests/twisted/sofiatest.py +++ b/tests/twisted/sofiatest.py @@ -32,7 +32,7 @@ class SipProxy(sip.RegisterProxy): def handle_request(self, message, addr): if message.method == 'REGISTER': - return sip.RegisterProxy.handle_request(self, message, addr) + return sip.RegisterProxy.handle_REGISTER_request(self, message, addr) elif message.method == 'OPTIONS' and \ 'REGISTRATION PROBE' == message.headers.get('subject','')[0]: self.deliverResponse(self.responseFromRequest(200, message)) diff --git a/tests/twisted/voip/dtmf.py b/tests/twisted/voip/dtmf.py deleted file mode 100644 index 4369bc3..0000000 --- a/tests/twisted/voip/dtmf.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -Test DTMF dialstring playback and signalling. -""" - -from sofiatest import exec_test -from servicetest import ( - call_async, wrap_channel, EventPattern, - assertEquals, assertContains, assertLength, assertSameSets - ) -from voip_test import VoipTestContext -import constants as cs - -def setup_dtmf_channel(context, initial_tones=None): - q = context.q - bus = context.bus - conn = context.conn - - conn.Connect() - q.expect('dbus-signal', signal='StatusChanged', args=[0, 1]) - - request_params = { - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, - cs.TARGET_ID: context.peer, - cs.INITIAL_AUDIO: True, - } - if initial_tones: - request_params[cs.DTMF_INITIAL_TONES] = initial_tones - - path = conn.Requests.CreateChannel(request_params)[0] - - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['MediaSignalling', 'DTMF']) - - channel_props = chan.Properties.GetAll(cs.CHANNEL) - - assertContains(cs.CHANNEL_IFACE_DTMF, channel_props['Interfaces']) - - dtmf_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_DTMF) - - if initial_tones: - assertEquals(initial_tones, dtmf_props['InitialTones']) - else: - assertEquals('', dtmf_props['InitialTones']) - assertEquals(False, dtmf_props['CurrentlySendingTones']) - - stream_handler = context.handle_audio_session(chan) - - invite_event = q.expect('sip-invite') - - context.accept(invite_event.sip_message) - - q.expect('dbus-signal', signal='SetRemoteCodecs') - - stream_handler.SupportedCodecs(context.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - - return chan - -def request_initial_tones(q, bus, conn, sip_proxy, peer='foo@bar.com'): - context = VoipTestContext(q, conn, bus, sip_proxy, 'sip:testacc@127.0.0.1', peer) - - tones = '123' - - chan = setup_dtmf_channel(context, tones) - - q.expect_many( - EventPattern('dbus-signal', signal='SendingTones', args=[tones]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', args=[int(tones[0])])) - - assertEquals(True, chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'CurrentlySendingTones')) - - q.expect('dbus-signal', signal='StopTelephonyEvent') - - for i in range(1, len(tones) - 1): - q.expect('dbus-signal', signal='StartTelephonyEvent', args=[int(tones[i])]) - q.expect('dbus-signal', signal='StopTelephonyEvent') - - q.expect('dbus-signal', signal='StoppedTones', args=[False]) - - assertEquals(False, chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'CurrentlySendingTones')) - -def multiple_tones(q, bus, conn, sip_proxy, peer='foo@bar.com'): - - context = VoipTestContext(q, conn, bus, sip_proxy, 'sip:testacc@127.0.0.1', peer) - - chan = setup_dtmf_channel(context) - - tones_deferred = '78' - tones = '56w' + tones_deferred - - chan.DTMF.MultipleTones(tones) - - q.expect_many( - EventPattern('dbus-signal', signal='SendingTones', args=[tones]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', args=[int(tones[0])])) - - dtmf_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_DTMF) - assertEquals(True, dtmf_props['CurrentlySendingTones']) - assertEquals('', dtmf_props['DeferredTones']) - - q.expect('dbus-signal', signal='StopTelephonyEvent') - - q.expect('dbus-signal', signal='StartTelephonyEvent', args=[int(tones[1])]) - q.expect('dbus-signal', signal='StopTelephonyEvent') - - q.expect('dbus-signal', signal='TonesDeferred', args=[tones_deferred]) - - dtmf_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_DTMF) - - assertEquals(False, dtmf_props['CurrentlySendingTones']) - assertEquals(tones_deferred, dtmf_props['DeferredTones']) - - chan.DTMF.MultipleTones(tones_deferred) - - q.expect_many( - EventPattern('dbus-signal', signal='SendingTones', args=[tones_deferred]), - EventPattern('dbus-signal', signal='StartTelephonyEvent', args=[int(tones_deferred[0])])) - - dtmf_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_DTMF) - - assertEquals(True, dtmf_props['CurrentlySendingTones']) - assertEquals('', dtmf_props['DeferredTones']) - - q.expect('dbus-signal', signal='StopTelephonyEvent') - - for i in range(1, len(tones_deferred) - 1): - q.expect('dbus-signal', signal='StartTelephonyEvent', args=[int(tones_deferred[i])]) - q.expect('dbus-signal', signal='StopTelephonyEvent') - - q.expect('dbus-signal', signal='StoppedTones', args=[False]) - -def bleep_bloop(q, bus, conn, sip_proxy, peer='foo@bar.com'): - - context = VoipTestContext(q, conn, bus, sip_proxy, 'sip:testacc@127.0.0.1', peer) - - chan = setup_dtmf_channel(context) - - call_async(q, chan.DTMF, 'StartTone', 666, 3) - q.expect_many( - EventPattern('dbus-signal', signal='StartTelephonyEvent'), - EventPattern('dbus-signal', signal='SendingTones', args=['3']), - EventPattern('dbus-return', method='StartTone'), - ) - - assertEquals(True, chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'CurrentlySendingTones')) - - call_async(q, chan.DTMF, 'StopTone', 666) - q.expect_many( - EventPattern('dbus-signal', signal='StopTelephonyEvent'), - EventPattern('dbus-signal', signal='StoppedTones', args=[True]), - EventPattern('dbus-return', method='StopTone'), - ) - - assertEquals(False, chan.Properties.Get(cs.CHANNEL_IFACE_DTMF, 'CurrentlySendingTones')) - -if __name__ == '__main__': - exec_test(request_initial_tones) - exec_test(multiple_tones) - exec_test(bleep_bloop) diff --git a/tests/twisted/voip/incoming-basics.py b/tests/twisted/voip/incoming-basics.py index 9ab3949..2a7890d 100644 --- a/tests/twisted/voip/incoming-basics.py +++ b/tests/twisted/voip/incoming-basics.py @@ -7,8 +7,8 @@ import dbus from sofiatest import exec_test from servicetest import ( make_channel_proxy, wrap_channel, - EventPattern, call_async, - assertEquals, assertContains, assertLength, + EventPattern, call_async, ProxyWrapper, + assertEquals, assertNotEquals, assertContains, assertLength, ) import constants as cs from voip_test import VoipTestContext @@ -25,139 +25,178 @@ def test(q, bus, conn, sip_proxy, peer='foo@bar.com'): # Try making a call to ourself. StreamedMedia should refuse this because # the API doesn't support it. context.incoming_call_from_self() - q.expect('sip-response', code=501) - + acc = q.expect('sip-response', code=501) + # Remote end calls us context.incoming_call() - nc, e = q.expect_many( - EventPattern('dbus-signal', signal='NewChannels'), - EventPattern('dbus-signal', signal='NewSessionHandler'), - )[0:2] + nc = q.expect('dbus-signal', signal='NewChannels') path, props = nc.args[0][0] - ct = props[cs.CHANNEL_TYPE] - ht = props[cs.CHANNEL + '.TargetHandleType'] - h = props[cs.CHANNEL + '.TargetHandle'] - - assert ct == cs.CHANNEL_TYPE_STREAMED_MEDIA, ct - assert ht == cs.HT_CONTACT, ht - assert h == remote_handle, h - - media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group') - media_iface = make_channel_proxy(conn, path, 'Channel.Type.StreamedMedia') - - # S-E was notified about new session handler, and calls Ready on it - assert e.args[1] == 'rtp' - session_handler = make_channel_proxy(conn, e.args[0], 'Media.SessionHandler') - session_handler.Ready() - - nsh_event = q.expect('dbus-signal', signal='NewStreamHandler') - - # S-E gets notified about a newly-created stream - stream_handler = make_channel_proxy(conn, nsh_event.args[0], - 'Media.StreamHandler') - - streams = media_iface.ListStreams() - assertLength(1, streams) - - stream_id, stream_handle, stream_type, _, stream_direction, pending_flags =\ - streams[0] - assertEquals(remote_handle, stream_handle) - assertEquals(cs.MEDIA_STREAM_TYPE_AUDIO, stream_type) - assertEquals(cs.MEDIA_STREAM_DIRECTION_RECEIVE, stream_direction) - assertEquals(cs.MEDIA_STREAM_PENDING_LOCAL_SEND, pending_flags) - - # Exercise channel properties - channel_props = media_chan.GetAll( - cs.CHANNEL, dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals(remote_handle, channel_props['TargetHandle']) - assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) - assertEquals((cs.HT_CONTACT, remote_handle), - media_chan.GetHandle(dbus_interface=cs.CHANNEL)) - assertEquals(context.peer_id, channel_props['TargetID']) - assertEquals(context.peer_id, channel_props['InitiatorID']) - assertEquals(remote_handle, channel_props['InitiatorHandle']) - assertEquals(False, channel_props['Requested']) - - group_props = media_chan.GetAll( - cs.CHANNEL_IFACE_GROUP, dbus_interface=dbus.PROPERTIES_IFACE) - - assert group_props['SelfHandle'] == self_handle, \ - (group_props['SelfHandle'], self_handle) - - flags = group_props['GroupFlags'] - assert flags & cs.GF_PROPERTIES, flags - # Changing members in any way other than adding or removing yourself is - # meaningless for incoming calls, and the flags need not be sent to change - # your own membership. - assert not flags & cs.GF_CAN_ADD, flags - assert not flags & cs.GF_CAN_REMOVE, flags - assert not flags & cs.GF_CAN_RESCIND, flags - - assert group_props['Members'] == [remote_handle], group_props['Members'] - assert group_props['RemotePendingMembers'] == [], \ - group_props['RemotePendingMembers'] - # We're local pending because remote_handle invited us. - assert group_props['LocalPendingMembers'] == \ - [(self_handle, remote_handle, cs.GC_REASON_INVITED, '')], \ - unwrap(group_props['LocalPendingMembers']) - - streams = media_chan.ListStreams( - dbus_interface=cs.CHANNEL_TYPE_STREAMED_MEDIA) - assert len(streams) == 1, streams - assert len(streams[0]) == 6, streams[0] - # streams[0][0] is the stream identifier, which in principle we can't - # make any assertion about (although in practice it's probably 1) - assert streams[0][1] == remote_handle, (streams[0], remote_handle) - assert streams[0][2] == cs.MEDIA_STREAM_TYPE_AUDIO, streams[0] - # We haven't connected yet - assert streams[0][3] == cs.MEDIA_STREAM_STATE_DISCONNECTED, streams[0] - # In Gabble, incoming streams start off with remote send enabled, and - # local send requested - assert streams[0][4] == cs.MEDIA_STREAM_DIRECTION_RECEIVE, streams[0] - assert streams[0][5] == cs.MEDIA_STREAM_PENDING_LOCAL_SEND, streams[0] - - # Connectivity checks happen before we have accepted the call - stream_handler.NewNativeCandidate("fake", context.get_remote_transports_dbus()) - stream_handler.NativeCandidatesPrepared() - stream_handler.Ready(context.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) - stream_handler.SupportedCodecs(context.get_audio_codecs_dbus()) - - # At last, accept the call - media_chan.AddMembers([self_handle], 'accepted') - - # Call is accepted, we become a member, and the stream that was pending - # local send is now sending. - memb, acc, _, _, _ = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged', - args=[u'', [self_handle], [], [], [], self_handle, - cs.GC_REASON_NONE]), - EventPattern('sip-response', call_id=context.call_id, code=200), - EventPattern('dbus-signal', signal='SetStreamSending', args=[True]), - EventPattern('dbus-signal', signal='SetStreamPlaying', args=[True]), - EventPattern('dbus-signal', signal='StreamDirectionChanged', - args=[stream_id, cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, 0]), - ) + assertEquals(cs.CHANNEL_TYPE_CALL, props[cs.CHANNEL_TYPE]) + assertEquals(cs.HT_CONTACT, props[cs.CHANNEL + '.TargetHandleType']) + assertEquals(remote_handle, props[cs.CHANNEL + '.TargetHandle']) + assertEquals(remote_handle, props[cs.CHANNEL + '.InitiatorHandle']) + assertEquals(True, props[cs.CHANNEL_TYPE_CALL + '.InitialAudio']) + assertEquals(True, props[cs.CHANNEL_TYPE_CALL + '.MutableContents']) + assertEquals(False, props[cs.CHANNEL_TYPE_CALL + '.HardwareStreaming']) + + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Call1') + + call_props = chan.Properties.GetAll(cs.CHANNEL_TYPE_CALL) + assertEquals(cs.CALL_STATE_INITIALISING, call_props['CallState']) + assertEquals(0, call_props['CallFlags']) + assertEquals(False, call_props['HardwareStreaming']) + assertEquals(True, call_props['MutableContents']) + assertEquals(True, call_props['InitialAudio']) + assertEquals("initial_audio_1", call_props['InitialAudioName']) + assertEquals(False, call_props['InitialVideo']) + assertEquals("", call_props['InitialVideoName']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, + call_props['InitialTransport']) + assertEquals({remote_handle: 0}, call_props['CallMembers']) + + + assertLength(1, call_props['Contents']) + + content = bus.get_object (conn.bus_name, call_props['Contents'][0]) + + content_props = content.GetAll(cs.CALL_CONTENT) + assertEquals(cs.CALL_DISPOSITION_INITIAL, content_props['Disposition']) + assertEquals("initial_audio_1", content_props['Name']) + assertLength(1, content_props['Streams']) + + cmedia_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA) + assertLength(0, cmedia_props['RemoteMediaDescriptions']) + assertLength(0, cmedia_props['LocalMediaDescriptions']) + assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0]) + assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP, + cmedia_props['Packetization']) + assertEquals(cs.CALL_SENDING_STATE_NONE, cmedia_props['CurrentDTMFState']) - context.check_call_sdp(acc.sip_message.body) + + stream = bus.get_object (conn.bus_name, content_props['Streams'][0]) + + stream = ProxyWrapper (stream, cs.CALL_STREAM, + {'Media': cs.CALL_STREAM_IFACE_MEDIA}) + + stream_props = stream.Properties.GetAll(cs.CALL_STREAM) + assertEquals(True, stream_props['CanRequestReceiving']) + assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, + stream_props['LocalSendingState']) + + smedia_props = stream.Properties.GetAll(cs.CALL_STREAM_IFACE_MEDIA) + assertEquals(cs.CALL_SENDING_STATE_NONE, smedia_props['SendingState']) + assertEquals(cs.CALL_SENDING_STATE_NONE, smedia_props['ReceivingState']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, smedia_props['Transport']) + assertEquals([], smedia_props['LocalCandidates']) + assertEquals(("",""), smedia_props['LocalCredentials']) + assertEquals([], smedia_props['STUNServers']) + assertEquals([], smedia_props['RelayInfo']) + assertEquals(True, smedia_props['HasServerInfo']) + assertEquals([], smedia_props['Endpoints']) + assertEquals(False, smedia_props['ICERestartPending']) + + md = bus.get_object (conn.bus_name, + cmedia_props['MediaDescriptionOffer'][0]) + md.Accept(context.get_audio_md_dbus(remote_handle)) + + o = q.expect_many( + EventPattern('dbus-signal', signal='EndpointsChanged'), + EventPattern('dbus-signal', signal='MediaDescriptionOfferDone'), + EventPattern('dbus-signal', signal='LocalMediaDescriptionChanged'), + EventPattern('dbus-signal', signal='RemoteMediaDescriptionsChanged')) + + assertLength(1, o[0].args[0]) + assertEquals([], o[0].args[1]) + + endpoint = bus.get_object(conn.bus_name, o[0].args[0][0]) + endpoint_props = endpoint.GetAll(cs.CALL_STREAM_ENDPOINT) + assertEquals(('',''), endpoint_props['RemoteCredentials']) + assertEquals(context.get_remote_candidates_dbus(), + endpoint_props['RemoteCandidates']) + assertLength(0, endpoint_props['EndpointState']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, + endpoint_props['Transport']) + assertEquals(False, endpoint_props['IsICELite']) + + endpoint.SetEndpointState(1, + cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + dbus_interface=cs.CALL_STREAM_ENDPOINT) + endpoint.SetEndpointState(2, + cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + dbus_interface=cs.CALL_STREAM_ENDPOINT) + + + assertEquals({1: cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + 2: cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED}, + endpoint.Get(cs.CALL_STREAM_ENDPOINT, 'EndpointState')) + + o = q.expect('dbus-signal', signal='CallStateChanged') + assertEquals(cs.CALL_STATE_INITIALISED, o.args[0]) + + chan.Call1.SetQueued() + + o = q.expect_many( + EventPattern('sip-response', call_id=context.call_id, code=182), + EventPattern('dbus-signal', signal='CallStateChanged')) + assertEquals(cs.CALL_STATE_INITIALISED, o[1].args[0]) + assertEquals(cs.CALL_FLAG_LOCALLY_QUEUED, o[1].args[1]) + + chan.Call1.SetRinging() + + o = q.expect_many( + EventPattern('sip-response', call_id=context.call_id, code=180), + EventPattern('dbus-signal', signal='CallStateChanged')) + assertEquals(cs.CALL_STATE_INITIALISED, o[1].args[0]) + assertEquals(cs.CALL_FLAG_LOCALLY_RINGING, o[1].args[1]) + + + chan.Call1.Accept() + + o = q.expect_many( + EventPattern('dbus-signal', signal='CallStateChanged'), + EventPattern('dbus-signal', signal='CallStateChanged'), + EventPattern('dbus-signal', signal='ReceivingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]), + EventPattern('dbus-signal', signal='SendingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START])) + assertEquals(cs.CALL_STATE_ACCEPTED, o[0].args[0]) + assertEquals(cs.CALL_STATE_ACTIVE, o[1].args[0]) + + + stream.Media.CompleteReceivingStateChange( + cs.CALL_STREAM_FLOW_STATE_STARTED) + stream.Media.CompleteSendingStateChange(cs.CALL_STREAM_FLOW_STATE_STARTED) + + o = q.expect_many( + EventPattern('dbus-signal', signal='ReceivingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_STARTED]), + EventPattern('dbus-signal', signal='SendingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_STARTED]), + EventPattern('dbus-signal', signal='LocalSendingStateChanged')) + assertEquals(cs.CALL_SENDING_STATE_SENDING, o[2].args[0]) + + stream.Media.AddCandidates(context.get_remote_candidates_dbus()) + stream.Media.FinishInitialCandidates() + + acc = q.expect('sip-response', call_id=context.call_id, code=200) + context.check_call_sdp(acc.sip_message.body) context.ack(acc.sip_message) - - # we are now both in members - members = media_chan.GetMembers() - assert set(members) == set([self_handle, remote_handle]), members + # Connected! Blah, blah, ... # 'Nuff said bye_msg = context.terminate() - q.expect_many(EventPattern('dbus-signal', signal='Closed', path=path), - EventPattern('sip-response', cseq=bye_msg.headers['cseq'][0])) + o = q.expect_many( + EventPattern('dbus-signal', signal='CallStateChanged', path=path), + EventPattern('sip-response', cseq=bye_msg.headers['cseq'][0])) + assertEquals(cs.CALL_STATE_ENDED, o[0].args[0]) if __name__ == '__main__': exec_test(test) exec_test(lambda q, bus, conn, stream: - test(q, bus, conn, stream, 'foo@sip.bar.com')) + test(q, bus, conn, stream, 'foo@sip.bar.com')) diff --git a/tests/twisted/voip/outgoing-basics.py b/tests/twisted/voip/outgoing-basics.py index c8e93bc..8d4a161 100644 --- a/tests/twisted/voip/outgoing-basics.py +++ b/tests/twisted/voip/outgoing-basics.py @@ -7,36 +7,19 @@ import dbus from sofiatest import exec_test from servicetest import ( - wrap_channel, EventPattern, call_async, - assertEquals, assertContains, assertLength, assertSameSets + wrap_channel, EventPattern, call_async, ProxyWrapper, + assertEquals, assertContains, assertLength, assertSameSets, + assertNotEquals ) import constants as cs from voip_test import VoipTestContext -# There are various deprecated APIs for requesting calls, documented at -# <http://telepathy.freedesktop.org/wiki/Requesting StreamedMedia channels>. -# These are ordered from most recent to most deprecated. CREATE = 0 # CreateChannel({TargetHandleType: Contact, TargetHandle: h}); # RequestStreams() -REQUEST_ANONYMOUS = 1 # RequestChannel(HandleTypeNone, 0); RequestStreams() -REQUEST_ANONYMOUS_AND_ADD = 2 # RequestChannel(HandleTypeNone, 0); - # AddMembers([h], ...); RequestStreams(h,...) -REQUEST_NONYMOUS = 3 # RequestChannel(HandleTypeContact, h); - # RequestStreams(h, ...) def create(q, bus, conn, sip_proxy, peer='foo@bar.com'): worker(q, bus, conn, sip_proxy, CREATE, peer) -def request_anonymous(q, bus, conn, sip_proxy, peer='publish@foo.com'): - worker(q, bus, conn, sip_proxy, REQUEST_ANONYMOUS, peer) - -def request_anonymous_and_add(q, bus, conn, sip_proxy, - peer='publish-subscribe@foo.com/Res'): - worker(q, bus, conn, sip_proxy, REQUEST_ANONYMOUS_AND_ADD, peer) - -def request_nonymous(q, bus, conn, sip_proxy, peer='subscribe@foo.com'): - worker(q, bus, conn, sip_proxy, REQUEST_NONYMOUS, peer) - def worker(q, bus, conn, sip_proxy, variant, peer): conn.Connect() q.expect('dbus-signal', signal='StatusChanged', args=[0, 1]) @@ -47,18 +30,13 @@ def worker(q, bus, conn, sip_proxy, variant, peer): self_handle = conn.GetSelfHandle() remote_handle = conn.RequestHandles(1, [context.peer])[0] - if variant == REQUEST_NONYMOUS: - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_CONTACT, remote_handle, True) - elif variant == CREATE: - path = conn.Requests.CreateChannel({ - cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_STREAMED_MEDIA, + path = conn.Requests.CreateChannel({ + cs.CHANNEL_TYPE: cs.CHANNEL_TYPE_CALL, cs.TARGET_HANDLE_TYPE: cs.HT_CONTACT, cs.TARGET_HANDLE: remote_handle, + cs.INITIAL_AUDIO: True, + cs.INITIAL_AUDIO_NAME: "audiocontent", })[0] - else: - path = conn.RequestChannel(cs.CHANNEL_TYPE_STREAMED_MEDIA, - cs.HT_NONE, 0, True) old_sig, new_sig = q.expect_many( EventPattern('dbus-signal', signal='NewChannel', @@ -68,172 +46,200 @@ def worker(q, bus, conn, sip_proxy, variant, peer): cs.CHANNEL_TYPE_CONTACT_LIST not in e.args[0][0][1].values()), ) - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_CONTACT, - remote_handle, True], old_sig.args) - else: - assertEquals( [path, cs.CHANNEL_TYPE_STREAMED_MEDIA, cs.HT_NONE, 0, - True], old_sig.args) + assertEquals( [path, cs.CHANNEL_TYPE_CALL, cs.HT_CONTACT, + remote_handle, True], old_sig.args) assertLength(1, new_sig.args) assertLength(1, new_sig.args[0]) # one channel assertLength(2, new_sig.args[0][0]) # two struct members emitted_props = new_sig.args[0][0][1] - assertEquals( - cs.CHANNEL_TYPE_STREAMED_MEDIA, emitted_props[cs.CHANNEL_TYPE]) + assertEquals(cs.CHANNEL_TYPE_CALL, emitted_props[cs.CHANNEL_TYPE]) - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals(remote_handle, emitted_props[cs.TARGET_HANDLE]) - assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals(context.peer_id, emitted_props[cs.TARGET_ID]) - else: - assertEquals(0, emitted_props[cs.TARGET_HANDLE]) - assertEquals(cs.HT_NONE, emitted_props[cs.TARGET_HANDLE_TYPE]) - assertEquals('', emitted_props[cs.TARGET_ID]) + assertEquals(remote_handle, emitted_props[cs.TARGET_HANDLE]) + assertEquals(cs.HT_CONTACT, emitted_props[cs.TARGET_HANDLE_TYPE]) + assertEquals(context.peer_id, emitted_props[cs.TARGET_ID]) assertEquals(True, emitted_props[cs.REQUESTED]) assertEquals(self_handle, emitted_props[cs.INITIATOR_HANDLE]) assertEquals('sip:testacc@127.0.0.1', emitted_props[cs.INITIATOR_ID]) - chan = wrap_channel(bus.get_object(conn.bus_name, path), 'StreamedMedia', - ['MediaSignalling']) + chan = wrap_channel(bus.get_object(conn.bus_name, path), 'Call1') # Exercise basic Channel Properties channel_props = chan.Properties.GetAll(cs.CHANNEL) - assertEquals(cs.CHANNEL_TYPE_STREAMED_MEDIA, + assertEquals(cs.CHANNEL_TYPE_CALL, channel_props.get('ChannelType')) - if variant == REQUEST_NONYMOUS or variant == CREATE: - assertEquals(remote_handle, channel_props['TargetHandle']) - assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) - assertEquals(context.peer_id, channel_props['TargetID']) - assertEquals((cs.HT_CONTACT, remote_handle), chan.GetHandle()) - else: - assertEquals(0, channel_props['TargetHandle']) - assertEquals(cs.HT_NONE, channel_props['TargetHandleType']) - assertEquals('', channel_props['TargetID']) - assertEquals((cs.HT_NONE, 0), chan.GetHandle()) - - for interface in [ - cs.CHANNEL_IFACE_GROUP, cs.CHANNEL_IFACE_MEDIA_SIGNALLING, - cs.TP_AWKWARD_PROPERTIES, cs.CHANNEL_IFACE_HOLD]: + assertEquals(remote_handle, channel_props['TargetHandle']) + assertEquals(cs.HT_CONTACT, channel_props['TargetHandleType']) + assertEquals(context.peer_id, channel_props['TargetID']) + assertEquals((cs.HT_CONTACT, remote_handle), chan.GetHandle()) + + + for interface in [cs.CHANNEL_IFACE_HOLD, cs.CHANNEL_IFACE_DTMF]: assertContains(interface, channel_props['Interfaces']) assertEquals(True, channel_props['Requested']) assertEquals('sip:testacc@127.0.0.1', channel_props['InitiatorID']) assertEquals(conn.GetSelfHandle(), channel_props['InitiatorHandle']) - # Exercise Group Properties - group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) - - assertEquals([self_handle], group_props['Members']) - assertEquals([], group_props['LocalPendingMembers']) - - if variant == REQUEST_NONYMOUS: - # In this variant, they're meant to be in RP even though we've sent - # nothing - assertEquals([remote_handle], group_props['RemotePendingMembers']) - else: - # For an anonymous channel, the peer isn't yet known; for a Create-d - # channel, the peer only appears in RP when we actually send them the - # session-initiate - assertEquals([], group_props['RemotePendingMembers']) - - if variant == REQUEST_ANONYMOUS_AND_ADD: - # but we should be allowed to add the peer. - chan.Group.AddMembers([remote_handle], 'I love backwards compat') - - base_flags = cs.GF_PROPERTIES | cs.GF_CAN_REMOVE | cs.GF_CAN_RESCIND | cs.GF_MEMBERS_CHANGED_DETAILED - - if variant in [REQUEST_ANONYMOUS_AND_ADD, REQUEST_ANONYMOUS, CREATE]: - expected_flags = base_flags | cs.GF_CAN_ADD - else: - expected_flags = base_flags - - assertEquals(bin(expected_flags), bin(group_props['GroupFlags'])) - assertEquals({}, group_props['HandleOwners']) - - assertEquals([], chan.StreamedMedia.ListStreams()) - streams = chan.StreamedMedia.RequestStreams(remote_handle, - [cs.MEDIA_STREAM_TYPE_AUDIO]) - assertEquals(streams, chan.StreamedMedia.ListStreams()) - assertLength(1, streams) - - # streams[0][0] is the stream identifier, which in principle we can't - # make any assertion about (although in practice it's probably 1) - - assertEquals(( - remote_handle, - cs.MEDIA_STREAM_TYPE_AUDIO, - # We haven't connected yet - cs.MEDIA_STREAM_STATE_DISCONNECTED, - # In Gabble, requested streams start off bidirectional - cs.MEDIA_STREAM_DIRECTION_BIDIRECTIONAL, - cs.MEDIA_STREAM_PENDING_REMOTE_SEND), - streams[0][1:]) - - stream_handler = context.handle_audio_session(chan) - - sh_props = stream_handler.GetAll( - cs.STREAM_HANDLER, dbus_interface=dbus.PROPERTIES_IFACE) - assertEquals('none', sh_props['NATTraversal']) - assertEquals(True, sh_props['CreatedLocally']) - - if variant == CREATE: - # When we actually send INVITE to the peer, they should pop up in remote - # pending. - invite_event, _ = q.expect_many( - EventPattern('sip-invite'), - EventPattern('dbus-signal', signal='MembersChanged', - args=["", [], [], [], [remote_handle], self_handle, - cs.GC_REASON_INVITED]), - ) - else: - invite_event = q.expect('sip-invite') - - # Check the Group interface's properties again. Regardless of the call - # requesting API in use, the state should be the same here: - group_props = chan.Properties.GetAll(cs.CHANNEL_IFACE_GROUP) - assertContains('HandleOwners', group_props) - assertEquals([self_handle], group_props['Members']) - assertEquals([], group_props['LocalPendingMembers']) - assertEquals([remote_handle], group_props['RemotePendingMembers']) + call_props = chan.Properties.GetAll(cs.CHANNEL_TYPE_CALL) + assertEquals(cs.CALL_STATE_PENDING_INITIATOR, call_props['CallState']) + assertEquals(0, call_props['CallFlags']) + assertEquals(False, call_props['HardwareStreaming']) + assertEquals(True, call_props['MutableContents']) + assertEquals(True, call_props['InitialAudio']) + assertEquals("audiocontent", call_props['InitialAudioName']) + assertEquals(False, call_props['InitialVideo']) + assertEquals("", call_props['InitialVideoName']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, + call_props['InitialTransport']) + assertEquals({remote_handle: 0}, call_props['CallMembers']) + + assertLength(1, call_props['Contents']) + + content = bus.get_object (conn.bus_name, call_props['Contents'][0]) + + content_props = content.GetAll(cs.CALL_CONTENT) + assertEquals(cs.CALL_DISPOSITION_INITIAL, content_props['Disposition']) + assertEquals("audiocontent", content_props['Name']) + assertLength(1, content_props['Streams']) + + cmedia_props = content.GetAll(cs.CALL_CONTENT_IFACE_MEDIA) + assertLength(0, cmedia_props['RemoteMediaDescriptions']) + assertLength(0, cmedia_props['LocalMediaDescriptions']) + assertNotEquals('/', cmedia_props['MediaDescriptionOffer'][0]) + assertEquals(cs.CALL_CONTENT_PACKETIZATION_RTP, + cmedia_props['Packetization']) + assertEquals(cs.CALL_SENDING_STATE_NONE, cmedia_props['CurrentDTMFState']) + + + stream = bus.get_object (conn.bus_name, content_props['Streams'][0]) + + stream = ProxyWrapper (stream, cs.CALL_STREAM, + {'Media': cs.CALL_STREAM_IFACE_MEDIA}) + + stream_props = stream.Properties.GetAll(cs.CALL_STREAM) + assertEquals(True, stream_props['CanRequestReceiving']) + assertEquals(cs.CALL_SENDING_STATE_PENDING_SEND, + stream_props['LocalSendingState']) + + smedia_props = stream.Properties.GetAll(cs.CALL_STREAM_IFACE_MEDIA) + assertEquals(cs.CALL_SENDING_STATE_NONE, smedia_props['SendingState']) + assertEquals(cs.CALL_SENDING_STATE_NONE, smedia_props['ReceivingState']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, smedia_props['Transport']) + assertEquals([], smedia_props['LocalCandidates']) + assertEquals(("",""), smedia_props['LocalCredentials']) + assertEquals([], smedia_props['STUNServers']) + assertEquals([], smedia_props['RelayInfo']) + assertEquals(True, smedia_props['HasServerInfo']) + assertEquals([], smedia_props['Endpoints']) + assertEquals(False, smedia_props['ICERestartPending']) + + chan.Call1.Accept() + + q.expect ('dbus-signal', signal='ReceivingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]) + + stream.Media.CompleteReceivingStateChange(cs.CALL_STREAM_FLOW_STATE_STARTED) + + md = bus.get_object (conn.bus_name, cmedia_props['MediaDescriptionOffer'][0]) + md.Accept(context.get_audio_md_dbus(remote_handle)) + q.expect_many( + EventPattern('dbus-signal', signal='MediaDescriptionOfferDone'), + EventPattern('dbus-signal', signal='LocalMediaDescriptionChanged'), + EventPattern('dbus-signal', signal='RemoteMediaDescriptionsChanged')) + + mdo = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, 'MediaDescriptionOffer') + assertEquals(('/', {}), mdo) + + + stream.Media.AddCandidates(context.get_remote_candidates_dbus()) + stream.Media.FinishInitialCandidates() + + q.expect('dbus-signal', signal='LocalCandidatesAdded') + + invite_event = q.expect('sip-invite') + + + # Send Ringing + context.pr_respond(invite_event, 180) + o = q.expect('dbus-signal', signal='CallMembersChanged') + assertEquals(cs.CALL_MEMBER_FLAG_RINGING, o.args[0][remote_handle]) context.check_call_sdp(invite_event.sip_message.body) context.accept(invite_event.sip_message) ack_cseq = "%s ACK" % invite_event.cseq.split()[0] - q.expect_many( + + o = q.expect_many( EventPattern('sip-ack', cseq=ack_cseq), # Call accepted - EventPattern('dbus-signal', signal='MembersChanged', - args=['', [remote_handle], [], [], [], remote_handle, - cs.GC_REASON_NONE]), - EventPattern('dbus-signal', signal='SetRemoteCodecs'), - ), - - stream_handler.SupportedCodecs(context.get_audio_codecs_dbus()) - stream_handler.StreamState(cs.MEDIA_STREAM_STATE_CONNECTED) + EventPattern('dbus-signal', signal='NewMediaDescriptionOffer')) - # Time passes ... afterwards we close the chan + md = bus.get_object (conn.bus_name, o[1].args[0]) + md.Accept(context.get_audio_md_dbus(remote_handle)) - chan.Group.RemoveMembers([self_handle], 'closed') + o = q.expect_many( + # Call accepted + EventPattern('dbus-signal', signal='CallStateChanged'), + EventPattern('dbus-signal', signal='EndpointsChanged'), + EventPattern('dbus-signal', signal='MediaDescriptionOfferDone'), + EventPattern('dbus-signal', signal='SendingStateChanged', + args=[cs.CALL_STREAM_FLOW_STATE_PENDING_START]), + EventPattern('dbus-signal', signal='LocalMediaDescriptionChanged'), + EventPattern('dbus-signal', signal='RemoteMediaDescriptionsChanged')) + + mdo = content.Get(cs.CALL_CONTENT_IFACE_MEDIA, 'MediaDescriptionOffer') + assertEquals(('/', {}), mdo) + + assertEquals(cs.CALL_STATE_ACCEPTED, o[0].args[0]) + assertLength(0, o[1].args[1]) + + endpoint = bus.get_object(conn.bus_name, o[1].args[0][0]) + endpoint_props = endpoint.GetAll(cs.CALL_STREAM_ENDPOINT) + assertEquals(('',''), endpoint_props['RemoteCredentials']) + assertEquals(context.get_remote_candidates_dbus(), + endpoint_props['RemoteCandidates']) + assertLength(0, endpoint_props['EndpointState']) + assertEquals(cs.CALL_STREAM_TRANSPORT_RAW_UDP, + endpoint_props['Transport']) + assertEquals(False, endpoint_props['IsICELite']) + + endpoint.SetEndpointState(1, + cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + dbus_interface=cs.CALL_STREAM_ENDPOINT) + endpoint.SetEndpointState(2, + cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + dbus_interface=cs.CALL_STREAM_ENDPOINT) + + assertEquals({1: cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED, + 2: cs.CALL_STREAM_ENDPOINT_STATE_FULLY_CONNECTED}, + endpoint.Get(cs.CALL_STREAM_ENDPOINT, 'EndpointState')) + + o = q.expect('dbus-signal', signal='CallStateChanged') + assertEquals(cs.CALL_STATE_ACTIVE, o.args[0]) + # Time passes ... afterwards we close the chan - mc_event, _, bye_event = q.expect_many( - EventPattern('dbus-signal', signal='MembersChanged'), - EventPattern('dbus-signal', signal='Close'), - EventPattern('sip-bye', call_id=context.call_id), - ) + chan.Call1.Hangup(cs.CALL_SCR_USER_REQUESTED, "", "User hangs up") + ended_event, bye_event = q.expect_many( + EventPattern('dbus-signal', signal='CallStateChanged'), + EventPattern('sip-bye', call_id=context.call_id)) # Check that we're the actor - assertEquals(self_handle, mc_event.args[5]) + assertEquals(cs.CALL_STATE_ENDED, ended_event.args[0]) + assertEquals(0, ended_event.args[1]) + assertEquals((self_handle, cs.CALL_SCR_USER_REQUESTED, "", + "User hangs up"), ended_event.args[2]) # For completeness, reply to the BYE. bye_response = sip_proxy.responseFromRequest(200, bye_event.sip_message) sip_proxy.deliverResponse(bye_response) + chan.Close() + def rccs(q, bus, conn, stream): """ Tests that the connection's RequestableChannelClasses for StreamedMedia are @@ -241,44 +247,43 @@ def rccs(q, bus, conn, stream): """ conn.Connect() - q.expect('dbus-signal', signal='StatusChanged', - args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) + + a = q.expect('dbus-signal', signal='StatusChanged', + args=[cs.CONN_STATUS_CONNECTING, cs.CSR_REQUESTED]) + + a = q.expect('dbus-signal', signal='StatusChanged', + args=[cs.CONN_STATUS_CONNECTED, cs.CSR_REQUESTED]) rccs = conn.Properties.Get(cs.CONN_IFACE_REQUESTS, 'RequestableChannelClasses') # Test Channel.Type.StreamedMedia media_classes = [ rcc for rcc in rccs - if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_STREAMED_MEDIA ] + if rcc[0][cs.CHANNEL_TYPE] == cs.CHANNEL_TYPE_CALL ] - assertLength(1, media_classes) + assertLength(2, media_classes) - fixed, allowed = media_classes[0] + for media_class in media_classes: + fixed, allowed = media_class - assertEquals(cs.HT_CONTACT, fixed[cs.TARGET_HANDLE_TYPE]) + assertEquals(cs.HT_CONTACT, fixed[cs.TARGET_HANDLE_TYPE]) + assert fixed.has_key(cs.INITIAL_AUDIO) or fixed.has_key(cs.INITIAL_VIDEO) - expected_allowed = [ - cs.TARGET_ID, cs.TARGET_HANDLE, - cs.INITIAL_VIDEO, cs.INITIAL_AUDIO, - cs.DTMF_INITIAL_TONES - ] + expected_allowed = [ + cs.TARGET_ID, cs.TARGET_HANDLE, + cs.INITIAL_VIDEO, cs.INITIAL_AUDIO, + cs.INITIAL_VIDEO_NAME, cs.INITIAL_AUDIO_NAME, + cs.INITIAL_TRANSPORT, + cs.DTMF_INITIAL_TONES, + ] - allowed.sort() - expected_allowed.sort() - assertSameSets(expected_allowed, allowed) + allowed.sort() + expected_allowed.sort() + assertSameSets(expected_allowed, allowed) if __name__ == '__main__': exec_test(rccs) exec_test(create) - exec_test(request_anonymous) - exec_test(request_anonymous_and_add) - exec_test(request_nonymous) exec_test(lambda q, b, c, s: create(q, b, c, s, peer='foo@gw.bar.com')) - exec_test(lambda q, b, c, s: - request_anonymous(q, b, c, s, peer='foo@gw.bar.com')) - exec_test(lambda q, b, c, s: - request_anonymous_and_add(q, b, c, s, peer='foo@gw.bar.com')) - exec_test(lambda q, b, c, s: - request_nonymous(q, b, c, s, peer='foo@gw.bar.com')) diff --git a/tests/twisted/voip/voip_test.py b/tests/twisted/voip/voip_test.py index c8724af..95b9fdc 100644 --- a/tests/twisted/voip/voip_test.py +++ b/tests/twisted/voip/voip_test.py @@ -8,6 +8,7 @@ from servicetest import ( make_channel_proxy, assertContains, ) +import constants as cs class VoipTestContext(object): # Default audio codecs for the remote end @@ -17,21 +18,23 @@ class VoipTestContext(object): # Default video codecs for the remote end. I have no idea what's # a suitable value here... - video_codecs = [ ('WTF', 42, 80000, {}) ] + video_codecs = [ ('H264', 96, 90000, {}) ] # Default candidates for the remote end - remote_transports = [ - ( "192.168.0.1", # host - 666, # port - 0, # protocol = TP_MEDIA_STREAM_BASE_PROTO_UDP - "RTP", # protocol subtype - "AVP", # profile - 1.0, # preference - 0, # transport type = TP_MEDIA_STREAM_TRANSPORT_TYPE_LOCAL, - "username", - "password" ) ] - - _mline_template = 'm=audio %(port)s %(subtype)s/%(profile)s %(codec_ids)s' + remote_candidates = [ + (1, # Component + "192.168.0.1", # ip + 2222, # port + {'protocol': cs.MEDIA_STREAM_BASE_PROTO_UDP, + 'priority': 0}), + (2, # Component + "192.168.0.1", # ip + 2223, # port + {'protocol': cs.MEDIA_STREAM_BASE_PROTO_UDP, + 'priority': 0}) + ] + + _mline_template = 'm=audio %(port)s RTP/AVP %(codec_ids)s' _aline_template = 'a=rtpmap:%(codec_id)s %(name)s/%(rate)s' def __init__(self, q, conn, bus, sip_proxy, our_uri, peer): @@ -45,60 +48,31 @@ class VoipTestContext(object): self._cseq_id = 1 def dbusify_codecs(self, codecs): - dbussed_codecs = [ (id, name, 0, rate, 0, params ) + dbussed_codecs = [ (id, name, rate, 1, False, params ) for (name, id, rate, params) in codecs ] - return dbus.Array(dbussed_codecs, signature='(usuuua{ss})') + return dbus.Array(dbussed_codecs, signature='(usuuba{ss})') def dbusify_codecs_with_params (self, codecs): return self.dbusify_codecs(codecs) - def get_audio_codecs_dbus(self): - return self.dbusify_codecs(self.audio_codecs) + def get_md_dbus(self, codecs, remote_contact): + return dbus.Dictionary( + {cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".Codecs": self.dbusify_codecs(codecs), + cs.CALL_CONTENT_MEDIA_DESCRIPTION + ".RemoteContact": + dbus.UInt32(remote_contact)}, + signature='sv') - def get_video_codecs_dbus(self): - return self.dbusify_codecs(self.video_codecs) + def get_audio_md_dbus(self, remote_contact): + return self.get_md_dbus(self.audio_codecs, remote_contact) - def dbusify_call_codecs(self, codecs): - dbussed_codecs = [ (id, name, rate, 0, params) - for (name, id, rate, params) in codecs ] - return dbus.Array(dbussed_codecs, signature='(usuua{ss})') - - def dbusify_call_codecs_with_params(self, codecs): - return dbusify_call_codecs (self, codecs) - - def get_call_audio_codecs_dbus(self): - return self.dbusify_call_codecs(self.audio_codecs) - - def get_call_video_codecs_dbus(self): - return self.dbusify_call_codecs(self.video_codecs) - - - def get_remote_transports_dbus(self): - return dbus.Array([ - (dbus.UInt32(1 + i), host, port, proto, subtype, - profile, pref, transtype, user, pwd) - for i, (host, port, proto, subtype, profile, - pref, transtype, user, pwd) - in enumerate(self.remote_transports) ], - signature='(usuussduss)') - - def get_call_remote_transports_dbus(self): - return dbus.Array([ - (1 , host, port, - { "Type": transtype, - "Foundation": "", - "Protocol": proto, - "Priority": int((1+i) * 65536), - "Username": user, - "Password": pwd } - ) for i, (host, port, proto, subtype, profile, - pref, transtype, user, pwd) - in enumerate(self.remote_transports) ], - signature='(usqa{sv})') + def get_video_md_dbus(self, remote_contact): + return self.get_md_dbus(self.video_codecs, remote_contact) + + def get_remote_candidates_dbus(self): + return dbus.Array(self.remote_candidates, signature='(usua{sv})') def get_call_sdp(self): - (ip, port, protocol, subtype, profile, preference, - transport, username, password) = self.remote_transports[0] + (component, ip, port, info) = self.remote_candidates[0] codec_id_list = [] codec_list = [] @@ -124,8 +98,7 @@ class VoipTestContext(object): codec_id_list.append(str(codec_id)) codec_ids = ' '.join(codec_id_list) - (ip, port, protocol, subtype, profile, preference, - transport, username, password) = self.remote_transports[0] + (component, ip, port, info) = self.remote_candidates[0] assert self._mline_template % locals() in sdp_string def send_message(self, message_type, body='', to_=None, from_=None, @@ -161,6 +134,12 @@ class VoipTestContext(object): response.addHeader('content-length', '%d' % len(response.body)) self.sip_proxy.deliverResponse(response) return response + + def pr_respond(self, invite_message, number): + self.call_id = invite_message.headers['call-id'][0] + response = self.sip_proxy.responseFromRequest(number, invite_message) + self.sip_proxy.deliverResponse(response) + return response def ack(self, ok_message): cseq = '%s ACK' % ok_message.headers['cseq'][0].split()[0] @@ -181,28 +160,3 @@ class VoipTestContext(object): def terminate(self): return self.send_message('BYE', call_id=self.call_id) - - def handle_audio_session(self, chan): - """ - Serves a SessionHandler and a StreamHandler for the MediaSignalling - channel. Returns the interface proxy for StreamHandler. - """ - session_handlers = chan.MediaSignalling.GetSessionHandlers() - sh_path, sh_type = session_handlers[0] - - assert sh_type == 'rtp' - - session_handler = make_channel_proxy(self.conn, sh_path, - 'Media.SessionHandler') - session_handler.Ready() - - e = self.q.expect('dbus-signal', signal='NewStreamHandler') - - stream_handler = make_channel_proxy(self.conn, e.args[0], - 'Media.StreamHandler') - - stream_handler.NewNativeCandidate("fake", self.get_remote_transports_dbus()) - stream_handler.NativeCandidatesPrepared() - stream_handler.Ready(self.get_audio_codecs_dbus()) - - return stream_handler |